AlgorithmX
Integrations7 min read

iOS Push Notifications

Register an iOS FCM token and forward owned notifications through native helpers, while keeping business logic in React Native.

Use this page for React Native apps managing their own native project, including apps with React Native Firebase. Complete installation and native startup first. Expo users must preserve this Firebase integration through their native configuration; the existing Expo Notifications plugin does not supply iOS FCM registration.

AlgorithmX requires the Firebase FCM registration token on iOS. Configure your iOS app in Firebase, add its matching GoogleService-Info.plist, and upload the APNs key, Key ID, and Team ID to Firebase. AlgorithmX receives the project's service-account JSON through the dashboard setup. A raw APNs token or Expo Push Token is not the token for AlgorithmX.

Apple delivers the message to native iOS callbacks first. The helpers below connect those callbacks to AlgorithmX and leave your customer and navigation logic in JavaScript. Add them to the callbacks your app already has, one section at a time.

Start with a plain notification and an API-based in-app campaign. Images, buttons, and extension-based delivery reports are a later, optional step at the end of this page.

1. Register for APNs

After SDK initialization in AppDelegate.application(_:didFinishLaunchingWithOptions:):

swift
application.registerForRemoteNotifications() // Every launch.

In Xcode, enable Push Notifications and Background Modes → Remote notifications for the app target. Keep your existing visible-notification permission prompt; native registration does not ask the customer for permission to show alerts.

The examples use Swift. In a modern React Native AppDelegate, add override to application methods that already exist on its superclass. Merge these calls into existing callbacks rather than creating duplicate methods.

Registration asks Apple for this installation's APNs address. It is separate from the prompt asking the customer to allow visible alerts. Firebase maps that address to the FCM token that AlgorithmX uses.

2. Register the FCM token

Choose one route. The app keeps ownership of Firebase and its delegates; the core AlgorithmX SDK does not install Firebase.

With React Native Firebase

Use the optional Firebase adapter in AlgorithmX 1.1.1 or later. It registers current and refreshed FCM tokens on iOS and Android. Keep React Native Firebase's supported Apple token mapping and delegate configuration. If your app owns the APNs callback manually, pass deviceToken to Messaging.messaging().apnsToken and preserve its existing forwarding.

Do not call the native AlgorithmXReactNative.registerDeviceToken(Data) helper from the Apple callback: that legacy helper converts the raw APNs token to hexadecimal. The adapter supplies the required FCM string through the JavaScript API instead.

With Firebase configured directly in Swift

If your app does not use React Native Firebase, install FirebaseCore/FirebaseMessaging through your existing iOS dependency setup. Add MessagingDelegate to your AppDelegate's protocols. After AlgorithmXReactNative.initialize(...) and before remote-notification registration at startup:

swift
import FirebaseCore
import FirebaseMessaging

if FirebaseApp.app() == nil { FirebaseApp.configure() }
Messaging.messaging().delegate = self

Merge these methods into the existing AppDelegate. Use the core SDK's string API to register the FCM token; the core pod was installed with the React Native bridge in the startup guide.

swift
import AlgorithmXSDK

func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
    Messaging.messaging().apnsToken = deviceToken
    Messaging.messaging().token { token, error in
        if let error = error { print("FCM token registration failed: \(error.localizedDescription)") }
        if let token = token, !token.isEmpty {
            AlgorithmX.shared.registerDeviceToken(token)
        }
    }
    // Keep the Apple token forwarding required by any existing sender.
}

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
    guard let token = fcmToken, !token.isEmpty else { return }
    AlgorithmX.shared.registerDeviceToken(token)
}

This is the native Firebase route used by the React Native demo app. Do not install a second Firebase messaging delegate or combine it with the adapter route. Preserve any superclass callback forwarding your app or notification library requires.

Check: launch the app on an iPhone and confirm the FCM token reaches AlgorithmX. Register its current value on startup and send refreshed values too. If Apple registration fails, check signing, capabilities, and Firebase's APNs configuration before testing delivery.

3. Optional background notification callback

