Live Activity,深入了解:实时调度功能开发者

你好!我叫 Seong-Hoon Kim,是 Trace 团队的 iOS 产品工程师。
如今,大多数应用程序都会通过推送通知轰炸用户以吸引他们的注意力。
但我们都知道。通知很容易被忽略,隐藏在滚动条中,并且在您需要时无法发挥作用。
相反,在锁定屏幕上实时改变配送状态的 Live Activity 体验(例如 Coupang Eats 或 Baedal Minjok)自然会吸引用户的注意力。
您无需打开应用程序即可立即查看您所在的位置以及还剩多少,这种流程使用户体验更加无缝。
事实上,苹果还推出了 Live Activity 作为一项优化功能,用于提供“不断变化的信息”,例如日程安排、锻炼、交付、运动和计时器。
Trace Discord 社区中的一位用户也提出了类似的请求。
- “我想一目了然地看到我今天需要做什么,而无需打开应用程序。”
- “我希望能在锁定屏幕上看到当前的日程安排。”
因此,Trace 开始认真尝试,看看如何通过 Live Activity 来解决此请求。
在这篇文章中,我将尝试一步步整理Trace在使用Live Activity实现实时日程体验的过程中遇到了哪些问题以及如何解决。



APN
在 iOS 上,所有推送均通过 Apple 推送通知服务 (APN) 传送。 APN发送的推送类型大致可以分为三种类型。
- 一般通知(警报推送)
- 用户可见的横幅/声音/振动通知
- 静默推送(后台推送)
- 用于短暂唤醒应用程序并执行后台任务,而不出现在屏幕上。
- ActivityKit Push(推送实时活动更新)
- 用于直接更新实时活动状态的专用类型。
当我第一次开始添加实时活动时,并不清楚 ActivityKit Push 是如何运作的以及它需要什么数据结构。
所以很自然地,我从静默推送开始,我已经经常使用它并且熟悉后台更新。
“难道不能安静地唤醒应用程序并更新实时活动吗?”
这是我能想到的最简单的方法。
但在尝试了几次之后,我意识到一件重要的事情。
Live Activity并不是一个简单发送“更新请求”的结构,而是必须通过推送的方式发送当时需要显示在屏幕上的整个数据(contentState)。
换句话说,服务器必须直接计算并发送“当前正在进行哪些计划以及还剩多少”,而 Silent Push 基础设施很难可靠地满足这一需求。
自动更新实时活动
核心思想很简单。
“无需唤醒应用程序,让服务器计算 Live Activity 的状态并将其作为推送发送。”
由于 Trace 使用 Firebase 而不是单独的服务器基础设施,
只需使用 Firebase Functions + Firestore 即可相对简单地实现此结构。
要“像实时一样”更新您的实时活动,您只需要做两件事:
- 计算当前正在进行的计划的地方
- 将结果直接推送到实时活动的途径
📌 整个数据流
iOS App
└─ (토큰 + 일정 저장)
↓
Firestore
↓
Firebase Functions
└─ 현재 이벤트 계산
↓
APNs – ActivityKit Push
└─ contentState 전송
↓
Live Activity
└─ UI 자동 업데이트
1)iOS
- 获取创建Live Activity时自动发放的liveActivityToken
- 将基于时间的日历列表保存到 Firestore
仅凭这些信息,服务器就可以知道“应在哪些设备上更新实时活动以及按什么计划更新”。
2) Firebase 功能
函数每分钟运行一次并执行以下操作:
- 查看 Firestore 中当前有效的设备列表
- 根据当前时间在各设备的事件中选择“立即显示的事件”
- 将事件放入 contentState 并将 ActivityKit Push 发送到 liveActivityToken
// ActivityKit Push 전송
const notification = new apn.Notification();
notification.topic = "com.example.app.push-type.liveactivity";
notification.pushType = "liveactivity";
notification.event = "update";
notification.contentState = {
event: currentEventData, // 지금 보여줄 이벤트
timestamp: Date.now(),
status: "Active"
};
await apnsProvider.send(notification, liveActivityToken);
3)操作视频
这显示了整个流程在实践中是如何工作的:服务器将 contentState 传递给 ActivityKit Push,Live Activity 立即反映它。

按下即可开始
到目前为止,Live Activity 结构有一个前提。
实时活动的特点是,它们仅在用户直接进入应用程序并触发它时启动。
但我们想更进一步。
“即使不打开应用程序,Live Activity 也无法自动启动吗?”
让这一切成为可能的函数是 iOS 17.2 中引入的 PushToStartToken。 PushToStartToken 允许您在服务器上远程启动实时活动。
这意味着即使用户没有打开应用程序:
- 当重要活动即将开始时
- 就在任务开始之前
- 即使用户白天根本没有打开应用程序。
您可以创建一种在锁定屏幕上自动显示实时活动的体验。
作为参考,Apple 的文档解释说,即使不创建 Activity,您也可以从 PushToStartTokenUpdates 接收令牌。然而,在 iOS 17.x 上,这种行为非常不稳定。有报道称,有几位开发者遇到了同样的问题,据悉苹果也意识到了这个问题。
因此,Trace 采用了一种保护令牌的方法,即通过简单地创建一个“虚拟活动”来保护令牌,该虚拟活动在运行应用程序时对用户来说是不可见的。 (据说这个行为在 iOS 18 中得到了改进。)
📌 整个数据流
iOS App
└─ (pushToStartToken + 시작 시각 저장)
↓
Firestore
↓
Firebase Functions
└─ 시작 시점 도달 여부 확인
↓
APNs – Push to Start
└─ attributes + contentState 전송
↓
Live Activity
└─ 앱을 열지 않아도 자동 생성
Push to Start 一旦你获得了代币,整体结构就非常简单了。
1)iOS
- 运行应用程序时通过虚拟活动推送启动令牌收购
- 保存 pushToStartToken 并将开始时间安排到 Firestore
2) Firebase 功能
函数每分钟运行一次并执行以下操作:
- 检查“现在是开始实时活动的时间吗?”
- 当到达该点时,APNs推送启动令牌发送推送启动请求至 。此时,Live Activity 中最初显示的属性和 contentState 也会被传递。
// Push to Start - Activity 생성용 Push
notification.event = "start"; // "update"가 아닌 "start"
notification.attributes = { // 생성 시에만 필요
startTime: Date.now()
};
notification.contentState = {
title: "러닝 30분",
eventDate: 1733458200,
status: "active"
};
换句话说,就像更新推送一样,服务器计算出所有要显示在屏幕上的数据并一次性发送出去。
3)操作视频
您可以查看服务器使用pushToStartToken远程创建Live Activity并发送初始显示的属性和contentState以使其自动显示在锁定屏幕上的过程。

完成
自从引入Live Activity以来,Trace的关键指标也发生了变化。
尤其是Day0→Day1留存率提升了10%左右,初步体验有了明显的提升。
用户给出的反馈称,“无需打开应用程序即可直接从锁定屏幕查看内容,非常方便”,以及“我喜欢能够在 Live Activity 中立即完成待办任务。”
Trace将继续深入探索AI和iOS生态系统的能力,创造自然渗透到用户日常生活中的体验。
构建这个 Live Activity 的过程对于团队来说是一个非常有趣的挑战,也是一次我个人获得很多见解的经历。希望这篇文章能给正在思考类似问题的人一些帮助或参考。
谢谢你
参考资料