# Live Activities

Integrate Live Activities into your Unity app to display real-time updates on the iOS Lock Screen and Dynamic Island. {{< badge "axp" >}}


Live Activities are an iOS-only feature. The `liveActivityManager` module is a no-op on Android.

The Live Activity APIs require iOS 16.1 or later. On earlier versions, each call fails and reports the error to the `onError` callback.

For the push API method, see the [iOS Live Activities](https://www.airship.com/docs/guides/messaging/features/ios-live-activities/) messaging guide. See also the [iOS Live Activities](https://www.airship.com/docs/guides/features/messaging/live-activities-updates/) feature guide.

## App setup

Live Activities require native iOS setup that Unity does not generate. After exporting the Xcode project, add a widget extension that defines your `ActivityAttributes`, then register each Live Activity type with Airship using a plugin extender.

Using the [plugin extender](https://www.airship.com/docs/developer/sdk-integration/unity/installation/extending-airship/), call `LiveActivityManager.shared.setup` from `onAirshipReady` to configure your Live Activities. Call `configurator.register` for each Live Activity type that your app defines, and include a block that returns the property Airship uses to track the activity. This name is used to send updates through APNs.

```swift
import Foundation
import AirshipKit
import AirshipFrameworkProxy
import ActivityKit

// This class header is required to be automatically picked up by the Airship plugin:
@objc(AirshipPluginExtender)
public class AirshipPluginExtender: NSObject, AirshipPluginExtenderProtocol {

  public static func onAirshipReady() {

   if #available(iOS 16.1, *) {
      // Will throw if called more than once
      try? LiveActivityManager.shared.setup { configurator in

        // Call for each Live Activity type
        await configurator.register(forType: Activity<SportsActivityAttributes>.self) { attributes in
          // Track this property as the Airship name for updates
          attributes.gameID
        }
      }
    }

    // other setup

  }
}
```


> **Important:** Because Unity regenerates the Xcode project on a clean build, the widget extension and the extender must be reapplied, or scripted as a post-build step, whenever the project is regenerated.


## Starting Live Activities

Start a Live Activity with the `Start` coroutine. The `attributesType` must match the `ActivityAttributes` type defined in your widget extension.

```csharp
StartCoroutine(Airship.Shared.liveActivityManager.Start(
    new LiveActivityStartRequest() {
        attributesType = "SportsActivityAttributes",
        content = new LiveActivityContent() {
            state = new Dictionary<string, object>() {
                { "status", "Game Pending" },
            },
            relevanceScore = 0.0,
        },
        attributes = new Dictionary<string, object>() {
            { "gameID", "sports-game-123" },
        },
    },
    (LiveActivityInfo info) => {
        Debug.Log("Started Live Activity: " + info.id);
    },
    (System.Exception error) => {
        Debug.LogError("Failed to start Live Activity: " + error.Message);
    }
));
```


Each method takes an optional `onError` callback. Pass one to catch failures such as running on iOS 16.0, where the Live Activity APIs are unavailable.

## Updating Live Activities

To update a Live Activity, you need its activity ID. Use `ListAll` to find it.

```csharp
StartCoroutine(Airship.Shared.liveActivityManager.ListAll((LiveActivityInfo[] activities) => {
    foreach (LiveActivityInfo activity in activities) {
        StartCoroutine(Airship.Shared.liveActivityManager.Update(new LiveActivityUpdateRequest() {
            activityId = activity.id,
            content = new LiveActivityContent() {
                state = new Dictionary<string, object>() {
                    { "status", "Game starting!" },
                },
                relevanceScore = 0.0,
            },
        }));
    }
}));
```


## Ending Live Activities

End a Live Activity with the `End` coroutine and the activity ID. As with `Update`, use `ListAll` to find the ID.

```csharp
string liveActivityId = "<ACTIVITY_ID>";

StartCoroutine(Airship.Shared.liveActivityManager.End(new LiveActivityEndRequest() {
    activityId = liveActivityId,
    dismissalPolicy = new LiveActivityDismissalPolicy() {
        type = "default",
    },
}));
```


The dismissal policy `type` accepts `immediate`, `default`, or `after`. The `after` policy also requires an ISO 8601 date, set through the `date` field on `LiveActivityDismissalPolicy`.
