Flutter SDK
Add Flutter push notifications
Use the native iOS bridge or bind host-owned Firebase Messaging callbacks for Android customer-message replies.
Add push only when needed
Customer messages and foreground reply banners work without push. Add push when customers should receive replies while the app is inactive.
Push requires the messenger feature and an identified customer. The push bridge
is enabled by default and can be disabled through BtxMessengerOptions.
await Btx.configure(
BtxConfiguration(
publishableClientKey: 'cfk_...',
features: const <BtxFeature>{BtxFeature.messenger},
messengerOptions: const BtxMessengerOptions(
enablePushBridge: true,
),
),
);Use the native iOS bridge
On iOS, the package owns the BTX-specific APNs bridge. BtxHost or the root
navigator integration creates the coordinator, requests authorization on first
messenger presentation, forwards the APNs token, recognizes BTX reply payloads,
and routes notification taps to the correct conversation.
- Enable Push Notifications for the host application target.
- Enable the Remote notifications background mode when the host app requires background delivery.
- Register the exact host bundle ID with the BTX publishable client.
- Keep APNs provider credentials on the BTX backend, never in the app bundle.
- Test authorization, foreground delivery, background delivery, cold launch, and notification response routing.
Bind host-owned Android messaging
Android push is Firebase-neutral in the btx package. The host owns
firebase_core, firebase_messaging, google-services.json, Firebase
initialization, and non-BTX notification behavior. Bind plain Dart callbacks so
BTX can register tokens and route customer-message opens.
final messaging = FirebaseMessaging.instance;
await Btx.push.bindAndroidSource(
BtxAndroidPushSource(
firebaseProjectId: messaging.app.options.projectId,
getToken: messaging.getToken,
tokenRefreshes: messaging.onTokenRefresh,
getInitialNotification: () async {
final message = await messaging.getInitialMessage();
return message == null
? null
: BtxAndroidNotificationOpen(
data: Map<String, Object?>.from(message.data),
handleIfUnhandled: () => handleHostNotification(message),
);
},
notificationOpens: FirebaseMessaging.onMessageOpenedApp.map(
(message) => BtxAndroidNotificationOpen(
data: Map<String, Object?>.from(message.data),
handleIfUnhandled: () => handleHostNotification(message),
),
),
),
);The Android plugin requests notification permission on first messenger presentation when a source or direct token is available. BTX does not add a FlutterFire dependency, declare a Firebase receiver, or change the host token.
Use direct Android callbacks when needed
Apps with another push abstraction can provide the token and notification-open
data directly. handleAndroidNotificationOpen(...) returns whether BTX accepted
and routed the payload so the host can handle everything else.
await Btx.push.setAndroidToken(
token: firebaseToken,
firebaseProjectId: firebaseProjectId,
);
final handled = await Btx.push.handleAndroidNotificationOpen(
data: Map<String, Object?>.from(message.data),
);Call Btx.push.unregisterAndroidDevice() only for explicit host-owned cleanup.
Normal sign-out, customer replacement, messenger disablement, and SDK disposal
clean up or block stale BTX bindings automatically.
Verify the registration boundary
- Confirm the runtime bundle ID or package name matches the client registered in BTX.
- Confirm the active publishable key resolves for the current platform and build variant.
- Present the messenger once before expecting an initial permission prompt.
- Confirm notification-open data remains a flat
Map<String, Object?>when crossing the host boundary. - Use an app-owned fallback for non-BTX Android notifications.