Skip to content

AppDelegate & SceneDelegate Configuration

Pulsate needs a small number of callbacks from your app: push-token registration, background pushes and notification taps. You keep ownership of your UIApplicationDelegate and forward those callbacks to Pulsate.

Create the manager with getInstance(withAuthorizationData:withLaunchOptions:andPulsateNotificationDelegate:). Pulsate never replaces your app delegate; the one choice is who owns the UNUserNotificationCenter delegate:

andPulsateNotificationDelegate Notification delegate You forward
false (recommended) Your app Sections 2 and 3
true Pulsate Section 2

Create the manager in application(_:didFinishLaunchingWithOptions:), and make your app delegate the notification center’s delegate before didFinishLaunching returns.

import UIKit
import UserNotifications
import PULPulsate
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var pulsateManager: PULPulsateManager?
/// Pulsate's delegate proxy. Fetched on demand so it is always current.
var pulsateSystemManager: (UIApplicationDelegate & UNUserNotificationCenterDelegate)? {
PULPulsateFactory.getDefaultInstance()?.getPulsateSystemManager()
}
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Must be set before this method returns. A notification tap that launches the app
// is delivered as soon as launch finishes; with no delegate set, it is dropped.
UNUserNotificationCenter.current().delegate = self
do {
let authData = try PULAuthorizationData(withAppId: "APP_ID", andAppKey: "APP_KEY")
pulsateManager = try PULPulsateFactory.getInstance(
withAuthorizationData: authData,
withLaunchOptions: launchOptions,
andPulsateNotificationDelegate: false
)
} catch {
print("Pulsate init failed: \(error)")
}
return true
}
}

getPulsateSystemManager() returns Pulsate’s delegate proxy, typed (UIApplicationDelegate & UNUserNotificationCenterDelegate)?. Forward each callback below to it.

2. Forward the push callbacks (UIApplicationDelegate)

Section titled “2. Forward the push callbacks (UIApplicationDelegate)”

These stay on your app delegate whether or not your app uses scenes. Without them your push token is never registered with Pulsate.

extension AppDelegate {
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)
}
}

3. Forward notification presentation and taps (UNUserNotificationCenterDelegate)

Section titled “3. Forward notification presentation and taps (UNUserNotificationCenterDelegate)”

Skip this section if you passed andPulsateNotificationDelegate: true.

Forward to Pulsate only the pushes Pulsate sent - those whose payload sender is "Pulsate" or "PulsateDebug". Handle every other push yourself: Pulsate does not call the completion handler for pushes it did not send.

extension AppDelegate: UNUserNotificationCenterDelegate {
private func isPulsatePush(_ notification: UNNotification) -> Bool {
let sender = notification.request.content.userInfo["sender"] as? String
return sender == "Pulsate" || sender == "PulsateDebug"
}
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
if isPulsatePush(notification), let pulsate = pulsateSystemManager {
pulsate.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
) {
if isPulsatePush(response.notification), let pulsate = pulsateSystemManager {
// Pulsate opens the campaign's URL, deeplink, card or feed
pulsate.userNotificationCenter?(center, didReceive: response, withCompletionHandler: completionHandler)
return
}
// Not a Pulsate push - handle it yourself
completionHandler()
}
}

Apps built with Xcode 27 must use the UIScene lifecycle (a UIApplicationSceneManifest in Info.plist). Pulsate’s integration does not change: everything it needs stays on the app delegate, and your scene delegate forwards nothing to Pulsate.

Callback Where it goes
Push token, registration failure, background push App delegate (section 2)
UNUserNotificationCenter delegate App delegate, set in didFinishLaunching (section 3)
Foreground / background Nothing to forward - Pulsate handles it

You call getInstance(...withPulsateAppDelegate: false, andPulsateNotificationDelegate: X) - remove the withPulsateAppDelegate: false argument. Nothing else changes.

You call getInstance(withLaunchOptions:), getInstance(withAuthorizationData:withLaunchOptions:), or pass withPulsateAppDelegate: true - Pulsate is currently your app delegate:

  1. Switch to getInstance(withAuthorizationData:withLaunchOptions:andPulsateNotificationDelegate:). Pass true to keep Pulsate as the notification delegate, as before, or false and forward as in section 3.
  2. Forward the push callbacks in section 2 - without this, your push token is never registered.
  3. Nothing else needs forwarding: not the foreground/background callbacks, application(_:open:options:), application(_:continue:restorationHandler:) or applicationWillTerminate(_:).