Push notifications
Connect Firebase for Android and your APNs key for iOS. Bubbl receives its own pushes and draws them, so there's no push code to write.
Bubbl sends two kinds of push, and your app doesn't forward either of them:
- Android: through Firebase Cloud Messaging, using your Firebase project. Bubbl's pushes are data only: the SDK receives each one with a receiver of its own, beside any
FirebaseMessagingServiceyour app has, and draws the notification itself. - iOS: straight from Bubbl to Apple (APNs) with your app's auth key, without Firebase. iOS draws the alert without running your app; tapping it opens Bubbl's notification screen.
What the user sees and how a notification opens is the same however it arrived: see Notifications and surveys.
Android push#
- 1Upload your Firebase service accountIn the Firebase console, create a service-account key for your project. In the dashboard, open Configuration › Firebase and, under Credentials, choose the service-account JSON and Validate and upload. Bubbl sends your Android pushes with it.
- 2Give the SDK your Firebase appEither keep
google-services.jsonin your app with thecom.google.gms.google-servicesGradle plugin, as usual (the file alone, without the plugin, is ignored), or leave Firebase files out of your app and upload the project'sgoogle-services.jsonunder Android apps on the same page, then Check and save. It must include your app's package name; Bubbl then starts Firebase for you. - 3Check the tokenRun the app and read
hasPushTokeninBubbl.diagnostics(). With the dashboard'sgoogle-services.json, Bubbl gets the Firebase settings when it first registers, so the token can come on the second launch or within the hour, not the first.
google-services.json in the dashboard. That project must be the one whose service account you uploaded. If it isn't, the phone gets a token but none of Bubbl's pushes, and nothing reports an error.For Expo, set android.googleServicesFile in app.json to keep the file in your app: prebuild then adds the file and the Gradle plugin.
Your own Firebase messaging#
Keep your own FirebaseMessagingService, firebase_messaging or React Native Firebase. Bubbl receives its pushes beside it and needs no tokens or payloads from you. Bubbl's pushes also reach your handler, so skip them there:
override fun onMessageReceived(message: RemoteMessage) {
if (Bubbl.isBubblMessage(message.data)) return
// your own pushes
}FirebaseMessaging.onMessage.listen((message) {
if (Bubbl.isBubblMessage(message.data)) return;
// your own pushes
});messaging().onMessage(async (remoteMessage) => {
if (Bubbl.isBubblMessage(remoteMessage.data)) return;
// your own pushes
});Status bar icon and channel#
Bubbl's status bar icon is your app's tech.bubbl.sdk.notification_icon meta-data. Without it, Bubbl uses Firebase's default notification icon (com.google.firebase.messaging.default_notification_icon), then your app icon.
<application ...>
<meta-data
android:name="tech.bubbl.sdk.notification_icon"
android:resource="@drawable/ic_notification" />
</application>Bubbl posts its notifications on its own high-importance channel, named "Offers and updates" in the system settings. Rename it with the bubbl_channel_name and bubbl_channel_description string resources: see Appearance and text.
iOS push#
- 1Add the Push Notifications capabilityIn Xcode, add the Push Notifications capability to your app target under Signing & Capabilities (the Runner target in Flutter). It adds the
aps-environmententitlement. Expo's config plugin adds the entitlement for you at prebuild. - 2Add your app and APNs key in the dashboardCreate an APNs auth key at developer.apple.com › Keys with Apple Push Notifications enabled. In the dashboard, open Configuration › Apple Push and, under Add an app, enter the Bundle ID, Key ID and Team ID, choose the APNs auth key (.p8), and Check and save. Bubbl checks the key with Apple before saving. Add each iOS app by its bundle ID.
- 3Let Bubbl get the device tokenDon't call
registerForRemoteNotifications()yourself. Bubbl asks iOS for the device token once notifications are allowed: straight afterBubbl.permissions.requestNotifications(), and at every app open, so permission given through your own prompt, another plugin or Settings is picked up too.hasPushTokenin diagnostics turns true once Bubbl has it.
Sandbox or production APNs#
The SDK reads your app's provisioning profile to tell Bubbl which APNs environment the token belongs to. A profile with aps-environment set to development (Xcode's development builds) is sandbox. Ad hoc, TestFlight and App Store builds, and builds with no profile, are production. Bubbl sends each push in the environment the phone registered with.
Your own notification handling#
Your own UNUserNotificationCenter delegate, Firebase, or other plugins such as flutter_local_notifications need no changes. Bubbl extends whichever notification delegate is set, answers only for Bubbl's pushes, and passes everything else on unchanged. If no delegate is set by the end of launch, Bubbl sets its own. It adds itself to your app delegate's application(_:didRegisterForRemoteNotificationsWithDeviceToken:) the same way, SwiftUI's UIApplicationDelegateAdaptor included. Bubbl.isBubblMessage(userInfo) tells you whether a payload is Bubbl's.
Handing over pushes yourself#
To turn the automatic integration off, set BubblAutoIntegrationEnabled to NO in Info.plist, then hand Bubbl the device token and the notification delegate's two calls yourself. willPresent and didReceive return true for Bubbl's pushes, and Bubbl then calls the completion handler.
<key>BubblAutoIntegrationEnabled</key>
<false/>import BubblSDK
import UserNotifications
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Bubbl.setPushToken(deviceToken) // fine before Bubbl.start too
// your own token handling
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
if Bubbl.willPresent(notification, completionHandler: completionHandler) { return }
completionHandler([.banner, .sound]) // yours
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
if Bubbl.didReceive(response, completionHandler: completionHandler) { return }
completionHandler()
}import bubbl_flutter_sdk // gives you the iOS SDK's Bubbl, under CocoaPods and Swift Package Manager alike
// Then call Bubbl.setPushToken, Bubbl.willPresent and Bubbl.didReceive
// from the same three methods as a native iOS app.#import <UserNotifications/UserNotifications.h>
#import <BubblReactNativeSdk/BubblReactNativeSdk-Swift.h>
// didRegisterForRemoteNotificationsWithDeviceToken:
[BubblPush setPushToken:deviceToken];
// willPresentNotification:withCompletionHandler:
if ([BubblPush willPresent:notification completionHandler:completionHandler]) return;
// didReceiveNotificationResponse:withCompletionHandler:
if ([BubblPush didReceive:response completionHandler:completionHandler]) return;In a Swift React Native AppDelegate, import BubblReactNativeSdk and call Bubbl.setPushToken, Bubbl.willPresent and Bubbl.didReceive as in the native iOS example. In this mode Bubbl doesn't touch your app delegate or notification delegate, but it still asks iOS for the device token once notifications are allowed. Calling registerForRemoteNotifications() yourself as well does no harm.
Pictures on iOS pushes#
iOS draws Bubbl's pushes without running your app, so a push's picture needs a Notification Service Extension. The extension downloads the push's image_url (https only, at most 10 MB) and attaches it. If anything goes wrong, the push shows without the picture. Other pushes pass through untouched.
- In Xcode, choose File › New › Target… › Notification Service Extension, named
NotificationServicehere, with the same deployment target as your app. - Link Bubbl's extension code to that target (see the platform tab below).
- Replace the whole of the extension's
NotificationService.swiftwith the two lines below. Don't keep Xcode's template code: it overridesdidReceiveandserviceExtensionTimeWillExpirewithout callingsuper, so Bubbl's code would never run.
Add the package's BubblNotificationService product to the NotificationService extension target
(the extension's target › General › Frameworks and Libraries, or when adding the package).# After the Runner target:
target 'NotificationService' do
use_frameworks! :linkage => :static
pod 'BubblFlutterNotificationService', :path => '.symlinks/plugins/bubbl_flutter_sdk/ios'
end# Outside your app's target, then run pod install:
target 'NotificationService' do
pod 'BubblReactNativeNotificationService', :path => '../node_modules/@bubblsdk/react-native-sdk/ios-extension'
endThen make the extension's NotificationService.swift just this, on every platform:
import BubblNotificationService
class NotificationService: BubblNotificationService {}- Flutter: the Podfile block works with Swift Package Manager on too, because Flutter installs pods whenever the app has a Podfile. An app on Swift Package Manager with no
ios/Podfilecreates one first: runflutter config --no-enable-swift-package-manager,flutter build iosonce (it writesios/Podfile), thenflutter config --enable-swift-package-manager, and add the block. Then, in Xcode's Runner target › Build Phases, drag "Embed Foundation Extensions" above "Thin Binary", or Xcode reports a dependency cycle. - Expo: set
"imageNotifications": trueunderiosin Bubbl's config plugin options. Prebuild adds the extension (bundle ID: yours plus.BubblNotificationExtension), its Podfile target and its EAS Build entry, so EAS signs it. It needsios.bundleIdentifier. - An extension that already does its own work: override
didReceive(_:withContentHandler:)and callsuperonly whenBubblNotificationService.isBubbl(request)is true.
Send a test push#
- Read
installIdfromBubbl.diagnostics()on your phone. - In the dashboard, open the Active users card on the home page, search for that install ID, and choose Send test push. In a Sandbox, Configuration › Test Devices has Send test push beside each approved phone too.
- It arrives as a plain notification that opens your app. It reports no events.
The button is greyed out while the device has no push token. active must be true in diagnostics or the phone drops the push: for example with requireConsent before setConsent(true), or while the server has paused Bubbl. A device that opted out gets no test push.
Configuration › Firebase and Configuration › Apple Push also have Send a test push, which takes a full token directly for a phone that hasn't registered yet. On Apple Push, choose the environment for a full token: Sandbox (Xcode builds) or Production (TestFlight, App Store).
When pushes don't arrive#
- Android: check that the app's Firebase project is the one whose service account is uploaded, that the package name is in the dashboard's
google-services.json, and that the phone wasn't force-stopped (Android wakes no app after a force stop until it's opened again). - iOS: check the bundle ID and key under Configuration › Apple Push, and that the build's APNs environment matches (a development build gets sandbox pushes).
iOS couldn't give the app a device tokenin the log usually means the Push Notifications capability or provisioning is missing.
More in Troubleshooting.