1. 引言实时活动Live Activity是 iOS 16.1 引入的一项功能它允许应用在锁屏界面和灵动岛Dynamic Island上持续展示实时更新的信息例如外卖配送进度、体育比赛比分、航班动态等。用户无需解锁手机或打开应用就能一眼获取关键信息。本文将从零开始系统讲解 Live Activity 的开发流程包括项目配置、ActivityKit 框架的使用、UI 构建、动态数据更新以及注意事项帮助你快速上手并落地到实际业务中。2. 核心概念在动手编码之前先理解 Live Activity 的几个核心概念这有助于你把握整体架构。ActivityKitiOS 16.1 引入的官方框架负责 Live Activity 的创建、更新和结束。ActivityAttributes描述 Live Activity 静态内容的协议例如一场球赛的对阵双方、开赛时间等。ContentState描述 Live Activity 动态内容的协议例如当前比分、比赛进行到第几分钟等。灵动岛Dynamic IslandiPhone 14 Pro 及以上机型的交互区域Live Activity 可以在此紧凑展示。锁屏界面Live Activity 在锁屏上以较大尺寸展示可包含更多信息。3. 项目配置要使用 Live Activity首先需要在 Xcode 中完成以下配置步骤。3.1 开启 Capability在 Xcode 中选中你的 Target进入Signing Capabilities点击 Capability搜索并添加Live Activities。这是使用 ActivityKit 的前提条件。3.2 Info.plist 配置在 Info.plist 中添加以下键值用于声明应用支持实时活动keyNSSupportsLiveActivities/key true/如果你的应用需要支持用户手动结束实时活动还需要添加keyNSSupportsLiveActivitiesFrequentUpdates/key true/3.3 部署目标Live Activity 要求 iOS 16.1 及以上版本请在 Target 的Deployment Info中将最低部署版本设置为 16.1 或更高。4. 定义 ActivityAttributes 和 ContentState接下来我们定义一个配送场景的 Live Activity。首先创建ActivityAttributes和ContentState。import ActivityKit struct DeliveryActivityAttributes: ActivityAttributes { public struct ContentState: Codable, Hashable { // 动态内容当前配送状态描述 var status: String // 动态内容预计剩余分钟数 var estimatedArrivalMinutes: Int } // 静态内容订单号 var orderNumber: String // 静态内容配送地址 var deliveryAddress: String }这里将订单号和配送地址作为静态属性在活动创建时确定配送状态和预计剩余时间作为动态状态可以在活动进行中多次更新。5. 创建 Live Activity使用Activity.request方法创建实时活动。以下代码展示了如何发起一个配送活动的请求。import ActivityKit func startDeliveryActivity(orderNumber: String, address: String) { let attributes DeliveryActivityAttributes( orderNumber: orderNumber, deliveryAddress: address ) let initialState DeliveryActivityAttributes.ContentState( status: 商家已接单, estimatedArrivalMinutes: 45 ) let content ActivityContent( state: initialState, staleDate: Date().addingTimeInterval(60 * 60) ) do { let activity try Activity.request( attributes: attributes, content: content ) print(Live Activity 已创建: \(activity.id)) } catch { print(创建失败: \(error.localizedDescription)) } }创建成功后系统会返回一个Activity实例你可以通过它的id在后续更新或结束该活动时进行定位。6. 构建 Live Activity UILive Activity 的界面使用 SwiftUI 构建并通过ActivityConfiguration进行注册。你需要为灵动岛和锁屏分别设计视图。6.1 注册 ActivityConfiguration在 SwiftUI 的App入口或主视图中使用ActivityConfiguration注册你的活动类型。import SwiftUI import ActivityKit main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } .activityConfiguration(for: DeliveryActivityAttributes.self) { context in // 灵动岛视图 DeliveryLiveActivityView(context: context) } lockScreen: { context in // 锁屏视图 DeliveryLockScreenView(context: context) } } }6.2 灵动岛视图灵动岛空间有限视图应保持简洁通常只展示核心信息。struct DeliveryLiveActivityView: View { let context: ActivityViewContextDeliveryActivityAttributes var body: some View { HStack { Image(systemName: shippingbox.fill) .foregroundColor(.white) VStack(alignment: .leading) { Text(context.state.status) .font(.headline) .foregroundColor(.white) Text(预计 \(context.state.estimatedArrivalMinutes) 分钟) .font(.caption) .foregroundColor(.white.opacity(0.8)) } } .padding(.horizontal) } }6.3 锁屏视图锁屏视图空间更大可以展示更丰富的信息例如订单号、配送地址和进度条。struct DeliveryLockScreenView: View { let context: ActivityViewContextDeliveryActivityAttributes var body: some View { VStack(alignment: .leading, spacing: 8) { HStack { Text(订单号\(context.attributes.orderNumber)) .font(.caption) Spacer() Text(预计 \(context.state.estimatedArrivalMinutes) 分钟) .font(.caption) } Text(context.state.status) .font(.title2) .fontWeight(.bold) Text(配送至\(context.attributes.deliveryAddress)) .font(.caption) .foregroundColor(.secondary) ProgressView(value: progress) .progressViewStyle(.linear) } .padding() } private var progress: Double { // 根据实际业务计算进度这里简单返回一个示例值 0.6 } }7. 更新 Live Activity当业务状态发生变化时例如骑手取货、配送中、即将送达你需要更新对应的 Live Activity。import ActivityKit func updateDeliveryActivity(activity: ActivityDeliveryActivityAttributes, status: String, minutes: Int) { let updatedState DeliveryActivityAttributes.ContentState( status: status, estimatedArrivalMinutes: minutes ) Task { await activity.update( ActivityContent( state: updatedState, staleDate: Date().addingTimeInterval(60 * 60) ) ) } }更新操作是异步的建议在Task中执行。系统会平滑地过渡到新的状态用户无需任何操作。8. 结束 Live Activity当配送完成或活动不再需要展示时应主动结束 Live Activity释放系统资源。import ActivityKit func endDeliveryActivity(activity: ActivityDeliveryActivityAttributes) { Task { await activity.end( ActivityContent( state: DeliveryActivityAttributes.ContentState( status: 已送达, estimatedArrivalMinutes: 0 ), staleDate: nil ), dismissalPolicy: .immediate ) } }dismissalPolicy支持三种模式.immediate立即移除、.default由系统决定移除时机、.after(date)在指定日期后移除。9. 处理推送更新除了在应用内直接更新Live Activity 还支持通过远程推送APNs更新。这适用于应用不在前台甚至被杀死时的场景。9.1 推送 payload 格式推送 payload 需要包含content-state字段用于传递新的动态状态。{ aps: { timestamp: 1697184000, event: update, content-state: { status: 骑手已取货, estimatedArrivalMinutes: 25 } } }9.2 推送 token 获取在创建 Live Activity 后你需要获取推送 token 并上传到自己的服务器。Task { let pushToken try await activity.pushToken // 将 pushToken 上传到你的服务器 uploadToken(pushToken) }服务器持有该 token 后即可在任意时刻向对应 Live Activity 发送更新推送。10. 注意事项与最佳实践系统限制同一应用同时活跃的 Live Activity 数量有限制通常为 5 个超出后新的创建请求会失败。电量考虑频繁更新会消耗电量建议仅在关键状态变化时更新避免高频轮询。staleDate 设置合理设置staleDate系统会在该时间后自动将活动标记为过期避免展示陈旧信息。灵动岛适配灵动岛视图应保持极简避免过多文字导致截断。权限说明Live Activity 无需用户授权但用户可以在系统设置中手动关闭某个应用的实时活动。测试真机Live Activity 在模拟器上支持有限建议在真机上验证灵动岛和锁屏的实际效果。11. 总结Live Activity 为 iOS 应用提供了一种全新的信息展示方式能够显著提升用户体验。通过 ActivityKit你可以快速实现从创建、更新到结束的完整流程。关键在于合理设计静态属性和动态状态并为灵动岛和锁屏分别构建合适的视图。希望本文能帮助你顺利上手 Live Activity 开发。如果在实践中遇到问题欢迎在评论区交流讨论。
阅读完成 · 觉得有帮助?