PusherHub

Docs Add PusherHub to your app

Flutter push notifications: add the SDK step by step

Android and iOS, every step with a picture from a real Flutter app: the SDK file, the packages, the Gradle and Xcode settings, and the code in main.dart.

12 min read

All guides
1

Download pusher_hub.dart

In the dashboard, open Applications your app SDK Integration and pick Flutter ①. Choose where your app runs — Android + iOS ② here — and click Download pusher_hub.dart ③. It goes in your lib/ folder ④.

1 Pick Flutter · 2 Android + iOS · 3 Download the SDK file · 4 The folder it goes in

Every step below is on this tab too, with your own keys already filled in — copy the code from there.

2

Put the three files in your project

  1. pusher_hub.dart ① goes in lib/, next to main.dart.
  2. Android: google-services.json ② goes in android/app/.
  3. iOS: GoogleService-Info.plist ③ goes in ios/Runner/, and Xcode has to know about it: open ios/Runner.xcworkspace, drag the file onto the Runner folder and tick the Runner target.
1 pusher_hub.dart in lib · 2 google-services.json in android/app · 3 GoogleService-Info.plist in ios/Runner
3

Add the packages

Add these to dependencies: in pubspec.yaml ①, then run flutter pub get ②. pusher_hub.dart needs every one of them to build, even the ones for features you don't use.

pubspec.yaml

dependencies:
  firebase_core: ^4.14.0
  firebase_messaging: ^16.6.0
  http: ^1.6.0
  shared_preferences: ^2.3.0
  device_info_plus: ^11.1.1
  package_info_plus: ^8.1.2
  flutter_timezone: ^5.1.0
  geolocator: ^13.0.1
  geocoding: ^5.0.0
  url_launcher: ^6.3.1
  webview_flutter: ^4.10.0
1 The packages · 2 flutter pub get
4

Android: add the Google services plugin

Open android/settings.gradle.kts. Inside plugins { }, add ①:

id("com.google.gms.google-services") version "4.4.2" apply false
1 The plugin line
5

Android: turn the plugin on for the app

Open android/app/build.gradle.kts. Inside plugins { }, add id("com.google.gms.google-services") ① — above the Flutter plugin, which has to stay last.

1 The plugin, before Flutter's
6

Android: add to AndroidManifest.xml

Open android/app/src/main/AndroidManifest.xml and add these to the manifest you already have — don't replace it.

  1. The permissions ①. ACCESS_COARSE_LOCATION is only needed if you turn on GPS state and city (step 13).
  2. A second <intent-filter> ② inside the MainActivity <activity>, so a tap on a notification opens your app and is counted.
  3. An <intent> in <queries> ③, so links in notifications and in-app messages can open in the browser on Android 11 and later.
1 Permissions · 2 The notification-tap intent filter · 3 Opening links
7

iOS: turn on push notifications in Xcode

Open ios/Runner.xcworkspace in Xcode and select the Runner target. On Signing & Capabilities ①, choose your paid Apple Developer Team, then click + Capability ② and add Background Modes — tick Remote notifications ③ — and Push Notifications ④.

1 Signing & Capabilities · 2 + Capability · 3 Remote notifications · 4 Push Notifications

Firebase needs iOS 15 or later: set platform :ios, '15.0' at the top of ios/Podfile, and Minimum Deployments to 15.0 on the Runner target's General tab.

8

iOS: add to Info.plist

Open ios/Runner/Info.plist and add, inside <dict>:

  1. The location text ①. Keep it even if you never turn location on — the location package is always in your app, and the App Store can warn about it otherwise.
  2. UIBackgroundModes ② with remote-notification. (Ticking Remote notifications in step 7 adds this for you.)

ios/Runner/Info.plist

<key>NSLocationWhenInUseUsageDescription</key>
<string>Used to resolve your approximate state/region so notifications can be targeted correctly.</string>

<key>UIBackgroundModes</key>
<array>
    <string>remote-notification</string>
