For the complete documentation index, see llms.txt. This page is also available as Markdown.

SDK: Swift / Obj-C

Prerequisites

Before you can integrate the SDK with your app the following requirements must be met:

  • An iOS 11+ device (iPhone, iPad, or iPod Touch) to develop and test on, or a simulator that meets the requirements in Testing on a simulator.

  • A Mac OS device with XCode 14+ (Swift 5.7, if using Swift) installed.

  • An iOS P12 Push Certificate or P8 Key. If you do not already have these follow our documentation to generate them.

  • An App ID registered for your bundle id with the Push Notifications and App Groups capabilities enabled. See Register Your App ID.

  • SDK Key: Obtained from the Pushly Platform in the Domain Settings page under the Overview > Details > Domain Information section.

Step 1: Import the PushSDK Framework

The PushSDK Framework is compatible with both Swift and Objective-C.

  • Select the root project and then your primary application target > General

  • Click + > Add Other > Add Package Dependency under Frameworks, Libraries, and Embedded Content

  • Search using the Package URL: https://github.com/pushly/push-sdk-ios

  • Set the Dependency Rule to: Range of Versions and 1.0.0 < 2.0.0

  • Click Add Package

  • Ensure the Pushly option is checked and click Add Package

  • Finally, add the Pushly library to the Primary Application Target

The PushSDK Framework is compatible with both Swift and Objective-C.

CocoaPods Link: https://cocoapods.org/pods/Pushly

Add the following to your Podfile:

Then run a pod install inside your terminal, or from CocoaPods.app.

Step 2: Add the Notification Service Extension

The Notification Service Extension is required to enable rich notifications that support images and custom actions.

Within your app's XCode project select File > New > Target. Select Notification Service Extension inside the iOS templates tab and click Next.

Enter "NotificationServiceExtension" for the Product Name and any other configuration details for your app extension and then click Finish but do not click activate on the subsequent dialog.

Click Cancel on the dialoging prompting you to activate the service extension so that you can set the deployment target once the modal is closed.

Make sure to set your deployment target to the same as your primary application target. Unless you have a specific reason not to, you should set the Deployment Target to be iOS 11 which is the lowest supported version of iOS in the PushSDK Framework and in the most recent releases of XCode.

Next, add the Pushly library to your Notification Service Extension:

Click + under Frameworks and Libraries and select the already imported Pushly library.

Now, open the newly created Notification Service Extension and replace the code with the following:

You can ignore dependency errors, such as Module Pushly not found, at this point as they will be resolved during the next build.

Step 3: Add Capabilities to Primary Application Target

Select the root project and then your primary application target > Signing & Capabilities

Click the + Capability and add Push Notifications.

Click the + Capability and add Background Modes.

After adding the Background Modes capability ensure that Remote Notifications are enabled.

Adding Push Notifications writes the aps-environment entitlement into the target's entitlements file — development for debug builds, and production for release, TestFlight, and App Store builds. Xcode manages this value; you should not set it by hand.

Step 4: Configure the Shared App Group

Your app and its Notification Service Extension run as two separate processes. The shared App Group container is the only storage both can reach, and the PushSDK relies on it for everything that begins in one process and completes in the other.

The same App Group must be declared on both targets. If only one carries it, each process silently falls back to its own private storage and the sharing simply does not happen — with no error raised at the point of failure.

Naming

The SDK derives the identifier from your app's bundle id rather than reading it from configuration, so the two targets cannot disagree about which container to use. It must be exactly:

For an app whose bundle id is com.pushly.example, the App Group is group.com.pushly.example.push. The Notification Service Extension uses the app's bundle id here, not the extension's own.

Add it to the primary application target

With your primary application target selected under Signing & Capabilities, click the + Capability and add App Groups.

Click the + symbol located inside the App Groups section to add a new named container, and name it as above.

Check the box next to the newly created App Group in the primary application target.

Add it to the Notification Service Extension

Select the root project and then the NotificationServiceExtension > Signing & Capabilities

