实现 LiveActivity(灵动岛)
限制说明
iOS 16.1 及以上版本支持。
灵动上岛最多保留八小时,在锁定屏幕上最多保留十二小时。
远端操作需要用户配置 p8 证书。
设备只支持 iPhone,并且是有“药丸屏”的 iPhone14Pro 和 14Pro Max 上。
接入指引
步骤1:增加 Live Activities 支持配置
需要在主程序的 Info.plist 中添加键值:Supports Live Activities 为 YES。
步骤2:创建 WidgetExtension,如果项目中已经存在,则跳过该步骤。


步骤3:代码实现
1.实现 Activity Attributes
以下实现需要按照自己的业务实现对应的数据模型,其中 ContentState 里为可以动态更新的数据,activityID 建议定义为 LiveActivity 的唯一标识 ID。
import Foundationimport ActivityKitstruct LiveActivityAttributes: ActivityAttributes {public struct ContentState: Codable, Hashable {// Dynamic stateful properties about your activity go here!var text: Stringvar pauseTime: Date?var endTime: Date?}// Fixed non-changing properties about your activity go here!// custom activityID when creating a LiveActivityvar activityID: String}
2.创建 UI
具体 UI 请按照自己的业务编写,包含了锁屏 UI 和灵动岛 UI 的定义:
import ActivityKitimport WidgetKitimport SwiftUIstruct LiveActivityLiveActivity: Widget {var body: some WidgetConfiguration {ActivityConfiguration(for: LiveActivityAttributes.self) { context in// Lock screen/banner UI goes hereVStack {Text("Hello \(context.state.text)")}.activityBackgroundTint(Color.cyan).activitySystemActionForegroundColor(Color.black)} dynamicIsland: { context inDynamicIsland {// Expanded UI goes here. Compose the expanded UI through// various regions, like leading/trailing/center/bottomDynamicIslandExpandedRegion(.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)}}}
灵动岛 UI 布局定义如下:

3.客户端操作,添加启动、更新和停止逻辑
// startlet activity = try Activity.request(attributes: adventure,content: .init(state: initialState, staleDate: nil),pushType: .token)// updateawait activity.update(ActivityContent<AdventureAttributes.ContentState>(state: contentState,staleDate: Date.now + 15,relevanceScore: alert ? 100 : 50),alertConfiguration: alertConfig)// endawait activity.end(ActivityContent(state: finalContent, staleDate: nil), dismissalPolicy: dismissalPolicy)
4.远端上报配置和更新操作
监听 token 更新和上报
Task {for await pushToken in activity.pushTokenUpdates {let pushTokenString = pushToken.hexadecimalStringLogger().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 = activityIDos_log("%@", type: .debug, "setLiveActivity activityID: \(activityID)\ntoken:\(pushToken.hexadecimalString)")ImSDK_Plus.V2TIMManager.sharedInstance().setLiveActivity(_apnsConfig, succ: {print("setLiveActivity succ")}, fail: {code, desc inprint("setLiveActivity fail, \(code), \(desc)")})}
上报清理 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 inprint("clearActivity fail, \(code), \(desc)")})}
通过服务端更新和停止 iOS 实时活动。
注意:
1. LiveActivity 推送限制 p8 证书,必须配置 P8 证书。
2. 如果接收方没有上报对应 activityID,将自动降级为普通通知推送。
ApnsInfo.LiveActivity 对应的 JSON Object格式说明
字段名称 | 类型 | 选项 | 字段说明 |
LaId | string | 必填 | 需要推送的实时活动标识,对应客户端 activityID。 长度不超过64字节。 |
Event | string | 必填 | 更新:“update”,结束:"end"。 |
ContentState | JSON Object | 必填 | 自定义的 key:value 的 object。需与客户端 SDK 值匹配。 |
DismissalDate | Integer | 选填 | event 为 end 时,锁屏实时活动结束展示的 uinx 时间。 不填默认为当前时间,锁屏会马上结束。 |
请求示例:
{"MsgBody": [...] // 这里同 MsgBody 相关描述"OfflinePushInfo": {"PushFlag": 0,"Title": "离线推送标题","Desc": "离线推送内容","Ext": "{\"entity\":{\"k1\":\"v1\",\"k2\":\"v2\"}}", // 透传字段,推送使用json格式字符串"ApnsInfo": {"LiveActivity": {"LaId": "timpush","Event": "update", // update LA"ContentState": {"k1": v1,"k2": v2,...}}},"AndroidInfo": {... // AndroidInfo相关参考官网文档}}}
{"MsgBody": [...] // 这里同 MsgBody 相关描述"OfflinePushInfo": {"PushFlag": 0,"Title": "离线推送标题","Desc": "离线推送内容","Ext": "{\"entity\":{\"k1\":\"v1\",\"k2\":\"v2\"}}", // 透传字段,推送使用json格式字符串"ApnsInfo": {"LiveActivity": {"LaId": "timpush","Event": "end", // end LA"ContentState": {"k1": v1,"k2": v2,...},"DismissalDate": 1739502750}},"AndroidInfo": {... // AndroidInfo相关参考官网文档}}}