Using push notifications to signal changes

Send push notifications to a device to signal changes from your server.

Overview

You can signal changes by sending push notifications from a remote server, using the PushKit framework and the fileProvider push type. When the system receives the notification, it automatically calls the signalEnumerator(for:completionHandler:) method with the specified identifier. It also delivers the notification to any PKPushRegistryDelegate objects.

To use push notifications, you start by generating the signing key for your app. Next, you configure your app to receive push notifications. Finally, you send the notifications from your server. The following sections describe each step.

Generate the signing key

To signal changes from a remote server, you use provider authentication tokens (not provider certificates). To create an APNs key for your app, see Communicate with APNs using authentication tokens. Use the APNs key to sign your JSON Web Tokens (JWT) when sending notifications from your server.

Enable and register for push notifications

To receive notifications, you first enable push notifications in your app. You can register to receive push notifications in either your app delegate or in your file provider extension. Finally, you send the device token to your server.

First, enable push notifications in your iOS app (not your File Provider extension). For details, see Communicate with APNs using authentication tokens.

  1. Open the Capabilities pane for your app target.

  2. Turn on push notifications.

Then, register for push notifications. You can register in your app delegate, your File Provider extension, or both.

In your AppDelegate or FileProviderExtension classes, adopt the PKPushRegistryDelegate protocol.

import PushKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate {
    // ...
}
import PushKit

class FileProviderExtension: NSFileProviderExtension, PKPushRegistryDelegate {
    // ...
}

Also, create a pushRegistry instance variable in each class.

var pushRegistry: PKPushRegistry!

In your AppDelegate class’s application(_:didFinishLaunchingWithOptions:) method, register for push notifications.

func application(
    _ application: UIApplication, 
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
    pushRegistry = PKPushRegistry(queue: nil)
    pushRegistry.delegate = self
    pushRegistry.desiredPushTypes = [.fileProvider]
    return true
}

Similarly, in your FileProvider class’s init() method, register for push notifications.

override init() {
    super.init()
    pushRegistry = PKPushRegistry(queue: nil)
    pushRegistry.delegate = self
    pushRegistry.desiredPushTypes = [.fileProvider]
}

Finally, implement the pushRegistry(_:didUpdate:for:) delegate method in both your AppDelegate and FileProvider classes. The pushRegistry(_:didInvalidatePushTokenFor:) method is optional.

In both your AppDelegate and FileProvider classes’ pushRegistry(_:didUpdate:for:) methods, when you receive a PKPushCredentials instance, extract the value of its token property, and send it to your server. This value is an app-specific device token. Your server uses the device token to request push notifications for this device.

func pushRegistry(
    _ registry: PKPushRegistry, 
    didUpdate credentials: PKPushCredentials, 
    forType type: PKPushType
) {
    let deviceToken = credentials.token
    // Send the device token to your server here.
}

Send push notifications

You’re now ready to send a push notification. Start by creating a JWT; for details, see Provider Authentication Tokens. You can reuse the JWT as long as it remains valid.

Then send a POST request to the APNs server with the following values:

  • The :path value is /3/device/<device-token>. This token is the device token you sent to your server from your pushRegistry(_:didUpdate:for:) method.

  • The authorization value is bearer <provider token>. This token is your JWT.

  • The apns-topic value is <bundle identifier>.pushkit.fileprovider. The bundle identifier is your app’s bundle identifier.

The POST request’s content is a JSON dictionary that specifies the container and domain for the updated content. Set the container identifier to the unique string used in the container’s itemIdentifier property. You can also use NSFileProviderRootContainerItemIdentifier to update the root container, or NSFileProviderWorkingSetContainerItemIdentifier to update the working set.

Set the domain identifier to the unique string used in the domain’s identifier property.

 {
     "container-identifier": "<your-container-identifier>"
     "domain": "<your-domain-identifier>"
 }

For more information, see APNs Notification API.