Mastering iOS Live Activities: From Setup to Real‑Time Updates
This guide walks you through Apple’s Live Activity feature introduced at WWDC22, covering the required ActivityKit framework, project configuration for Objective‑C/Swift mixed or pure Swift apps, data modeling, creation, updating, ending, push‑token handling, server‑side push payloads, permission checks, and common pitfalls such as network‑image restrictions.
Introduction
At WWDC22 Apple introduced Live Activity to let apps display real‑time information on the lock screen. The feature is implemented via the ActivityKit framework and requires SwiftUI for the UI.
Scenario & Configuration
Live Activity is available on iOS 16.1+ (lock‑screen) and iPhone 14 Pro+ (Dynamic Island). Compared with iOS 16.0 widgets, Live Activities appear in the notification area, support custom views, and refresh via push or local updates. Limitations include an 8‑hour maximum duration, foreground‑only creation, a 4 KB push payload limit, and restrictions on creating multiple cards simultaneously.
Project Setup
OC & Swift mixed project : Create a Swift file in the main app to bridge to ActivityKit, which is Swift‑only. Add a new Target for the Live Activity, link it with the main app, and ensure the Target contains the UI and update logic.
Pure Swift project : No bridging file is needed; the same steps apply.
Both setups require adding NSSupportsLiveActivities = YES to the app’s Info.plist.
Data Model
struct ActivityWidgetAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
var process: Double
var title: String
// … other dynamic fields
}
var icon: String // static field
}The ContentState holds mutable data, while static fields are defined directly in the attribute struct.
Main Program
Creating a Live Activity:
let initialState = ActivityWidgetAttributes.ContentState(process: 0.6, title: "this is a title")
let attributes = ActivityWidgetAttributes(icon: "XiaoBu")
myActivity = try Activity.request(attributes: attributes, contentState: initialState, pushType: .token)Updating the activity:
let updateState = ActivityWidgetAttributes.ContentState(nickName: "Augus123")
let alert = AlertConfiguration(title: "111", body: "2222", sound: .default)
await myActivity?.update(using: updateState, alertConfiguration: alert)Ending the activity with a dismissal policy:
await myActivity?.end(using: nil, dismissalPolicy: .immediate)State Monitoring & Push Token Handling
Use activityStateUpdates to observe lifecycle changes and pushTokenUpdates to retrieve the push token, which must be sent to the backend for remote updates.
for await token in activity.pushTokenUpdates {
// send token to server
}From iOS 17.2 onward you can also use pushToStartTokenUpdates to obtain a token without launching the activity.
Permissions
Live Activity availability can be checked with ActivityAuthorizationInfo().areActivitiesEnabled. The value is read‑only and cannot be set programmatically.
Server‑Side Push Payload
{
"aps": {
"timestamp": 1666667682,
"event": "update",
"content-state": {"process": 0.7, "title": "更新的title"},
"alert": {"title": "Track Update", "body": "Tony Stark is now handling the delivery!"}
}
}Required fields: TEAM_ID, AUTH_KEY_ID, TOPIC (your bundle identifier with .push-type.liveactivity), and the device token. Use the APNs sandbox or production host accordingly.
Technical Challenge: Network Images
Live Activity extensions cannot perform network requests. To display remote images you must download them in the main app (e.g., via URLSession) and store them in an App Group container, then read the file from the extension.
private func downloadImage(from url: URL) async throws -> URL? {
guard var destination = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.test.liveactivityappgroup") else { return nil }
destination = destination.appendingPathComponent(url.lastPathComponent)
if FileManager.default.fileExists(atPath: destination.path()) { return destination }
let (source, _) = try await URLSession.shared.download(from: url)
try FileManager.default.moveItem(at: source, to: destination)
return destination
}In the extension, read the image from the shared container and display it with SwiftUI’s Image(uiImage:).
References
Live Activities UI – https://developer.apple.com/design/human-interface-guidelines/live-activities
Live Activities API – https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities
Live Activity Push Notifications – https://developer.apple.com/documentation/activitykit/starting-and-updating-live-activities-with-activitykit-push-notifications
How to fetch an image in live activity – https://forums.developer.apple.com/forums/thread/716902
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
