AppDelegate Configuration

Let Pulsate own your app delegate (the default), or keep your own and forward the required UIApplicationDelegate and UNUserNotificationCenterDelegate callbacks to Pulsate.

By default, Pulsate takes ownership of your UIApplicationDelegate and UNUserNotificationCenterDelegate and forwards the callbacks back to your own delegate automatically. This is the simplest integration and requires no extra wiring.

If your app needs to keep ownership of these delegates — for example, because another SDK also requires them — you can opt out of Pulsate's ownership and forward the relevant callbacks yourself.

📘

Note

The SDK targets iOS 15 (build) and supports a minimum of iOS 13. The UNUserNotificationCenterDelegate methods below are always available on supported deployment targets.

Integration modes

There are two modes, selected by the last two arguments of getInstance(withAuthorizationData:withLaunchOptions:withPulsateAppDelegate:andPulsateNotificationDelegate:):

ModewithPulsateAppDelegateandPulsateNotificationDelegateYou forward callbacks?
Pulsate owns the delegates (default)truetrueNo
Host keeps the delegatesfalsefalseYes — see below

If you use the shorter getInstance(withAuthorizationData:withLaunchOptions:) initializer, Pulsate owns both delegates (equivalent to passing true/true).

1. Letting Pulsate own the delegates (default)

Create the manager and you're done — no callback forwarding required.

import UIKit
import PULPulsate

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        do {
            let authData = try PULAuthorizationData(withAppId: "APP_ID", andAppKey: "APP_KEY")
            _ = try PULPulsateFactory.getInstance(
                withAuthorizationData: authData,
                withLaunchOptions: launchOptions
            )
        } catch {
            print("Pulsate init failed: \(error)")
        }
        return true
    }
}

2. Keeping your own delegates

Pass withPulsateAppDelegate: false and andPulsateNotificationDelegate: false to keep ownership. In this mode you must forward the callbacks in the following sections.

let authData = try PULAuthorizationData(withAppId: "APP_ID", andAppKey: "APP_KEY")
let pulsateManager = try PULPulsateFactory.getInstance(
    withAuthorizationData: authData,
    withLaunchOptions: launchOptions,
    withPulsateAppDelegate: false,
    andPulsateNotificationDelegate: false
)

withPulsateAppDelegate: false tells Pulsate not to take ownership of the UIApplicationDelegate. andPulsateNotificationDelegate: false tells Pulsate not to take ownership of the UNUserNotificationCenterDelegate.

3. Getting the Pulsate system manager

Retrieve Pulsate's delegate proxy from the manager with getPulsateSystemManager(). It conforms to both UIApplicationDelegate and UNUserNotificationCenterDelegate, so store it as a combined type:

let pulsateSystemManager = pulsateManager.getPulsateSystemManager()
// Type: (UIApplicationDelegate & UNUserNotificationCenterDelegate)?

Forward each callback to this instance as shown below.

4. UIApplicationDelegate callbacks

Forward the following application-lifecycle and push callbacks:

func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
    pulsateSystemManager?.application?(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}

func application(
    _ application: UIApplication,
    didFailToRegisterForRemoteNotificationsWithError error: Error
) {
    pulsateSystemManager?.application?(application, didFailToRegisterForRemoteNotificationsWithError: error)
}

func application(
    _ application: UIApplication,
    didReceiveRemoteNotification userInfo: [AnyHashable: Any],
    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
    pulsateSystemManager?.application?(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
}

func application(
    _ app: UIApplication,
    open url: URL,
    options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
    pulsateSystemManager?.application?(app, open: url, options: options) ?? false
}

func application(
    _ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
    pulsateSystemManager?.application?(application, continue: userActivity, restorationHandler: restorationHandler) ?? false
}

func applicationDidBecomeActive(_ application: UIApplication) {
    pulsateSystemManager?.applicationDidBecomeActive?(application)
}

func applicationWillEnterForeground(_ application: UIApplication) {
    pulsateSystemManager?.applicationWillEnterForeground?(application)
}

func applicationDidEnterBackground(_ application: UIApplication) {
    pulsateSystemManager?.applicationDidEnterBackground?(application)
}

func applicationWillResignActive(_ application: UIApplication) {
    pulsateSystemManager?.applicationWillResignActive?(application)
}

func applicationWillTerminate(_ application: UIApplication) {
    pulsateSystemManager?.applicationWillTerminate?(application)
}

🚧

Important

Forward application(_:didFinishLaunchingWithOptions:) to the proxy as well if you construct the manager separately from launch. Pulsate reads the launch options during initialization, so passing launchOptions into getInstance(...) normally covers this.

5. UNUserNotificationCenterDelegate callbacks

For notification callbacks, inspect the sender field in the payload and forward to Pulsate only when Pulsate sent the push; otherwise handle it yourself.

func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
    let userInfo = notification.request.content.userInfo
    if let sender = userInfo["sender"] as? String, sender == "Pulsate" {
        // Pulsate sent the push — let Pulsate handle it
        pulsateSystemManager?.userNotificationCenter?(center, willPresent: notification, withCompletionHandler: completionHandler)
        return
    }
    // Not a Pulsate push — handle it yourself
    completionHandler([.banner, .list, .badge, .sound])
}

func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
) {
    let userInfo = response.notification.request.content.userInfo
    if let sender = userInfo["sender"] as? String, sender == "Pulsate" {
        // Pulsate sent the push — let Pulsate handle it
        pulsateSystemManager?.userNotificationCenter?(center, didReceive: response, withCompletionHandler: completionHandler)
        return
    }
    // Not a Pulsate push — handle it yourself
    completionHandler()
}

👍

Tip

If you don't keep the proxy in a stored property, fetch it on demand from the manager: PULPulsateFactory.getDefaultInstance()?.getPulsateSystemManager().

Related pages