このページは現在英語版のみで提供されており、日本語版も近日中に提供される予定です。ご利用いただきありがとうございます。

Implementing LiveActivity

Some Limits

iOS 16.1 and above versions support;
LiveActivity can be retained for up to eight hours, and up to twelve hours on the lock screen;
Remote operation requires users to configure the p8 certificate;
The equipment only supports iPhone, and is the iPhone 14 Pro and 14 Pro Max with a "pill-shaped screen";

Access Guide

1.Add support configuration for Live Activities

Add the key-value: Supports Live Activities = YES in the Info.plist of the main program.

2.Create a WidgetExtension. If there is already one in the project, skip this step.




3.Code implementation

3.1 Implement Activity Attributes

The following implementation needs to implement the corresponding data model according to your own business. Among them, the data in ContentState can be dynamically updated. It is recommended to define activityID as the unique identifier of LiveActivity.
import Foundation
import ActivityKit

struct LiveActivityAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var text: String
var pauseTime: Date?
var endTime: Date?
}

// Fixed non-changing properties about your activity go here!
// custom activityID when creating a LiveActivity
var activityID: String
}

3.2 Create UI

Please write the specific UI according to your own business. It contains the definitions of Lock Screen UI and Dynamic Island UI.
import ActivityKit
import WidgetKit
import SwiftUI

struct LiveActivityLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: LiveActivityAttributes.self) { context in
// Lock screen/banner UI goes here
VStack {
Text("Hello \(context.state.text)")
}
.activityBackgroundTint(Color.cyan)
.activitySystemActionForegroundColor(Color.black)

} dynamicIsland: { context in
DynamicIsland {
// Expanded UI goes here. Compose the expanded UI through
// various regions, like leading/trailing/center/bottom
DynamicIslandExpandedRegion(.leading) {
Text("Leading \(context.attributes.activityID)\(context.state.text)")
}
DynamicIslandExpandedRegion(.trailing) {
Text("Trailing \(context.state.text)")
}
DynamicIslandExpandedRegion(.center) {
Text("Center \(context.state.text)")
}
DynamicIslandExpandedRegion(.bottom) {
Text("Bottom \(context.state.text)")
// more content
}
} compactLeading: {
Text("CL \(context.state.text)")
} compactTrailing: {
Text("CT \(context.state.text)")
} minimal: {
Text("CB \(context.state.text)")
}
.widgetURL(URL(string: "https://cloud.tencent.com/document/product/269/100621"))
.keylineTint(Color.red)
}
}
}
The layout definition of Dynamic Island UI is as follows:



3.3 Client Operation, Add Startup, Update and Stop Logic

// start
let activity = try Activity.request(
attributes: adventure,
content: .init(state: initialState, staleDate: nil),
pushType: .token
)
// update
await activity.update(
ActivityContent<AdventureAttributes.ContentState>(
state: contentState,
staleDate: Date.now + 15,
relevanceScore: alert ? 100 : 50
),
alertConfiguration: alertConfig
)
// end
await activity.end(ActivityContent(state: finalContent, staleDate: nil), dismissalPolicy: dismissalPolicy)

3.4 Remote Reporting Configuration and Update Operation

Listen for token updates and report
Task {
for await pushToken in activity.pushTokenUpdates {
let pushTokenString = pushToken.hexadecimalString
Logger().debug("New push token: \(pushTokenString)")
try await self.setLiveActivity(activityID:activity.attributes.activityID, pushToken: pushToken)
}
}


func setLiveActivity(activityID: String, pushToken: Data) async throws {
var _apnsConfig = ImSDK_Plus.V2TIMLiveActivityConfig()
_apnsConfig.businessID = xxxx
_apnsConfig.token = pushToken
_apnsConfig.activityID = activityID
os_log("%@", type: .debug, "setLiveActivity activityID: \(activityID)\ntoken:\(pushToken.hexadecimalString)")
ImSDK_Plus.V2TIMManager.sharedInstance().setLiveActivity(_apnsConfig, succ: {
print("setLiveActivity succ")
}, fail: {code, desc in
print("setLiveActivity fail, \(code), \(desc)")
})
}
Submit the cleaning of LiveActivity
func clearActivity(activityID: String) async throws {
os_log("clearActivity ID: \(activityID)")
ImSDK_Plus.V2TIMManager.sharedInstance().setLiveActivity(nil, succ: {
print("clearActivity succ")
}, fail: {code, desc in
print("clearActivity fail, \(code), \(desc)")
})
}
Update and disable IOS real-time activity on the server side
Notes:
1. Push restrictions for LiveActivity. The P8 certificate, p8 certificate, must be configured.
2. If the recipient does not report the corresponding activityID, it will automatically downgrade to a normal notification push.
Format description of the JSON Object corresponding to ApnsInfo.LiveActivity
Field Name
Type
Option
Field description
LaId
string
Required
The flag of the real-time activity that needs to be pushed corresponds to the client activityID.
The length does not exceed 64 bytes.
Event
string
Required
update a policy Query an instance Reset the access password of an instance
ContentState
JSON Object
Required
Custom key: value object. It needs to match the client SDK value. Corresponding apns official document: Starting and updating Live Activities with ActivityKit push notifications | Apple Developer Documentation.
DismissalDate
Integer
Optional.
The uinx Time when the lock screen real-time activity ends if the event is end.
If not filled in, it defaults to the current time, and the lock screen will end soon.
Request sample:
Omitted or unlisted parameters in the example, refer to the documentation: Single chat, Wholesale chat, related to offlinePushInfo.
{
"MsgBody": [...] // Relevant description here for MsgBody
"OfflinePushInfo": {
"PushFlag": 0,
"Title": "Offline Push Title"
"Desc": "Offline push content"
"Ext": "{\"entity\":{\"k1\":\"v1\",\"k2\":\"v2\"}}", // custom passthrough field, use string in json format for push
"ApnsInfo": {
"LiveActivity": {
"LaId": "timpush",
"Event": "update", // update LA
"ContentState": {
"k1": v1,
"k2": v2,
...
}
}
},
"AndroidInfo": {
... // Related reference of AndroidInfo in official website document
}
}
}
{
"MsgBody": [...] // Relevant description here for MsgBody
"OfflinePushInfo": {
"PushFlag": 0,
"Title": "Offline Push Title"
"Desc": "Offline push content"
"Ext": "{\"entity\":{\"k1\":\"v1\",\"k2\":\"v2\"}}", // custom passthrough field, use string in json format for push
"ApnsInfo": {
"LiveActivity": {
"LaId": "timpush",
"Event": "end", // end LA
"ContentState": {
"k1": v1,
"k2": v2,
...
},
"DismissalDate": 1739502750
}
},
"AndroidInfo": {
... // Related reference of AndroidInfo in official website document
}
}
}