NPNotify Partners Docs

iOS SDK

Integrating Notify Partners push notifications into an iOS application — installation via Swift Package Manager, APNs setup, SDK initialization, and full API reference.

Requirements

  • iOS 13.0+
  • Swift 5.9+ (Swift 6 concurrency supported)
  • Xcode 15+
  • Apple Developer account with APNs configured
  • app_id from the Notify Partners dashboard

1. Installation via Swift Package Manager

  1. In Xcode: File → Add Package Dependencies...
  2. Enter the SDK repository URL
  3. Select a version (or the main branch)
  4. Add NotifyPartnersSDK to your target

Alternatively, add the dependency in Package.swift:

dependencies: [
    .package(url: "https://github.com/anthropics/notify-partners-ios-sdk", from: "1.0.0")
]

The SDK has no external dependencies — only URLSession from Foundation is used.

2. APNs Setup

  1. In the Apple Developer Portal: enable Push Notifications for your App ID
  2. Create an APNs Key (recommended) or an APNs Certificate
  3. In Xcode: add the Push Notifications capability in your target settings
  4. Add the Background Modes capability → Remote notifications

3. SDK Initialization

Initialize the SDK in AppDelegate.didFinishLaunchingWithOptions:

Basic

import UIKit
import NotifyPartnersSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let config = NotifyPartnersConfig(appId: "YOUR_APP_ID")
        NotifyPartnersSDK.shared.initialize(config: config)

        return true
    }
}

With All Options

import UIKit
import NotifyPartnersSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let config = NotifyPartnersConfig(
            appId: "YOUR_APP_ID",
            externalId: "user-123",
            requestTimeoutSeconds: 10,
            resourceTimeoutSeconds: 30,
            debugLogging: true,
            manageNotificationDelegate: true
        )

        NotifyPartnersSDK.shared.setListener(self)
        NotifyPartnersSDK.shared.initialize(config: config)

        return true
    }
}

extension AppDelegate: NotifyPartnersListener {
    func onInitialized(instanceId: String) {
        print("SDK ready: \(instanceId)")
    }

    func onInitializationFailed(error: SdkError) {
        print("Init failed: \(error.localizedDescription)")
    }

    func onMessageReceived(msgId: String, title: String, body: String, data: [String: String]) {
        print("Push received: \(title)")
    }
}

What Happens During Initialization

  1. A unique device token is generated (or restored from UserDefaults) and the device is registered on the server
  2. The notification delegate is configured (with forwarding to the previous delegate)
  3. Push notification permission is requested and the device registers for remote notifications
  4. Device info is sent to the server and periodic updates begin
  5. The listener is notified via onInitialized(instanceId:) on success

4. Passing the APNs Token

Pass the APNs device token to the SDK in AppDelegate:

func application(_ application: UIApplication,
                 didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    NotifyPartnersSDK.shared.setAPNsToken(deviceToken)
}

5. Lifecycle Events

Send lifecycle events from SceneDelegate:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    func sceneDidBecomeActive(_ scene: UIScene) {
        NotifyPartnersSDK.shared.notifyLifecycle(.onscreen)
    }

    func sceneWillResignActive(_ scene: UIScene) {
        NotifyPartnersSDK.shared.notifyLifecycle(.background)
    }
}

If the application does not use Scenes, use AppDelegate methods:

func applicationDidBecomeActive(_ application: UIApplication) {
    NotifyPartnersSDK.shared.notifyLifecycle(.onscreen)
}

func applicationWillResignActive(_ application: UIApplication) {
    NotifyPartnersSDK.shared.notifyLifecycle(.background)
}

6. Push Notification Handling

The SDK automatically sets PushNotificationHandler.shared as the UNUserNotificationCenter delegate (when manageNotificationDelegate is true, which is the default). If your application already has a delegate, the SDK retains it and forwards all calls.

