Push to start live activities
Description
One Line Summary
Update SDK to support Live Activities PushToStart
Details
Starting with iOS 17.2, Live Activities can now be started via push notification (Apple's documentation). This change enhances the OneSignal SDK to provide application's access to the full suite of Live Activity functionality.
Preferred method to setup Live Activities with OneSignal
A new function OneSignal.LiveActivities.setup has been created which allows OneSignal to manage the lifecycle of a LiveActivity on behalf of the application. This includes listening for both pushToStart token updates and pushToUpdate token updates. When using this method, the application does not need to listen for pushToStart token updates, the starting of a live activity, nor update token updates. A typical usage looks like this:
OneSignal.LiveActivities.setup(MyWidgetAttributes.self)
This method accepts any struct which adopts the OneSignalLiveActivityAttributes protocol. The OneSignalLiveActivityAttributes protocol establishes a high-level attribute onesignal which will be used internally by OneSignal.
If an application already has a LiveActivity using OneSignal.LiveActivities.enter when starting a live activity, it no longer has to listen for token updates explicitly, starting a Live Activity "in-app" will look something like this:
let oneSignalAttribute = OneSignalLiveActivityAttributeData.create(activityId: "my-activity-id")
let attributes = MyWidgetAttributes(onesignal: oneSignalAttribute, ...otherWidgetAttributes)
let contentState = MyWidgetAttributes.ContentState(widgetContentState)
do {
let _ = try Activity<MyWidgetAttributes>.request(
attributes: attributes,
contentState: contentState,
pushType: .token)
} catch let error {
print(error.localizedDescription)
}
Alternative (low level) method to setup Live Activities with OneSignal
Alternative to the above method, lower-level methods are provided. These methods require the application to listen for pushToStart token updates, the starting of live activities, and update token updates. This encompasses existing
functions OneSignal.LiveActivities.enter and OneSignal.LiveActivities.exit which are documented here. Additional new methods to cover registering/unregistering pushToStart tokens have been created:
-
OneSignal.LiveActivities.setPushToStartToken: To be called 'per-activity-type` each time that activity type's pushToStart token has been refreshed. The new pushToStart tokens are sync'd to the OneSignal backend and registered against the current subscription, where it can be the target of a started live activity. A typical usage looks like this:
if #available(iOS 17.2, *) {
// Setup an async task to monitor and send pushToStartToken updates to OneSignalSDK.
Task {
for try await data in Activity<MyWidgetAttributes>.pushToStartTokenUpdates {
let token = data.map {String(format: "%02x", $0)}.joined()
OneSignal.LiveActivities.setPushToStartToken(MyWidgetAttributes.self, withToken: token)
}
}
// Setup an async task to monitor for an activity to be started, for each started activity we
// can then set up an async task to monitor and send updateToken updates to OneSignalSDK. If
// there can be multiple instances of this activity-type, the activity-id (i.e. "my-activity-id") is
// most likely passed down as an attribute within MyWidgetAttributes.
Task {
for await activity in Activity<MyWidgetAttributes>.activityUpdates {
Task {
for await pushToken in activity.pushTokenUpdates {
let token = pushToken.map {String(format: "%02x", $0)}.joined()
OneSignal.LiveActivities.enter("my-activity-id", withToken: token)
}
}
}
}
}
-
OneSignal.LiveActivities.removePushToStartToken: To be calledper-activity-typewhenever that activity type should no longer be registered against the current subscription. A typical usage looks like this:
OneSignal.LiveActivities.removePushToStartToken(MyWidgetAttributes.self)
Motivation
Full support of Live Activities functionality introduced in iOS 17.2
Scope
Live Activities
Testing
Unit testing
- Added some basic unit testing to ensure the public APIs will not regress from their initial definition.
Manual testing
- Ran the iOS Example app and monitored log statements to ensure the pushToStart token and pushToUpdate token requests were being sent to the backend.
- Ensured a pushToStart request "per-activity-type, per token" was only sent up once.
- Ensured a pushToUpdate request "per-activity-id, per token" was only sent up once.
- Ensured the start/update requests are removed after their TTL expires.
Affected code checklist
- [ ] Notifications
- [ ] Display
- [ ] Open
- [ ] Push Processing
- [ ] Confirm Deliveries
- [ ] Outcomes
- [ ] Sessions
- [ ] In-App Messaging
- [x] REST API requests
- [x] Public API changes
- [x] Live Activities
Checklist
Overview
- [x] I have filled out all REQUIRED sections above
- [x] PR does one thing
- If it is hard to explain how any codes changes are related to each other then it most likely needs to be more than one PR
- [x] Any Public API changes are explained in the PR details and conform to existing APIs
Testing
- [ ] I have included test coverage for these changes, or explained why they are not needed
- [ ] All automated tests pass, or I explained why that is not possible
- [ ] I have personally tested this on my device, or explained why that is not possible
Final pass
- [ ] Code is as readable as possible.
- Simplify with less code, followed by splitting up code into well named functions and variables, followed by adding comments to the code.
- [ ] I have reviewed this PR myself, ensuring it meets each checklist item
- WIP (Work In Progress) is ok, but explain what is still in progress and what you would like feedback on. Start the PR title with "WIP" to indicate this.