</array>
1 The location text · 2 Background notifications
9

iOS: show pictures in notifications (recommended)

An iPhone doesn't download a notification's image by itself — without this step it shows only the title and text. In Xcode, with ios/Runner.xcworkspace open:

  1. File New Target… , pick Notification Service Extension, name it NotificationService, click Finish, then Don't Activate.
  2. On the NotificationService target's General tab, set Minimum Deployments to 15.0.
  3. On the Runner target's Build Phases, drag Embed Foundation Extensions up, above Thin Binary. Skip this and the build fails with "Cycle inside Runner".
  4. On the project's Info tab, under Configurations, set the NotificationService row to Generated for Debug, Release and Profile. Then in the NotificationService target's Build Settings, set Marketing Version to $(FLUTTER_BUILD_NAME) and Current Project Version to $(FLUTTER_BUILD_NUMBER).
  5. Replace everything in ios/NotificationService/NotificationService.swift with the file on your SDK Integration tab.

The simulator can't draw notification pictures, so check this on a real iPhone.

10

iOS, optional: clear the badge

Only if your notifications set a badge number on the app icon. iOS keeps it until the app clears it, and Dart can't, so add these to ios/Runner/AppDelegate.swift: the import ① and, before the return, the lines that clear it each time the app opens ②.

1 The import · 2 Clear the badge when the app opens
11

Start PusherHub in main.dart

Open lib/main.dart and add the code from your SDK Integration tab — your keys and server are already filled in. (In the picture they're placeholders.)

  1. The import ①: import 'pusher_hub.dart';
  2. PusherHub(…) ② with your App key, Public key and server, outside main().
  3. registerDevice() ③ gets the phone's push token, asks the user to allow notifications and adds the phone to PusherHub. collectDeviceMetadata() after it is optional: it adds the phone's brand, model, language and country.
  4. PusherHubMessageHost ④ around your home screen — optional: it shows your in-app messages when the app opens. Leave it out if you only send notifications.
1 The import · 2 Your keys · 3 Register the phone · 4 In-app messages (optional)
12

Optional: log the user in

If your app has its own sign-in, tell PusherHub who's using the phone. Then you can send to one person by your own user ID. It's remembered, even after the app restarts, until logout().

// When someone signs in:
await pusherHub.login(currentUserId);

// When they sign out:
await pusherHub.logout();
13

Optional: open a screen when a notification is tapped

Put your own data in Custom Data when you create a notification — say {"campaign_id": "232"} — and your app gets it back whenever someone taps that notification, whether the app was open, in the background or closed. Add onNotificationOpened to the PusherHub(…) from step 11, and give your MaterialApp a navigatorKey so it can open the screen:

final navigatorKey = GlobalKey<NavigatorState>();

final pusherHub = PusherHub(
  appKey: 'YOUR_APP_KEY',
  publicKey: 'YOUR_PUBLIC_KEY',
  baseUrl: 'YOUR_SERVER',
  onNotificationOpened: (data) {
    final campaignId = data['campaign_id'];
    if (campaignId != null) {
      navigatorKey.currentState?.pushNamed('/campaign', arguments: campaignId);
    }
  },
);

// ...and: MaterialApp(navigatorKey: navigatorKey, ...)

Every value arrives as text ("232"). If your app starts on a splash screen that moves on by itself, keep the data and open the screen after it. This needs pusher_hub.dart from 24 October 2026 or later — download it again if yours is older.

14

Optional: GPS state and city

PusherHub already estimates each phone's state from its internet address. If you need it from GPS instead, turn location on — the app then asks for location once, and if the user says no, only state and city are skipped. It needs the location permission from steps 6 and 8.

await pusherHub.collectDeviceMetadata(resolveLocation: true);
15

Run the app on a phone

Run flutter run on an Android phone or emulator with Google Play, or on a real iPhone (the iOS simulator can't get push notifications). Tap Allow when it asks about notifications. Within a few seconds the phone shows up in PusherHub under Devices.

Then send it a test notification.