PushNotificationHandler automatically:

  • On foreground delivery: sends a delivered event, calls onMessageReceived on the listener, and displays the notification (banner + sound + badge)
  • On notification tap: sends a clicked event

Both handlers extract msg_id from the push payload using NotifyPartnersConstants.msgIdKey.

Push Payload Format

{
  "aps": {
    "alert": {
      "title": "Title",
      "body": "Notification body"
    }
  },
  "msg_id": "message-uuid",
  "url": "https://example.com/action"
}

Extract the URL from the push payload for navigation:

if let url = userInfo[NotifyPartnersConstants.urlKey] as? String {
    // Handle deep link
}

Managing the Delegate Manually

let config = NotifyPartnersConfig(
    appId: "YOUR_APP_ID",
    manageNotificationDelegate: false
)
NotifyPartnersSDK.shared.initialize(config: config)

// Assign your own delegate:
UNUserNotificationCenter.current().delegate = yourDelegate

When managing the delegate manually, call notifyDelivered/notifyClicked from your delegate.

7. Tags and Segmentation

// Set tags
try NotifyPartnersSDK.shared.setTags([
    "plan": "premium",
    "city": "moscow",
    "interests": "sports"
])

// Update external ID
try NotifyPartnersSDK.shared.setExternalId("user-456")

Validation limits:

  • Maximum 50 tags per call
  • Tag key: maximum 128 characters, must not be blank
  • Tag value: maximum 256 characters
  • externalId: maximum 256 characters
  • Violations throw SdkError.configurationError

Debouncing: rapid consecutive calls to setTags or setExternalId are coalesced (500ms window) — only the last value is sent to the server.

8. Shutdown

NotifyPartnersSDK.shared.shutdown()

After shutdown, initialize(config:) can be called again with new configuration.

Full Example

AppDelegate.swift

import UIKit
import NotifyPartnersSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let config = NotifyPartnersConfig(appId: "YOUR_APP_ID", externalId: "user-123")
        NotifyPartnersSDK.shared.initialize(config: config)
        return true
    }

    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        NotifyPartnersSDK.shared.setAPNsToken(deviceToken)
    }
}

SceneDelegate.swift

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func sceneDidBecomeActive(_ scene: UIScene) {
        NotifyPartnersSDK.shared.notifyLifecycle(.onscreen)
    }

    func sceneWillResignActive(_ scene: UIScene) {
        NotifyPartnersSDK.shared.notifyLifecycle(.background)
    }
}

API Reference

NotifyPartnersSDK

@MainActor singleton. The main entry point.

@MainActor
public final class NotifyPartnersSDK {
    public static let shared = NotifyPartnersSDK()
    public private(set) var isInitialized: Bool
}

initialize(config:)

Initialize the SDK. Call in AppDelegate.didFinishLaunchingWithOptions.

public func initialize(config: NotifyPartnersConfig)
ParameterTypeDescription
configNotifyPartnersConfigSDK configuration (see below)

Protected against double initialization — subsequent calls are ignored. Call shutdown() first to re-initialize.


shutdown

Release all resources: cancels pending operations, stops periodic updates, removes the listener.

public func shutdown()

After shutdown, initialize(config:) can be called again.


setListener

Set the listener for SDK lifecycle events.

public func setListener(_ listener: (any NotifyPartnersListener)?)

Pass nil to remove the listener. Set before initialize(config:) to receive onInitialized.


setAPNsToken

Pass the APNs device token. Call in AppDelegate.didRegisterForRemoteNotificationsWithDeviceToken.

public func setAPNsToken(_ deviceToken: Data)
ParameterTypeDescription
deviceTokenDataRaw APNs token from the system

setExternalId

Update the external user identifier.

public func setExternalId(_ externalId: String) throws(SdkError)
ParameterTypeDescription
externalIdStringExternal user identifier (max 256 characters)
  • Throws SdkError.configurationError if exceeds 256 characters
  • If SDK is not initialized, the call is silently ignored
  • Debounced — rapid calls are coalesced

