Live Activity — iPhone 锁屏界面和 Dynamic Island 上的动态小组件,实时显示信息:配送状态、体育比分、计时器和音乐播放。通过 ActivityKit(Swift,iOS 16.1+)结合 WidgetKit 实现。Live Activity 可在本地或通过推送通知更新,支持多种状态,并在事件结束后由系统终止。更多信息请访问 ActivityKit Documentation。
要点
Live Activity — WidgetKit 的扩展,在 iPhone 锁屏界面和 Dynamic Island 上显示动态内容。与根据系统计时器更新的静态小组件不同,Live Activity 由应用程序启动并存在有限时间 — 活跃 Activity 最多 8 小时,完成后最多 4 小时。用户无需解锁设备即可查看最新数据:配送订单状态、出租车到目的地的距离、比赛结果或训练进度。
ActivityKit — 用于处理 Live Activities 的框架,在 iOS 16.1 中引入。提供用于请求、更新和终止 Activity 的 API。Activity 是一个包含内容和状态的对象。内容(ActivityContent)定义静态数据,状态(ActivityState)定义随时间变化的动态数据。系统自行决定何时渲染新状态 — 这可以节省电池并保证动画流畅。
每个 Live Activity 由 ActivityID 唯一标识,并绑定到一个进程 — 创建它的应用程序。系统可以在内存不足或电池电量低时终止 Activity。开发者通过 ActivityKit 委托收到强制终止通知,并可以保存最后状态以便恢复。
Live Activity 架构 基于两个框架:WidgetKit 负责渲染 SwiftUI 视图,ActivityKit 负责 Activity 的生命周期。开发者创建支持 LiveActivityConfiguration 的 WidgetBundle。每个配置定义数据类型(Attributes 和 State)以及系统在 Lock Screen 和 Dynamic Island 上渲染的 SwiftUI View。数据通过 ActivityAttributes 传输 — 一个具有用于内容的 let 字段和用于状态的 var 字段的结构体。
| 组件 | 用途 | API |
|---|---|---|
| Attributes | 整个 Activity 的静态数据 | let name: String, let icon: String |
| ContentState | 动态状态,在更新时改变 | var progress: Double, var status: Status |
| Activity | Activity 的请求和管理对象 | Activity.request(attributes:content:) |
| PushToken | 用于服务器推送更新的令牌 | activity.pushToken publisher |
| ActivityUI | 用于 Lock Screen 和 Dynamic Island 的 SwiftUI View | LockScreenView, ExpandedView, CompactView |
Activity 的生命周期 包括三个阶段:活跃(系统显示和更新)、最终(活动已完成但 UI 仍可见 4 小时)、已删除(系统移除 UI)。应用程序可以随时终止 Activity。系统也会强制终止 Activity — 例如在设备重启或超过 8 小时限制时。
import ActivityKit
struct DeliveryAttributes: ActivityAttributes {
public struct ContentState: Codable & Hashable {
var status: DeliveryStatus
var estimatedMinutes: Int
}
var orderNumber: String
var restaurantName: String
}
WidgetBundle 通过 @main 宏注册 Live Activity:小组件返回配置列表,包括 LiveActivityConfiguration。基于此配置,系统知道期望什么数据类型以及如何在不同的状态下渲染 UI — 紧凑、最小和扩展用于 Dynamic Island。
创建 Activity 从向 ActivityKit 发起请求开始。应用程序使用初始数据调用 Activity.request(attributes:content:pushType:)。系统检查设备上是否可用 Dynamic Island 并返回 Activity 对象。如果超过活跃 Activity 的限制,请求可能会失败 — 通常不超过 5 个同时进行。请求成功后,系统在 Lock Screen 上显示小组件,并在可能的情况下在 Dynamic Island 中显示。
let attributes = DeliveryAttributes(
orderNumber: "A-1234",
restaurantName: "Pizza House"
)
let initialState = DeliveryAttributes.ContentState(
status: DeliveryStatus.preparing,
estimatedMinutes: 30
)
do {
let activity = try await Activity<DeliveryAttributes>.request(
attributes: attributes,
content: ActivityContent(state: initialState, staleDate: nil),
pushType: .token
)
print("Activity started: \(activity.id)")
} catch {
print("Failed: \(error)")
}
用于 Live Activity 的 SwiftUI View 使用 WidgetKit 中的 LockScreenView、ExpandedView 和 CompactView 结构。View 接收包含当前属性和状态的上下文(ActivityViewContext)。View 的更新在从系统接收新状态时自动发生。Live Activity 仅支持有限的 SwiftUI 组件集 — Text、Image、HStack、VStack 和几个修改器。
每个 Live Activity View 必须轻量且快速 — 系统拒绝渲染沉重的视图。渲染时间限制 — 每帧 30 毫秒。动画仅限于状态之间的系统过渡 — Live Activity 中不支持自定义动画。渲染在 WidgetKit 进程的后台执行,具有 Lock Screen 响应优先权。
本地更新 — 应用程序通过调用 activity.update(using:) 更新 Activity 状态。该方法接受新的 ContentState 和可选的 AlertConfiguration,用于在更新时显示通知。本地更新快速 — 系统在下一个渲染周期中重绘 View,通常在 1-2 秒内。对于频繁更新(计时器、秒表)使用本地模式 — 比推送更可靠、更快速。
let updatedState = DeliveryAttributes.ContentState(
status: DeliveryStatus.outForDelivery,
estimatedMinutes: 10
)
await activity.update(
ActivityContent<DeliveryAttributes.ContentState>(
state: updatedState,
staleDate: Date().addingTimeInterval(60)
),
alertConfiguration: AlertConfiguration(
title: "Order out for delivery",
body: "Arriving in 10 min"
)
)
推送更新 — 服务器发送包含 JSON 格式新状态的 ActivityKit 推送通知。为此,应用程序从 activity.pushToken 发布者获取 pushToken 并将其传递给服务器。服务器向 APNs 发送包含新 ContentState 的 payload 的 POST 请求。系统接收推送,解码状态并更新 Live Activity,无需应用程序参与 — 这允许即使在应用程序关闭时也能更新 Activity。
对于不经常的更新(每 5-10 分钟配送状态),推送更新比本地更新更经济 — 应用程序无需保持网络连接。对于每 1-2 秒的频繁更新,请使用本地方法。服务器 payload 仅包含 ContentState 的可变字段 — Attributes 的静态数据仅在创建 Activity 时发送。
Dynamic Island — iPhone 14 Pro、15 Pro 及更新机型上的硬件-软件区域,可适应 Live Activity 的内容。系统自动以三种模式显示 Activity:紧凑(切口左侧的图标 + 短文本)、最小(仅图标)和扩展(300pt 矩形带信息)。开发者不直接管理这些模式 — 系统根据优先级和可用空间选择模式。
struct DeliveryLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: DeliveryAttributes.self) { context in
LockScreenView(context: context)
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedContent {
ExpandedView(context: context)
}
} compactLeading: {
CompactLeadingView(context: context)
} compactTrailing: {
CompactTrailingView(context: context)
} minimal: {
MinimalView(context: context)
}
}
}
}
Dynamic Island 支持交互性 — 用户触摸该区域并进入应用程序或打开扩展视图。点击紧凑模式切换到扩展模式,向左滑动将 Activity 隐藏到最小模式。扩展模式下的按钮(暂停/取消)通过 SwiftUI 的 Link 处理 — 系统使用 deep link URL 启动应用程序,处理在 UIApplicationDelegate 中进行。
Dynamic Island 限制:扩展模式宽度 — 最多 300pt,紧凑文本 — 最多 30 个字符。颜色和字体与系统主题一致 — 自定义有限。模式之间的过渡动画是系统性的,不可配置。如果多个应用程序有活跃的 Activity,Dynamic Island 根据启动时间和内容类型优先级显示它们。
常见问题
普通的 WidgetKit 小组件显示静态信息,并根据系统计时器以最短 15-30 分钟的间隔更新。Live Activity 在锁屏界面和 Dynamic Island 上实时显示动态数据。Live Activity 由应用程序启动,持续最多 8 小时,并在事件结束后由系统终止,与永久存在的小组件不同。
Live Activity 支持两种更新模式:本地 — 应用程序通过 ActivityKit API 随时更新状态;推送 — 服务器发送 ActivityKit 推送通知,系统将其转换为小组件的新状态。电池电量低时,系统可能会冻结 Live Activity 直到连接充电器。
Live Activities 在运行 iOS 16.1 及更新版本的 iPhone 上可用。在 iPhone 14 Pro 及更新机型上,Live Activity 也在 Dynamic Island 中显示。在 iPad 上,Live Activity 仅在锁屏界面上受支持 — iPad 上没有 Dynamic Island。Apple Watch 不直接支持 Live Activities,但可以显示完成通知。
系统限制活跃 Live Activities 的数量 — 通常所有应用程序同时不超过 5 个。尝试超过限制时,ActivityKit 返回错误。每个 Live Activity 可以有多个状态 — 例如,等待中、运送中、已送达用于食品订单。完成后,Activity 在 UI 中再保留 4 小时。
是的,应用程序必须请求发送通知的许可 — Live Activity 使用系统通知渠道。用户可以在设置中为特定应用程序关闭 Live Activity。首次启动时,ActivityKit 显示请求许可的对话框。没有许可,Activity 请求会失败并返回错误。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。