原文地址:官方文档地址
概述
实时活动在iPhone锁定屏幕上显示和更新应用程序的最新数据。这允许人们一目了然地看到他们最关心的实时信息。
重要的
Live Activities和ActivityKit将不会包含在最初公开发布的iOS 16版本中,但将在今年晚些时候的更新中公开发布。一旦它们公开发布,您可以将带有Live Activities的应用程序提交到App Store。
要提供实时活动,请向现有小部件扩展添加代码,或者如果您的应用程序尚未包含新的小部件扩展,则创建新的小部件扩展。Live Activities使用WidgetKit功能和SwiftUI作为锁定屏幕上的用户界面。ActivityKit的作用是处理每个实时活动的生命周期:您可以使用其API请求、更新和结束实时活动。
/现场活动仅在iPhone上提供。/
查看“实时活动”要求和限制
除非您的应用程序或用户明确终止,否则实时活动最多可以活动八小时。在此限制之后,如果用户或您的应用程序尚未结束实时活动,系统会自动结束活动。在这个结束状态下,实时活动在锁定屏幕上最多可延长四个小时,然后系统将其删除。用户也可以选择删除它。因此,实时活动在锁定屏幕上最多停留12小时。
有关结束实时活动的更多信息,请参阅下面的“从应用程序内结束实时活动”。
每个实时活动都在自己的沙盒中运行,与小部件不同,它无法访问网络或接收位置更新。要更新活动实时活动的动态数据,请使用应用程序中的ActivityKit框架,或允许您的实时活动接收远程推送通知,如下面的“使用远程推送通知更新或结束实时活动”部分中所述。
活动套件更新和远程推送通知更新的动态数据大小不得超过4KB。
为您的应用程序添加对实时活动的支持
描述实时活动用户界面的代码是应用程序小部件扩展的一部分。如果您已经在应用程序中提供了小部件,您可以将实时活动的用户界面代码添加到现有的小部件扩展中,并可能能够在小部件和实时活动之间重用代码。然而,尽管Live Activities利用了WidgetKit的功能,但它们不是小部件。与用于更新小部件用户界面的时间机制不同,您可以使用ActivityKit或远程推送通知从应用程序更新实时活动。
您可以创建一个小部件扩展来采用实时活动,而无需提供小部件。但是,请考虑同时提供小部件和实时活动,让人们在主屏幕和锁定屏幕上添加可浏览的信息和个人触摸。
要为您的应用程序添加对实时活动的支持:
1、如果您尚未向应用程序添加小部件扩展,请创建一个小部件扩展。有关创建小部件扩展的更多信息,请参阅WidgetKit和创建小部件扩展。
2、打开应用程序的Info.plist文件,并添加一个条目,其键为布尔类型为NSSupportsLiveActivities,值为YES。
3、在您的代码中,为您的实时活动定义一组ActivityAttributes和Activity.ContentState。您将使用它们开始、更新和结束实时活动。
4、添加代码以创建小部件,并在小部件实现中返回ActivityConfiguration,如下例所示。
5、如果您的应用程序已经包含小部件,请将您的实时活动添加到您的WidgetBundle中,或按照创建小部件扩展中所述创建一个。如果您只添加小部件扩展以支持实时活动,请跳过此步骤。
6、添加代码以开始、更新和结束实时活动,并创建其用户界面,如下所述。
7、要测试您的实时活动,请在模拟器中运行您的应用程序,并从应用程序的用户界面启动实时活动。
以下代码片段返回一个活动配置,以将包含交付信息的实时活动添加到披萨交付应用程序中:
import ActivityKit
import SwiftUI
import WidgetKit
struct PizzaDeliveryAttributes: ActivityAttributes {
public typealias PizzaDeliveryStatus = ContentState
public struct ContentState: Codable, Hashable {
var driverName: String
var estimatedDeliveryTime: Date
}
var numberOfPizzas: Int
var totalAmount: String
}
struct PizzaDeliveryActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(attributesType: PizzaDeliveryAttributes.self) { context in
// Create the Lock Screen user interface for your Live Activity.
// ...
}
}
}
要创建 ActivityConfiguration,您可以提供 ActivityAttributes,告知系统实时活动中显示的静态数据。使用ActivityAttributes还声明所需的自定义Activity.ContentState类型,该类型描述了您实时活动的动态数据。在上面的示例中,PizzaDeliveryAttributes描述了以下静态数据:订购的披萨数量和客户需要支付的金额。注意代码如何定义Activity.ContentState来封装动态数据:交付披萨的驱动程序的名称和预计交货时间。它定义了类型别名PizzaDeliveryStatus,使代码更具描述性和易于阅读性。
创建实时活动的用户界面
要创建 Live Activity 的用户界面,请在之前创建的小组件扩展中使用 SwiftUI。与小部件类似,您不提供实时活动用户界面的大小,而是让系统确定适当的尺寸。
如果活动高度超过160点,系统可能会截断实时活动。
以下代码显示PizzaDeliveryAttributes结构使用标准SwiftUI视图描述的信息:
struct PizzaDeliveryActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(attributesType: PizzaDeliveryAttributes.self) { context in
// Create the user interface for your Live Activity that appears on the Lock Screen.
VStack {
Text("\(context.attributes.numberOfPizzas) ordered for \(context.attributes.totalAmount).")
HStack {
Text("\(context.state.driverName) is on their way with your pizza!")
Text(context.state.estimatedDeliveryTime, style: .timer)
}
}.activityBackgroundTint(Color.cyan)
}
}
}
默认情况下,系统对文本使用默认的白色,对您的实时活动使用最适合用户锁定屏幕的背景颜色。要设置自定义色调颜色,请使用活动BackgroundTint(:)视图修饰符,如上例所示。要设置自定义背景色调颜色的半透明性,请使用不透明度(:)视图修饰符。或者,使用ZStack指定不透明的背景颜色:
// Create the Lock Screen user interface for your Live Activity.
ZStack {
Color.cyan
VStack {
Text("\(context.attributes.numberOfPizzas) ordered for \(context.attributes.totalAmount).")
HStack {
Text("\(context.state.driverName) is on their way with your pizza!")
Text(context.state.estimatedDeliveryTime, style: .timer)
}
}
}.activitySystemActionForegroundColor(Color.cyan)
此外,您可以自定义辅助按钮的颜色,允许用户使用activitySystemActionForegroundColor(_:)视图修饰符结束实时活动,如上例所示。
确保现场活动可用
现场活动仅在iPhone上提供。如果您的应用程序在多个平台上可用,并提供小部件扩展,请确保实时活动在运行时可用。此外,用户可以选择在iPhone上的设置应用程序中停用应用程序的实时活动。
要查看实时活动是否可用,以及用户是否允许您的应用程序使用实时活动:
使用 areActivitiesEnabled同步确定是否在应用程序中显示用户界面以开始实时活动。
通过使用 activityEnablementUpdates 流观察任何用户授权更改,接收有关用户授权的异步更新,并相应地响应它们。
每个应用程序可以启动多个实时活动,一台设备可以从多个应用程序运行实时活动。然而,用户的设备可能已经达到了活跃的实时活动极限。除了确保实时活动可用外,在开始、更新或结束实时活动时,请务必优雅地处理任何错误。
开始现场活动
当应用程序处于前台时,您可以使用request(attributes:contentState:pushType:)功能在应用程序的代码中开始实时活动。您创建的属性和内容状态作为参数,以提供实时活动中显示的初始值,并告诉系统哪些数据是动态的。如果您实现远程推送通知以更新实时活动,也请提供pushType参数。
以下代码示例从前面的示例中为披萨配送应用程序启动了一个新的实时活动:
let pizzaDeliveryAttributes = PizzaDeliveryAttributes(numberOfPizzas: 42, totalAmount:"$420,-")
// Estimated delivery time is one hour from now.
let initialContentState = PizzaDeliveryAttributes.PizzaDeliveryStatus(driverName: "Bill James", estimatedDeliveryTime: Date().addingTimeInterval(60 * 60))
do {
let deliveryActivity = try Activity.request(
attributes: pizzaDeliveryAttributes,
contentState: initialContentState,
pushType: nil)
print("Requested a pizza delivery Live Activity \(deliveryActivity.id)")
} catch (let error) {
print("Error requesting pizza delivery Live Activity \(error.localizedDescription)")
}
注意上面的片段如何将零传递给pushType参数,并在不使用远程推送通知来更新其内容的情况下开始实时活动。有关使用远程推送通知更新实时活动的更多信息,请参阅下面的“使用远程推送通知更新或结束实时活动”部分。
您只能在应用程序处于前台时从其启动实时活动。但是,您可以在应用程序在后台运行时更新或结束实时活动——例如,通过使用后台任务。
更新实时活动
当您从应用程序开始实时活动时,请使用您在开始实时活动时收到的健身记录对象上的更新(使用:)功能更新实时活动上显示的数据。要检索应用程序的活跃实时活动,请使用活动。
例如,披萨送货应用程序可以更新实时活动,显示送货状态,包括新的送货时间和新的驱动程序:
let updatedDeliveryStatus = PizzaDeliveryStatus(driverName: "Anne Johnson", estimatedDeliveryTime: Date().addingTimeInterval(60 * 60))
do {
try await deliveryActivity.update(using: updatedDeliveryStatus)
} catch(let error) {
print("Error updating activity \(error.localizedDescription)")
}
更新数据的大小不能超过4KB。
动画内容更新
当您定义实时活动的用户界面时,系统会忽略任何动画修饰符——例如withAnimation(::)和动画(_:value:)——而是使用系统的动画计时。然而,当实时活动的动态内容发生变化时,系统会执行一些动画。文本视图通过模糊的内容转换为内容更改添加动画效果,系统为图像和 SF 符号的内容转换添加动画效果。如果您根据内容或状态更改从用户界面中添加或删除视图,视图会淡入和淡出。使用以下视图过渡来配置这些内置过渡:不透明度、移动(边缘:)、滑动、推送(从:)或组合。此外,使用numericText(countsDown:)请求计时器文本的动画。
从您的应用程序内结束实时活动
请务必在相关任务或现场活动结束后结束现场活动。已结束的实时活动仍保留在锁定屏幕上,直到用户删除它或系统自动删除它。自动删除取决于您最后提供的解雇策略(使用:dismissalPolicy:)函数。
以下示例显示了披萨送货应用程序将如何结束实时活动,该活动显示披萨交付时订单的送货状态:
let updatedDeliveryStatus = PizzaDeliveryStatus(driverName: "Anne Johnson", estimatedDeliveryTime: Date())
do {
try await deliveryActivity.end(using: updatedDeliveryStatus, dismissalPolicy: .default)
} catch(let error) {
print("Error ending activity \(error.localizedDescription)")
}
上面的示例对解雇策略使用默认值。因此,实时活动在锁定屏幕上显示一段时间,以便用户浏览手机以查看最新信息。用户可以选择随时删除已结束的实时活动,或者系统会在四小时后自动删除它。
要立即从锁定屏幕中删除结束的实时活动,请使用立即。或者,使用 after(_:) 在四小时内指定日期。虽然您可以提供任何日期,但系统会在给定日期之后或从实时活动结束之日起四小时后删除结束的实时活动,以先到者为准。
用户可以随时从锁定屏幕中删除您的实时活动。这会结束您的实时活动,但它不会结束或取消开始活动的用户操作。例如,用户可以从锁定屏幕中删除披萨送货的实时活动,但这不会取消披萨订单。
通过远程推送通知更新或结束实时活动
除了从您的应用程序更新和结束实时活动外,还可以通过从服务器发送到Apple推送通知服务(APN)的远程推送通知来更新或结束实时活动。接收远程推送通知以更新实时活动类似于您使用它们显示应用程序通知的方式。您使用用户通知框架来请求使用通知的权限。您还必须设置远程通知服务器。此任务对于实时活动与在用户设备上显示为通知的远程推送通知相同。
如果您是远程推送通知的新手,请查看用户通知框架的文档。确保您阅读了使用APN注册应用程序和请求使用通知的权限,并按照用户通知文档所述计划实施远程通知服务器的时间。
要使用远程推送通知来更新您的实时活动,请首先将推送通知功能添加到您的应用程序中,如使用APN注册您的应用程序中所述。请注意,您不必为实时活动注册ForRemoteNotifications()注册远程推送通知。相反,请使用ActivityKit获取以下概述的推送令牌。
要通过推送通知更新或结束实时活动:
1、在应用程序中启动实时活动,并确保将pushType参数传递给request(attributes:contentState:pushType:)函数。
2、成功启动实时活动后,将活动的pushToken发送到推送通知服务器,并使用它向实时活动发送远程推送通知。
3、如果您尚未实现自己的远程推送通知服务器,请创建一个服务器应用程序,使用APN发送远程推送通知。
4、使用存储在服务器上的推送令牌向实时活动发送推送通知。您必须设置内容状态键的字段,以匹配您的自定义活动。内容状态类型,以确保系统可以解码JSON有效负载并更新实时活动。
5、要更新实时活动,请设置要更新的有效载荷事件密钥的值。要结束现场活动,请将其设置为结束。
6、使用pushTokenUpdates观察活动推送令牌的更改,将任何新的推送令牌发送到您的服务器,并使服务器上的旧令牌无效。
7、当您的实时活动结束时,使服务器上的推送令牌无效。
要测试模拟器中实时活动的远程推送通知,请使用配备Apple T2安全芯片的Mac机型或运行macOS 13或更高版本的搭载Apple芯片的Mac。
以下有效负载更新了披萨送货应用程序的司机姓名和交货时间。注意内容状态的内容如何与之前示例中自定义PizzaDeliveryStatus类型的属性匹配。
{
"aps": {
"timestamp": 1650998941,
"event": "update",
"content-state": {
"driverName": "Anne Johnson",
"estimatedDeliveryTime": 1659416400
}
}
}
跟踪更新
如上图所示,当您开始实时活动时,ActivityKit将返回一个活动对象。除了唯一标识每个活动的id属性外,活动还提供了观察内容状态、活动状态和推送令牌更新的序列。使用相应的顺序在应用程序中接收更新,保持应用程序和实时活动同步,并响应更改的数据:
要观察正在进行的实时活动的状态——例如,确定它是活跃的还是已经结束的——请使用 activityStateUpdates。
要观察实时活动动态内容的变化,请使用contentState。
要观察实时活动的推送令牌的变化,请使用pushTokenUpdates。
获取活动列表
您的应用程序可以启动多个实时活动。例如,体育应用程序可能允许用户为他们感兴趣的每个现场体育游戏开始现场活动。如果您的应用程序启动多个实时活动,请使用活动更新功能获取应用程序的所有正在进行的活动,以确保应用程序的数据与ActivityKit跟踪的活动实时活动同步。
以下片段显示了披萨配送应用程序如何检索正在进行的活动列表:
// Fetch all ongoing pizza delivery activities.
let activityStream = Activity.activityUpdates()
for await activity in activityStream {
print("Pizza delivery details: \(activity.description)")
}
获取所有活动的另一个用例是维护正在进行的实时活动,并确保您不会使任何活动运行的时间超过需要。例如,系统可能会停止您的应用程序,或者您的应用程序可能会在实时活动处于活动状态时崩溃。当应用程序下次启动时,检查是否有任何活动仍在活动,更新应用程序存储的实时活动数据,并结束任何不再相关的实时活动。