setTags

Set tags for user segmentation.

public func setTags(_ tags: [String: String]) throws(SdkError)
ParameterTypeDescription
tags[String: String]Tags for segmentation (max 50, key ≤128, value ≤256)
  • Throws SdkError.configurationError on validation failure
  • If SDK is not initialized, the call is silently ignored
  • Tags are replaced in full (not merged)
  • Debounced — rapid calls are coalesced

notifyDelivered

Report that a push notification was delivered. Called automatically by PushNotificationHandler.

public func notifyDelivered(msgId: String)

notifyClicked

Report that a push notification was clicked. Called automatically by PushNotificationHandler.

public func notifyClicked(msgId: String)

notifyLifecycle

Send a lifecycle event.

public func notifyLifecycle(_ event: LifecycleEvent)
ValueWhen to call
.onscreensceneDidBecomeActive / applicationDidBecomeActive
.backgroundsceneWillResignActive / applicationWillResignActive
.closedOn application termination (optional)

isInitialized

public private(set) var isInitialized: Bool

Read-only property. Returns true if the SDK has been initialized.


NotifyPartnersConfig

public struct NotifyPartnersConfig: Sendable {
    public let appId: String
    public let externalId: String?
    public let requestTimeoutSeconds: TimeInterval
    public let resourceTimeoutSeconds: TimeInterval
    public let debugLogging: Bool
    public let manageNotificationDelegate: Bool
}
FieldTypeDefaultDescription
appIdStringApplication ID (required)
externalIdString?nilExternal user identifier
requestTimeoutSecondsTimeInterval10HTTP request timeout (seconds)
resourceTimeoutSecondsTimeInterval30HTTP resource timeout (seconds)
debugLoggingBoolfalseEnable verbose logging
manageNotificationDelegateBooltrueAutomatically manage UNUserNotificationCenter delegate

NotifyPartnersListener

Protocol for SDK lifecycle callbacks. All methods have default empty implementations — implement only what you need.

public protocol NotifyPartnersListener: AnyObject {
    func onInitialized(instanceId: String)
    func onInitializationFailed(error: SdkError)
    func onMessageReceived(msgId: String, title: String, body: String, data: [String: String])
}
CallbackWhen it fires
onInitialized(instanceId)SDK registered with server successfully
onInitializationFailed(error)All retry attempts failed
onMessageReceived(msgId, title, body, data)Push message received while app is in foreground

SdkError

Typed error enum for structured handling.

public enum SdkError: Error, LocalizedError, Sendable {
    case networkError(String)
    case serverError(httpCode: Int, body: String)
    case clientError(httpCode: Int, body: String)
    case timeoutError(String)
    case configurationError(String)
}
CaseRetryableDescription
networkErrorYesDNS, offline, TLS failure
serverErrorYesHTTP 5xx
timeoutErrorYesRequest timed out
clientErrorNoHTTP 4xx
configurationErrorNoInvalid config (blank appId, validation failure)

NotifyPartnersConstants

Public constants for push notification payload keys.

public enum NotifyPartnersConstants {
    public static let msgIdKey = "msg_id"
    public static let urlKey = "url"
}

Use these when extracting data from UNNotification.request.content.userInfo:

if let msgId = userInfo[NotifyPartnersConstants.msgIdKey] as? String {
    NotifyPartnersSDK.shared.notifyClicked(msgId: msgId)
}

LifecycleEvent

public enum LifecycleEvent: String, Sendable {
    case onscreen
    case background
    case closed
}

PushNotificationHandler

Built-in push notification handler. Implements UNUserNotificationCenterDelegate.

public final class PushNotificationHandler: NSObject, UNUserNotificationCenterDelegate {
    public static let shared = PushNotificationHandler()
}

Automatically installed when manageNotificationDelegate is true. Forwards all calls to the previous delegate if one was set.