Skip to content

Setting Up the Push Notification SDK

What you'll learn

  • Generating the Push Notification SDK with FCM and/or OneSignal providers
  • Configuring Firebase on Android and iOS
  • Requesting permission and retrieving the device token
  • Handling tap-driven navigation from a notification
  • Creating Android notification channels and simulating topic subscriptions

Prerequisites

  • An existing Archipelago monorepo (see Monorepo Scaffolding)
  • A Firebase project (for FCM) or a OneSignal account (for OneSignal)

Step 1: Generate the Push Notification SDK

The Push Notification SDK is a Free tier brick.

bash
archipelago generate push_notification_sdk

You will be prompted for:

  • includeFcmtrue to include the Firebase Cloud Messaging provider
  • includeOneSignaltrue to include the OneSignal provider

At least one provider must be enabled. Both can be enabled simultaneously, though using a single provider is the common setup.

Or use a config file:

json
{
  "includeFcm": true,
  "includeOneSignal": false
}
bash
archipelago generate push_notification_sdk --config push_notification_config.json

Step 2: Understand the Generated Structure

features/
└── push_notification/
    ├── push_notification_api/          # PushNotificationSDK contract
    ├── push_notification_impl/         # Provider-agnostic orchestration
    ├── push_notification_fcm_impl/     # FCM-specific implementation (if includeFcm)
    └── push_notification_onesignal_impl/ # OneSignal implementation (if includeOneSignal)

Your app code and other features depend only on push_notification_api. Swapping or adding providers is a DI change, not an application change.

Step 3: Configure FCM on Android

  1. Download google-services.json from the Firebase console and place it at:

    apps/my_app/android/app/google-services.json
  2. Verify android/app/build.gradle applies the plugin (generated automatically):

    groovy
    apply plugin: 'com.google.gms.google-services'
  3. Create a default notification channel (required on Android API 26+):

    kotlin
    // apps/my_app/android/app/src/main/kotlin/.../MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
    
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
          "default",
          "General",
          NotificationManager.IMPORTANCE_DEFAULT,
        )
        getSystemService(NotificationManager::class.java)
          .createNotificationChannel(channel)
      }
    }

Step 4: Configure FCM on iOS

  1. Download GoogleService-Info.plist from the Firebase console and place it at:

    apps/my_app/ios/Runner/GoogleService-Info.plist
  2. Initialize Firebase in AppDelegate.swift:

    swift
    import FirebaseCore
    
    @main
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        FirebaseApp.configure()
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
  3. In Xcode, enable the following capabilities for the Runner target:

    • Push Notifications
    • Background Modes → Remote notifications

Step 5: Configure OneSignal (if includeOneSignal is true)

  1. Create an app at onesignal.com and copy the App ID.

  2. Initialize OneSignal before runApp in main.dart:

    dart
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      OneSignal.initialize('<YOUR_ONESIGNAL_APP_ID>');
      runApp(const MyApp());
    }
  3. In Xcode, enable the same capabilities as FCM:

    • Push Notifications
    • Background Modes → Remote notifications

Step 6: Request Permission and Get the Token

In your post-launch initializer or onboarding flow:

dart
final pushSDK = getIt<PushNotificationSDK>();

// Request system permission (shows the OS prompt on first call)
await pushSDK.requestPermission();

// Retrieve the device token for your backend
final token = await pushSDK.getToken();
if (token != null) {
  await userRepository.registerDeviceToken(token);
}

Step 7: Handle Tap-Driven Navigation

When a user taps a notification, the SDK emits on tapStream. Wire this in your shell app after the router is ready:

dart
// apps/my_app/lib/host_app_widget.dart
@override
void initState() {
  super.initState();

  getIt<PushNotificationSDK>().tapStream.listen((notification) {
    if (notification.route != null) {
      router.push(RouteUri.parse(notification.route!));
    }
  });
}

The notification.route value is populated from a route key in the notification data payload, so your backend controls where deep links land.

Step 8: Simulate Topic Subscriptions with OneSignal

OneSignal does not have a native topic API like FCM. The SDK simulates topics using tags:

dart
// Subscribe the user to the "premium" topic
await pushSDK.subscribeToTopic('premium');
// Internally calls: OneSignal.User.addTag('topic_premium', 'true')

// Unsubscribe
await pushSDK.unsubscribeFromTopic('premium');
// Internally calls: OneSignal.User.removeTag('topic_premium')

Segment your OneSignal audiences by the topic_* tag keys to send targeted pushes.

Common Customizations

GoalWhat to do
Multiple notification channels (Android)Create additional NotificationChannel instances with distinct IDs
Handle foreground notificationsListen to foregroundStream on PushNotificationSDK
Send token to backend on refreshListen to tokenRefreshStream and re-register
Use APNs auth key instead of p12Upload the .p8 key in Firebase console → Project Settings → iOS app
Custom notification icon (Android)Set com.google.firebase.messaging.default_notification_icon in AndroidManifest.xml

Next Steps

Built by Banua Coder