Skip to content

Start and Update iOS Live Activities With Push Notifications

The third part of a series on Live Activities.

  1. What are iOS Live Activities and Four Kinds of Presentations
  2. Add Live Activities to Your iOS App in 5 Steps
  3. Start and Update iOS Live Activities With Push Notifications

Live activities are introduced in iOS 16.1.

On devices that run iOS 17.1 or iPadOS 17.1 and earlier, you can start a Live Activity in your app's code while it's in the foreground.

Additionaly, you can update or end a Live Activity with ActivityKit push notifications, as well as in your app's code both in the both foreground and background mode.

Starting with iOS 17.2 and iPadOS 17.2, you can start new Live Activities with ActivityKit push notifications.

Add Push Notifications Capability to Your App

push-notification-capability

Start a Live Activity With AcitivtyKit Push Notifcations

To start Live Activities from ActivityKit push notifications, configure your app to support push notifications. Then obtain the push-to-start token for starting a Live Activity and send a start event push notifcation to Your app using the push-to-start token.

1. Obtain the PushToStart Token

Configure your app to support push notifications. Then use the pushToStartTokenUpdates asynchronous sequence of Activity class to retrieve a push-to-start token that allows you to start new Live Activities

swift
func getPushToStartToken() {
    if #available(iOS 17.2, *) {
        Task {
            for await data in Activity<LiveActivityAttributes>.pushToStartTokenUpdates {
                let token = data.map {String(format: "%02x", $0)}.joined()
                        print("Activity PushToStart Token: \(token)")
                        //send this token to your notification server
                }
        }
    }
}

Then, send the push-to-start token to your push notification server.

2. Send Push Notifcation to Start a Live Activity

On your push notification server, use the push-to-start token to send a push notification that start a new Live Activity.

Authentication

You can only use Token-based authentication to send live activity push notifications.

Request Header

  • apns-push-type: liveactivity
  • apns-topic: <your bundleID>.push-type.liveactivity
  • apns-priority: 5 or 10

Payload

  • timestamp: the current time in seconds since 1970.
  • event: start
  • attributes-type: Set the value to match your custom ActivityAttributes type. For example LiveActivityAttributes in this case.
  • attributes: the static data of your live activity content.
  • content-state: the dynamic data of your live activity content.
  • alert: provide an alert to alert the user about a new Live Activity.

For more payload fields, please refer to the afterward section.

json
{
    "aps": {
        "timestamp": 1705547770,
        "event": "start",
        "content-state": {
            "emoji": "🍏🍏"
        },
        "attributes-type": "LiveActivityAttributes",
        "attributes": {
            "name": "Apple"
        },
        "alert": {
            "title": "Hello",
            "body": "World",
            "sound": "chime.aiff"
        }
    }
}

Send Test Push with apnspush.com

Open apnspush and send push notifications as the following image.

start-live-activity-with-push

3. Start a Live Activity and Observe Push Token for Updating

When the system receives the ActivityKit push notification on a device, it starts a new Live Activity, wakes up your app, and grants it background run time.

Then, you can receive the push token that you can use to update or end this activity afterwards using the activityUpdates asynchronous sequence of the Activity class.

swift
extension AppDelegate {
    func observeActivityPushToken() {
        Task {
            for await activityData in Activity<LiveActivityAttributes>.activityUpdates {
                Task {
                    for await tokenData in activityData.pushTokenUpdates {
                        let token = tokenData.map {String(format: "%02x", $0)}.joined()
                        print("Push token: \(token)")
                    }
                }
            }
        }
    }
}

Update or End a Live Activities With Push Notifications

1. Get the Push Token to Update a Live Activity

There are two ways that you can obtain the push token to update or end a Live Activity.

One way is to observe all the changes of ongoing Live Activites, including Live Activities created by push Notifications as well as those created by your apps'code. Then, observe every activity's pushTokenUpdates asynchronous sequence to obtain the push token, as shown in the previous section.

swift
extension AppDelegate {
    func observeActivityPushToken() {
        Task {
            for await activityData in Activity<LiveActivityAttributes>.activityUpdates {
                Task {
                    for await tokenData in activityData.pushTokenUpdates {
                        let token = tokenData.map {String(format: "%02x", $0)}.joined()
                        print("Push token: \(token)")
                    }
                }
            }
        }
    }
}