Silent/background pushes are handled by this main-app callback. They do not require a Notification Service Extension. Enable Background Modes → Remote notifications on the app target as described above.

swift
import AlgorithmXReactNativeSDK

func application(
    _ application: UIApplication,
    didReceiveRemoteNotification userInfo: [AnyHashable: Any],
    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
    if AlgorithmXReactNative.handleRemoteNotification(
        userInfo, completionHandler: completionHandler
    ) { return }
    // Your existing handling of other notifications goes here.
    completionHandler(.noData) // Fallback only if no existing handler owns it.
}

The SDK checks ownership and completes an owned notification itself. A false return leaves the completion untouched for your existing handler. Every path must complete exactly once; remove the fallback if your existing handler already completes it.

SDK 1.1.0 fetches in-app campaigns from the API on startup/foreground. Legacy silent in-app triggers are ignored. This callback is optional for other background notification processing; in-app views do not need it.

4. Forward foreground delivery and taps

Put these calls in the object that already implements UNUserNotificationCenterDelegate. If your app has no delegate, make AppDelegate conform to that protocol and set UNUserNotificationCenter.current().delegate = self at startup. Keep an existing delegate when another notification library owns it.

swift
func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
    if AlgorithmXReactNative.handleForegroundNotification(
        notification, completionHandler: completionHandler
    ) { return }
    // Your existing foreground handling goes here.
    completionHandler([]) // Fallback only if nothing else handles it.
}

func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
) {
    if AlgorithmXReactNative.handleNotificationResponse(
        response, completionHandler: completionHandler
    ) { return }
    // Your existing tap handling goes here.
    completionHandler() // Fallback only if nothing else handles it.
}

The foreground helper presents AlgorithmX alerts with banner, list, and sound by default. Pass presentationOptions: [] before completionHandler: if your app chooses to suppress visible foreground alerts.

Do not forward the same AlgorithmX message again through a JavaScript Firebase listener. Keep other notifications on their existing path. If Firebase, Notifee, or another library changes your delegate, verify that its supported integration still invokes the SDK helpers; replacing its delegate can break its notifications.

Check: send a plain dashboard test with the app in the background to confirm FCM delivery. Then send an AlgorithmX campaign while the app is open and in the background. Each campaign tap should reach the intended JavaScript action once; the plain test has no campaign navigation payload.

Optional images, buttons, and delivery reports

For rich iOS notifications with AlgorithmX images and action buttons, create or reuse a Notification Service Extension. Basic notifications, taps, background push callbacks, and API-based in-app campaigns do not require this extension. It can also report delivery and impressions when configured with a shared App Group.

The extension is a separate iOS target. This Swift Package Manager example links AlgorithmXSDK; React Native apps add the standalone helper file instead.
Xcode showing the separate Notification Service Extension target and its Frameworks and Libraries section

The extension is a separate iOS target. This Swift Package Manager example links AlgorithmXSDK; React Native apps add the standalone helper file instead.

  1. Open your app's .xcworkspace in Xcode. Create a target with File → New → Target → Notification Service Extension, or reuse your existing extension. Configure its bundle identifier, deployment version, and signing, and confirm it is embedded in the app.
  2. Download AlgorithmX's EngageNotificationService.swift helper for 1.1.0. The same file is available in the versioned iOS SDK source.
  3. Add the file in Xcode with Copy items if needed and only the extension target selected. Keep Xcode's NotificationService.swift. The helper is a second file; do not add AlgorithmXReactNativeSDK or the whole native pod to the extension.
  4. Use the extension handler example, omitting import AlgorithmXSDK. It calls EngageNotificationService.isAlgorithmXPush and processNotification, preserving your existing handling of other notifications.
  5. For delivery reports, enable the same App Group for the app and extension, use the wrapper's initialize(apiBaseUrl:partnerId:appGroup:) overload, and pass that group to the helper. Images and buttons alone can use the overload without an App Group.

Refresh the copied helper when upgrading the SDK. Test on an iPhone that an AlgorithmX notification displays its image/buttons and that unrelated notifications still work.

Next: customers, events, and navigation, then device tests.