WWDC 2022 Keynote 中苹果给我们介绍了 iOS 16 中一个比较亮眼的更新:Live Activity(实时活动),开发者可以在锁屏页面上放置一个可以“实时”更新的 Widget,比如外卖或者打车应用,在开启实时活动之后我们可以在锁屏页上实时看到外卖小哥/司机与我们的距离及预计到达时间。但是这一 API 及对应功能并没有第一时间放出,而是随着 iOS 16 Beta4 一起放出:【实时活动现已推出 Beta 版本】[1]。
这篇文章主要是对官方 API 做一个简单提炼,并梳理下一些需要注意的点。
Live Activity 后续均使用实时活动来翻译。
设备及开发环境:iPhone 12 iOS 16 Beta 4、Xcode 14 Beta 4、macOS 12.4
3. 没有付费账号,还没尝试使用远程推送来更新/停止实时活动; 4. 实时活动锁屏 UI 必须使用 SwiftUI,相对来说比较简单,实时活动组件的高度不能超过 220px(原文是 220 pixels,但实际测试发现是 220pt),否则系统会自动裁切; 5. 基于 Widget,但刷新机制不一样,widget 是根据时间线来更新,而实时活动则不受这个控制,可以使用远程推送或者宿主应用代码来更新,暂时没看到更新频率相关限制; 6. 因为是基于 Widget,所以还是可以给控件绑定不同 deep link,使其可以跳转到对应页面; 7. 整体上来说实时活动的适配比较容易,重要的还是结合 App 的实际场景合理运用应该能取得不错效果,后续应该会有很多有创意的 idea 出现,可以期待一波。
写了个 Demo,模拟地铁到站预估时间的场景,代码放在 GitHub/iOS16LiveActivityDemo[2] 上了,有啥疑问可以留言或者提 issue。
以下内容主要对文档做个翻译.
ActivityKit
来更新实时活动,也可以在实时活动的 Widget 中接收远程推送来更新,下面会具体说到;如果应用之前已经有 Widget,那么可以在已有的 Widget Extension 中添加实时活动的相关实现;如果之前没有的话可以新建一个。值得注意的是:实时活动并不是 widget,他们的更新机制有较大区别。上面也有提到,实时活动是通过应用内的 ActivityKit 或者远程推送来更新的,而 widget 则依赖系统的 timeline 机制。
下面是适配的相关步骤:
2. 在 Info.plist
文件中添加一个键值对,key 为 NSSupportsLiveActivities
,value 为 YES
;
3. 在代码里定义一组 ActivityAttributes
以及 Activity.ContentState
,后续会用它们来开始、更新及结束实时活动;
4. 创建 Widget 并返回一个 ActivityConfiguration
;
5. 添加开始、更新、结束实时活动的相关代码,并设计对应的 UI 样式;
6. 运行查看效果。
import ActivityKit
import SwiftUI
import WidgetKit
// 示例代码,展示披萨配送的实时活动
// 继承 ActivityAttributes ,定义自定义属性用于widget UI展示
// Attributes 用来定义不可变的静态数据,比如这里的披萨数量和花费
struct PizzaDeliveryAttributes: ActivityAttributes {
public typealias PizzaDeliveryStatus = ContentState
// 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
// 根据数据创建锁屏widget UI,系统默认情况下文字颜色使用白色,然后使用最适合锁屏页的背景色;也可以像下面这样使用 activityBackgroundTint(_:) 来设置自定义颜色
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)
// 或者像这样使用ZStack的方式在最底下放置背景视图
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)
}
}
}
值得注意的是实时活动 Widget 的最大高度不能超过 220px(原文是 220 pixels,但实际测试发现是 220pt),否则系统会自动裁剪。
由于实时活动仅在 iPhone 上生效,同时用户也可以在设置中手动关闭某个应用的实时活动,所以在使用前最好要做一个检测。
areActivitiesEnabled
来同步判断开始实时活动前是否显示锁屏 UI;activityEnablementUpdates
来检测用户授权状态的变更。需要注意的是:每个应用可以开启若干个实时活动,同时系统也能展示多个 app 的实时活动;所以我们在启动、更新、结束实时活动时,也要考虑出错的情况以提供更好的用户体验。
应用在前台的时候,我们可以使用 request(attributes:contentState:pushType:)
方法来启动实时活动,对应参数 attributes 作为实时活动的初始值,contentState
作为动态变化的数据。如果应用实现了远程推送,也可以提供 pushType
参数,后面远程推送部分会讲到。
// 启动实时活动示例代码
// 提供初始化值
let pizzaDeliveryAttributes = PizzaDeliveryAttributes(numberOfPizzas: 42, totalAmount:"$420,-")
// 提供动态变化数据,预估配送到达时间为1小时后
let initialContentState = PizzaDeliveryAttributes.PizzaDeliveryStatus(driverName: "Bill James", estimatedDeliveryTime: Date().addingTimeInterval(60 * 60))
// 启动实时活动,这里 pushType 暂时置 nil
do {
let deliveryActivity = try Activity<PizzaDeliveryAttributes>.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)")
}
启动实时活动后我们可以得到一个 Activity
实例,接着我们可以调用该实例 update(using:)
方法来更新实时活动。我们也可以通过 Activity。activities
方法来获取当前所有的实时活动实例。
更新一个已结束的实时活动会被忽略。
let updatedDeliveryStatus = PizzaDeliveryStatus(driverName: "Anne Johnson", estimatedDeliveryTime: Date().addingTimeInterval(60 * 60))
do {
// deliveryActivity是上面启动时拿到的Activity实例
// 更新的数据大小不能超过4KB
try await deliveryActivity.update(using: updatedDeliveryStatus)
} catch(let error) {
print("Error updating activity \(error.localizedDescription)")
}
系统会忽略实时活动 widget 的所有动画修饰符,比如withAnimation(_:_:)
、animation(_:value:)
。系统会自动给动态变化的内容添加动画,比如会给 Text 添加模糊的过渡效果,给 Image 以及 SF Symbol 添加过渡动画。如果更新过程中有视图的添加或移除,系统也会给他们加上淡入淡出的过渡动画。
我们也可以使用系统内置的过渡动画:opacity
、move(edge:)
、slide
、push(from:)
或者将它们组合使用,对于那种计时的 Text,我们也可以使用 numericText(countsDown:)
修饰符来做文本变化动画。
在关联的事件/任务结束时,我们也应该结束对应的实时活动。上面也有提到结束后的实时活动在用户手动移除前还会在锁屏页上停留 4 小时。当然我们也可以使用 end(using:dismissalPolicy:)
方法指定实时活动结束后的移除策略。
let updatedDeliveryStatus = PizzaDeliveryStatus(driverName: "Anne Johnson", estimatedDeliveryTime: Date())
do {
// 指定移除策略为默认,即用户手动移除前停留4小时
// 还有 immediate 即立即移除,以及可以指定一个移除的时间 after(Date)
try await deliveryActivity.end(using: updatedDeliveryStatus, dismissalPolicy: .default)
} catch(let error) {
print("Error ending activity \(error.localizedDescription)")
}
需要注意的是,用户可以在任意时间将实时活动从锁屏页面移除,该操作相应的也会结束对应的实时活动,但是他不会取消用户在启动实时活动时的一些行为。比如上面披萨配送示例里,尽管用户可以移除披萨配送信息的实时活动,但不代表取消了对应的披萨订单。
除了上述的更新和结束的方式,我们还可以通过推送通知来实现,具体实现流程和逻辑其实普通的推送通知区别不大,这里不做赘述。有一点不同的是:实时活动不需要使用 registerForRemoteNotifications()
来注册推送通知,我们使用 ActivityKit 来获取推送 token。具体流程如下:
.token
,或者不传该参数(参数默认值就为 .token
);pushToken
发送给服务端,后续使用该 token
来给对应实时活动发送推送通知;content-state
字段的值和代码里的 Activity.ContentState
匹配上,这样系统才能解码对应 JSON 内容来更新实时活动;pushTokenUpdates
监听实时活动实例的 pushToken 变化,并将新值发送给服务端同时废弃旧值,模拟器上测试实时活动的远程推送需要使用 T2 或 M 系列芯片的 Mac,并且要求系统 >=macOS 13。
如果你不清楚自己电脑是否是 T2,可以通过如图方式确认,按住 Option 键,并点击左上角 查看 系统信息->控制器即可
也可以使用直接在下方列表查找,基本上 18 年后的都支持。
下面是一个对应上方披萨配送示例的 push payload 数据
{
"aps": {
"timestamp": 1650998941,
"event": "update",
// 这里和上述 PizzaDeliveryAttributes.ContentState 里的字段一一对应
"content-state": {
"driverName": "Anne Johnson",
"estimatedDeliveryTime": 1659416400
}
}
}
Activity 这个类除了拥有一个 id 的唯一标识外,还提供了一系列的状态变化的监听,比如内容状态、活动状态以及 push token 的变更。我们可以使用对应的监听来更新应用,让实时活动与应用保持同步。
activityStateUpdates
来监听实时活动的状态,判断是否已结束;contentState
来监听实时活动的动态内容变化;pushTokenUpdates
来监听实时活动的 push token 变化。一个应用可以同时开启多个实时活动,比如用户可以同时关注多个球赛直播,我们可以使用 activityUpdates
来获取当前正在进行中的实时活动。在某些场景下我们可能也会用到这个方法来获取当前进行中的实时活动,比如应用闪退后再次打开应用,如果想要结束或更新某些实时活动,就可以通过这个方法来获取到所有的实时活动。
// Fetch all ongoing pizza delivery activities.
let activityStream = Activity<PizzaDeliveryAttributes>.activityUpdates() for await activity in activityStream { print("Pizza delivery details: \(activity.description)") }
[1]【实时活动现已推出 Beta 版本】: https://developer.apple.com/cn/news/?id=hi37aek8
[2]GitHub/iOS16LiveActivityDemo: https://github.com/wang9262/iOS16LiveActivityDemo
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/aKD-WBYHsepg96zOC378cg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。