The other way is, when you start a Live Activity in your app's code with request(attributes:content:pushType:) method and pass token to its pushType parameter, you can receive a push token that’s unique to this Live Activity when observing this Live Activity's pushTokenUpdates asynchronous sequence.

swift
func startActivity() {
    guard ActivityAuthorizationInfo().areActivitiesEnabled else {
        print("You can't start live activity.")
        return
    }
    
    do {
        let atttribute = LiveActivityAttributes(name:"APNsPush")
        let initialState = LiveActivityAttributes.ContentState(emoji: "😇")
        let activity = try Activity<LiveActivityAttributes>.request(
            attributes: atttribute,
            content: .init(state:initialState , staleDate: nil),
            pushType: .token
        )
        self.currentActivity = activity
        
        let pushToken = activity.pushToken // Returns nil.
        Task {
            
            for await pushToken in activity.pushTokenUpdates {
                let pushTokenString = pushToken.reduce("") {
                    $0 + String(format: "%02x", $1)
                }
                print("New push token: \(pushTokenString)")
                //send this token to your notification server
            }
        }
    } catch {
        print(error)
    }
}

The push token for a Live Activity may change throughout its duration. so it's important to keep track of the push token for each Live Activity. Additionally, when you receive an updated token, invalidate the previous, now outdated token on your server. This step is necessary to ensure successful sending of subsequent updates.

2. Send Push Notifications to Update or End a Live Activity

Authentication

You can only use token-based authenticaiton but not certificate-based authenticaito to send Activity push notifications.

How To Generate APNs Token Key

Request Header

  • apns-push-type: liveactivity
  • apns-topic: <your bundleID>.push-type.liveactivity
  • apns-priority: 5 or 10

Payload

json
{
    "aps": {
        "timestamp": 1705560370,
        "event": "update",
        "content-state": {
            "emoji": "🍏🍑"
        },
        "stale-date": 1705567570,
        "alert": {
            "title": "Hello",
            "body": "Update World",
            "sound": "chime.aiff"
        }
    }
}
json
{
    "aps": {
        "timestamp": 1705560370,
        "event": "end",
        "content-state": {
            "emoji": "🍑🍑"
        },
        "dismissal-date": 1705567570,
        "alert": {
            "title": "Hello",
            "body": "Update World",
            "sound": "chime.aiff"
        }
    }
}
  1. timestamp
    Set the timestamp to the current timestamp in seconds since 1970 to allow the system to always display the most recent ActivityKit push update.
  2. event
    To update a Live Activity, set the value to update.
    To end a Live Activity, set the value to end.
  3. content-state
    Set the fields for the content-state key to match your custom Activity.ContentState type. The system will decode the JSON payload and update or end the Live Activity.
    If you end a Live Activity, also include the final content state to make sure the Live Activity displays the latest data after it ends.
    Always use default encoding strategies to encode your data, or the system can't decode the JSON payload which result in update failures.
  4. stale-date (optional)
    Add a timestamp in seconds since 1970 in the optional stale-date field to provide the time when the system will consider the Live Activity to be stale. With each update, you can advance this stale-date.
    When you can’t update the Live Activity because of without network or other reasons for some time until it becomes stale, the activityState changes to ActivityState.stale at the specified date.
    Use the activityStateUpdates stream in your app to monitor the activity state and respond to outdated Live Activities that haven’t received updates.
  5. dismissal-date (optional)
    When you end a Live Activity, by default the Live Activity appears on the Lock Screen for up to four hours after it ends to allow people to glance at their phone to see the latest information.
    To change the time until the system removes a Live Activity from the Lock Screen after it ends, add a timestamp in seconds since 1970 in the optional dismissal-date field.
    To dismiss the Live Activity from the Lock Screen immediately after it ends, provide a date for dismissal-date that’s in the past — for example, "dismissal-date": 1663177260.
  6. alert (optional)
    To alert a person about a critical Live Activity update, optionally provide an alert field.
    It will light up your device and display the expanded presentation on devices that support the Dynamic Island or a banner on devices that don’t support it.
    The title and body attributes of the alert will only be showed on Apple Watch.

Send Test Push with apnspush.com

Open apnspush and send push notifications as the following images.

update-live-activity-with-pushend-live-activity-with-push

Demo

LiveActivityPushDemo


Have any questions? Feel free to drop me a message on Twitter!

References