Click the + Capability and add App Groups.

Check the box next to the same App Group in the NotificationServiceExtension.

Adding the capability writes com.apple.security.application-groups into each target's entitlements file, containing the group identifier. Both files must list it.

With Automatically manage signing enabled, Xcode creates the App Group identifier, enables the App Groups capability on your App ID, and regenerates the provisioning profiles for both targets. If Xcode complains about the new App Group, it is usually still provisioning — refresh the list once it has finished.

If you manage signing manually, creating the identifier is not enough on its own: enable App Groups on the App ID as well, then regenerate and download both profiles.

What breaks without it

The SDK keeps running, but the features that depend on cross-process state stop working:

  • Notification impressions — recorded by the extension and completed by the app, so a severed container costs every one of them.

  • Badge counts — the shared count is no longer visible to both processes.

  • Service-extension attribution — notifications handled by the extension are no longer attributed correctly.

The per-installation event sequence counter is also guarded by a cross-process lock that lives in the container. Without the container the SDK falls back to a best-effort in-process increment, so events still carry a sequence value, but it is no longer coordinated between the two processes.

Confirming it is configured

The SDK reports the state of the shared container once per launch. When it is missing you will see:

When it is configured correctly, the same check reports the resolved identifier at debug level:

Step 5: SDK Initialization

First import the Pushly library in your AppDelegate

Add the following code to the AppDelegate's didFinishLaunchingWithOptions method of your application.

Replace the REPLACE_WITH_SDK_KEY in the setConfiguration method with the SDK Key from the platform settings page.

SwiftUI apps. If your app supplies its delegate with @UIApplicationDelegateAdaptor, place the setConfiguration call in that delegate's didFinishLaunchingWithOptions exactly as shown above — the integration works normally.

Be aware when debugging that SwiftUI installs its own SwiftUI.AppDelegate as UIApplication.shared.delegate and forwards callbacks on to your adapted class. Inspecting UIApplication.shared.delegate will therefore not show your own delegate type. This is expected and does not indicate a broken integration.

Step 6: Test the Implementation

Run your app on a physical iOS device, or on a simulator that meets the requirements in Testing on a simulator, to make sure it builds correctly.

The code you added in the previous step will show the push permission dialog upon app open. This can be customized using SDK methods to control when the dialog shows.

After accepting the dialog, log into the platform and navigate to Notifications > Create Notification and send your first notification, targeting the Native: iOS channel, to your device.

Testing on a simulator

A simulator can register with APNs and receive real remote notifications, so it can be used to test subscription and end-to-end delivery. This requires all of the following:

  • A Mac with Apple silicon or a T2 chip

  • macOS 13 or later

  • An iOS 16 or later simulator

  • Xcode 14 or later

When those conditions are met the app registers normally and iOS issues a genuine device token. Two things differ from a physical device:

  • The token is sandbox-only. Notifications must be sent through the APNs sandbox environment. A debug build carries aps-environment: development, which is what routes sends to sandbox, so this is handled for you.

  • The token is tied to that simulator on that Mac. It is specific to the combination of the simulator and the Mac hardware it runs on, so it is not portable, and erasing the simulator issues a new one.

Delivering a notification without APNs

xcrun simctl push delivers a notification straight to a booted simulator with no APNs setup at all, and works on any simulator regardless of the requirements above. It is the quickest way to check notification presentation and tap handling.

Save a payload as payload.apns:

Then deliver it to a booted simulator, replacing the bundle id with your own:

For the SDK to recognise the payload as a Pushly notification and process it, the payload must carry all of the following:

  • aps.alert as a dictionary — a plain string alert is not recognised

  • piid — string

  • notification_idinteger

  • landing_url — string

If any of these are missing or the wrong type, iOS still displays the notification but the SDK ignores it, and no SDK callbacks or events fire.

Next Steps

Once you have confirmed the SDK is working properly you may continue to add additional optional functionality like:

Last updated