How to start a Live Activity with a remote push notification

How to set up Live Activities on your iOS Mobile App with OneSignal

With iOS 17.2+, Live Activities can be started remotely. Also called "Push-To-Start Live Activities", they can be started and updated by a remote push notification. Live Activities can now be initiated when the app is in the foreground or background.

Setup

Requirements

  • Ensure you have the latest Live Activities compatible SDK starting with iOS 5.2.0 Beta-01, more details found in OneSignal's GitHub.

1. Create a Widget Extension with “Include Live Activity”

Follow the instructions in Step 1 of our Live Activities Setup Guide.

2. Update Info list

Follow the instructions in Step 2 of our Live Activities Setup Guide.

3. Define the Static and Dynamic Data of Your Live Activity

The OneSignalLiveActivityAttributes protocol inherits from ActivityAttributes and describes the content that appears in your Live Activity. In addition to your widget-specific static attribute data and dynamic ContentState it also defines a static onesignal attribute that contains metadata necessary for the OneSignal iOS SDK to manage the live activities lifecycle.

ExampleAppFirstWidgetAttributes.swift

import ActivityKit
import OneSignalLiveActivities

struct ExampleAppFirstWidgetAttributes: OneSignalLiveActivityAttributes {
    public struct ContentState: OneSignalLiveActivityContentState{
        
        // Dynamic stateful properties about your activity go here!
        var message: String
        var onesignal: OneSignalLiveActivityContentStateData?
    }
    // Fixed non-changing properties about your activity go here!
    var name: String
    var onesignal: OneSignalLiveActivityAttributeData
}

4. Add Live Activities UI to the Widget Extension

In the widget extension, the Live Activities interface code should be added in the Live Activity swift file.

import ActivityKit
import WidgetKit
import SwiftUI

 struct ExampleAppFirstWidget: Widget {
     var body: some WidgetConfiguration {
         ActivityConfiguration(for: ExampleAppFirstWidgetAttributes.self) { context in
             // Lock screen/banner UI goes here\VStack(alignment: .leading) {
             VStack {
                 Spacer()
                 Text("FIRST: " + context.attributes.title).font(.headline)
                 Spacer()
                 HStack {
                     Spacer()
                     Label {
                         Text(String(context.state.message))
                     } icon: {
                         Image("onesignaldemo")
                             .resizable()
                             .scaledToFit()
                             .frame(width: 40.0, height: 40.0)
                     }
                     Spacer()
                 }
                 Spacer()
             }
             .activitySystemActionForegroundColor(.black)
             .activityBackgroundTint(.white)
         } dynamicIsland: { _ in
             DynamicIsland {
                 // Expanded UI goes here.  Compose the expanded UI through
                 // various regions, like leading/trailing/center/bottom
                 DynamicIslandExpandedRegion(.leading) {
                     Text("Leading")
                 }
                 DynamicIslandExpandedRegion(.trailing) {
                     Text("Trailing")
                 }
                 DynamicIslandExpandedRegion(.bottom) {
                     Text("Bottom")
                     // more content
                 }
             } compactLeading: {
                 Text("L")
             } compactTrailing: {
                 Text("T")
             } minimal: {
                 Text("Min")
             }
             .widgetURL(URL(string: "http://www.apple.com"))
             .keylineTint(Color.red)
         }
     }
 }

5. Invoke the setup() in the AppDelegate

OneSignal makes this activity-id handoff seamless by providing a new function OneSignal.LiveActivities.setup that manages the life cycle of the Live Activity for 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, or update token updates.

In the AppDelegate, call the setup method.

AppDelegate.swift

if #available(iOS 16.1, *) {
	OneSignal.LiveActivities.setup(ExampleAppFirstWidgetAttributes.self)
}

6. Start the Live Activity with a remote push notification

The included activity_type param must be a stringified representation of the attributes struct used to define the Live Activity. In this case ExampleAppFirstWidgetAttributes becomes exampleappfirstwidgetattributes.

Additionally, a unique activity_id value must be created and used to represent the real-time event. In the example below, we specify my-example-activity-id. However, in a production setting, it is highly recommended to append a random unique value such as UUID to guarantee uniqueness.

There are a handful of parameters that must be included when creating the Push-to-Start Notification:

  • event_attributes is an object data structure that maps to the static attributes data defined in the widget struct.
  • event_updates is an object data structure that maps to the dynamic ContentState data defined in the widget struct.
  • An audience targeting parameter (included_segments, excluded_segments, include_subscription_ids, filters)
  • To avoid surprising users with a sudden Live Activity, include headings and content fields to alert the user when the Live Activity starts.
curl --request POST \ --url "http://onesignal.com/api/v1/apps/APP_ID/activities/activity/exampleappfirstwidgetattributes" \ --header "Authorization: Basic REST API KEY" \ --header "accept: application/json" \ --header "content-type: application/json" \ --data '{ "included_segments: ["Subscribed Users"], "activity_id": "my-example-activity-id", "attributes": { "foo": "bar" }, "event_updates": { "message": "hello" }, "name": "hello" }'

7. Update a Live Activity

To ensure that update notifications are sent to a Live Activity that has actually been started, it is important to use the same activity-id in both the start notification and the update notification. Include the same activity_id when making the API request along with the next iteration of event updates (or content state).

curl --request POST \
     --url https://onesignal.com/api/v1/apps/app_id/live_activities/my-example-activity-id/notifications \
     --header 'Authorization: Basic YOUR_REST_API_KEY' \
     --header 'Content-Type: application/json' \
     --header 'accept: application/json' \
     --data '
{
  "event": "update",
  "event_updates": {
    "message": "The content available to the Live Activity from the defined ContentState."
  },
  "name": "Internal OneSignal Notification Name",
  "contents": {
    "en": "English Message"
  },
  "headings": {
    "en": "English Message"
  },
  "sound": "beep.wav",
  "stale_date": 1695760785,
  "dismissal_date": 1703505600,
  "priority": 10
}

Follow our Live Activity Server API reference for instructions and examples on making a request to start a Live Activity remotely.