Skip to Content

iOS SDK — Advanced

Beyond the core tracking methods, the iOS SDK handles push tokens, deep links, rich notifications, and offline resilience.

Push token management

Register for push in your AppDelegate:

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in if granted { DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } } }

Token registration (in didRegisterForRemoteNotificationsWithDeviceToken):

Aegis.shared.push.register(deviceToken: deviceToken)

The SDK automatically handles token refresh — when iOS issues a new token, the SDK re-registers with Active Reach.

Deep linking

Handle incoming deep links from push notifications or in-app messages:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool { if Aegis.shared.handleDeepLink(url) { return true } // Your own deep link handling return false }

The SDK parses Active Reach deep link parameters and routes to the appropriate screen.

Rich notifications

For image/video attachments in push notifications, add a Notification Service Extension (NSE):

  1. In Xcode: File → New → Target → Notification Service Extension
  2. Add AegisNotificationService as a dependency on the extension target
  3. Subclass it from the Active Reach base class:
import AegisNotificationService class NotificationService: AegisNotificationService { }

The base class handles image / video attachment download (25-second timeout) plus the push.delivered POST to /v1/push/engagement. No additional code is needed in the extension target.

App Group configuration

The NSE runs in a separate process from your host app, so it can’t read in-memory SDK state. Configuration is shared via an App Group UserDefaults suite that the host app writes and the NSE reads.

Setup steps:

  1. Create an App Group in Apple Developer (group.com.yourapp.aegis is the convention).

  2. Enable the App Group capability on both the host app and the NSE target.

  3. Tell the host SDK the suite name so it persists push tracker config + consent state to the shared store:

    AegisPushTracker.shared.configure(appGroupSuiteName: "group.com.yourapp.aegis")
  4. Tell the NSE the suite name by adding AegisNotificationServiceAppGroup to the extension’s Info.plist:

    <key>AegisNotificationServiceAppGroup</key> <string>group.com.yourapp.aegis</string>

Fallback: if the Info.plist key is missing, the NSE reads aegis_app_group from the push payload’s userInfo — useful for per-push configuration when you can’t ship a plist change.

The NSE checks the host app’s marketing consent state before posting any delivery telemetry. This is the iOS counterpart of the web SDK’s setOptIn per-channel mirror — both surfaces gate analytics on the same consent record.

The gate reads from the App Group UserDefaults (key: ai.aegis.consent.preferences) — the exact same record ConsentManager.shared.setConsent(...) writes:

import ActiveReachSDK // Host app — when the customer accepts marketing consent in your CMP: ConsentManager.shared.setConsent([.marketing: true])

What the NSE does at delivery time:

  • Consent granted → POST /v1/push/engagement with push.delivered (canonical wire shape per tests/drift/push-engagement-payload.json).
  • Consent denied → silently skip the POST. The OS still shows the rich notification; only the analytics call is suppressed.
  • No consent record yet → treated as denied (the host hasn’t shown its CMP). Once the customer grants consent, subsequent deliveries flow normally.

The customer-visible notification is independent of the gate — consent only affects what the platform measures, not what the customer sees. iOS-level UNNotificationCenter authorization governs whether the OS displays the notification at all; the Aegis consent gate is layered on top for marketing-analytics suppression.

Why the gate lives in the NSE, not the host app

Push delivery is a background event. By the time the host app launches and could check consent, the delivery moment has passed and the user has already seen (or dismissed) the notification. The NSE runs at the moment of delivery — it’s the only process with both the live consent state and the chance to suppress the analytics POST before iOS marks the delivery as complete.

The cross-SDK contract for this gate is pinned by libs/mobile-sdk/tests/drift/phase45-cross-platform.json under ios_nse_consent_gating.

App lifecycle

Track foreground/background transitions for accurate session management:

func applicationDidBecomeActive(_ application: UIApplication) { Aegis.shared.onAppResume() }

This triggers in-app message evaluation and session refresh.

Offline mode

The SDK caches events when the device is offline:

  • Events are stored in a local SQLite database
  • When connectivity returns, queued events are flushed in order
  • Max 1,000 offline events (configurable)

What’s next