1. 前语
实时活动是iOS 16.1及以上版别中新增的功用,它允许应用在锁屏界面显现实时数据,能够协助用户实时检查当时订单的进展,而无需解锁手机。用户在货拉拉APP上下单后,能够将手机放置一旁,开端其他作业。当用户想要查询订单状况时,只需从确定屏幕或灵动岛上轻松操作即可。实时活动的出现不只省去了用户解锁手机的过程,更为用户节省了时刻和精力。现在货拉拉APP适配“灵动岛”的最新6.7.68版别已正式上线,欢迎大家晋级体会。在适配过程中,货拉拉App也踩过很多“坑”,在此汇总为实战经验分享给大家。
2. Live Activity&灵动岛的介绍
Live Activity的完结需求运用Apple的ActivityKit框架。经过运用ActivityKit,开发者能够轻松地创立一个Live Activity,这是一个动态的、实时更新的活动,能够在用户的设备上显现各种信息。此外,ActivityKit还供给了推送告诉的功用,开发者能够经过服务器向用户的设备发送更新;这样,即使应用程序没有运转,用户也能够接收到最新的信息。
灵动岛是Live Activity的一种展现方法,灵动岛有三种展现方法:Compact紧凑、Minimal最小化,Expanded扩展。开发时有必要完结这三种方法,以确保灵动岛在不同的场景下都能正常展现。
一起还需求完结锁屏下的实时活动UI,设备处于锁屏状况下,也能检查实时更新的内容。以上功用的完结,都是运用WidgetKit和SwiftUI完结开发。
2.1 技能难点及战略
实时活动,主要是APP在后台时,自动更新告诉栏和灵动岛的数据,为用户展现最新实时订单状况。怎么及时改写实时活动的数据,是一个重点、难点。
更新方法有3种:
- 经过APP内订单状况的改变改写实时活动和灵动岛。此办法开发量小,可是APP退到后台30s后或许进程杀掉,会停止数据的更新。
- 让APP装备支撑后台运转形式,经过本地现有的订单状况改变逻辑,在后台发起网络恳求,获取订单的数据后改写实时活动。此办法开发量小,但求主App进程有必要存在,进程一旦杀掉就无法更新。
- 经过接受长途推送告诉来更新实时活动。此办法需求后端配合,此方法比较灵敏,无需App进程存在,数据更新及时。也是业界常见的方案。
经过对数据改写的三种方案进行评价后,选择了用户体会最佳的第三种方法。经过后端产生push,端上接受push数据来更新实时活动。
3. Live Activity&灵动岛的实践
3.1 完结方案流程图
完结流程图:
3.2 完结代码
创立Live Activities的预备:
- Xcode需求14.1以上版别
- 在主工程的 Info.plist 文件中增加一个键值对,key 为 NSSupportsLiveActivities,value 为 YES
- 运用ActivityKit在Widget Extension 中创立一个Live Activity
需求完结锁屏状况下UI、灵动岛长按打开的UI、灵动岛单个UI、多个实时活动时的minimalUI
import SwiftUI
import WidgetKit
@main
struct TestWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TestAttributes.self) { context in
// 锁屏状况下的UI
} dynamicIsland: { context in
DynamicIsland {
//灵动岛打开后的UI
} compactLeading: {
// 未被打开左边UI
} compactTrailing: {
// 未被打开右边UI
} minimal: {
// 多任务时,右边的一个圆圈区域
}
.keylineTint(.cyan)
}
}
}
灵动岛主要分为Start
、Update
、End
三种状况,可由ActivityKit
与长途推送
操控其状况。
敞开Live Activity:
let state = TestAttributes.ContentState()
let attri = TestAttributes(value: 100)
do {
let current = try Activity.request(attributes: attri, contentState: state, pushType: .token)
Task {
for await state in current.contentStateUpdates {
//监听state状况
}
}
Task {
for await state in current.activityStateUpdates {
//监听activity状况
}
}
} catch(let error) {
}
更新Live Activity:
Task {
guard let current = Activity<TestAttributes>.activities.first else {
return
}
let state = TestAttributes.ContentState(value: 88)
await current.update(using: state)
}
完毕Live Activity:
Task {
for activity in Activity<TestAttributes>.activities {
await activity.end(dismissalPolicy: .immediate)
}
}
4. 运用ActivityKit推送告诉
ActivityKit供给了接收推送令牌的功用,咱们能够运用这个令牌来经过ActivityKit推送告诉从咱们的服务器向Apple Push Notification service (APNs)发送更新。
推送更新Live Activity的预备:
-
在开发者后台装备生成p8证书,替换原来的p12证书
-
经过
pushTokenUpdates
获取推送令牌PushToken
-
向后端注册
PushToken
代码展现:
//取得PushToken
for await tokenData in current.pushTokenUpdates {
let mytoken = tokenData.map { String(format: "%02x", $0) }.joined()
//向后端注册
registerActivityToken(mytoken)
}
4.1 模拟器push验证测验
环境要求:
Xcode >= 14.1
MacOS >= 13.0
预备作业:
- 经过
pushTokenUpdates
获取推送需求的token - 依据开发者TeamID、p8证书本地途径、BuidleID等进行脚本装备
脚本示例:
export TEAM_ID=YOUR_TEAM_ID
export TOKEN_KEY_FILE_NAME=YOUR_AUTHKEY_FILE.p8
export AUTH_KEY_ID=YOUR_AUTHKEY_ID
export DEVICE_TOKEN=YOUR_PUSH_TOKEN
export APNS_HOST_NAME=api.sandbox.push.apple.com
export JWT_ISSUE_TIME=$(date +%s)
export JWT_HEADER=$(printf '{ "alg": "ES256", "kid": "%s" }' "${AUTH_KEY_ID}" | openssl base64 -e -A | tr -- '+/' '-_' | tr -d =)
export JWT_CLAIMS=$(printf '{ "iss": "%s", "iat": %d }' "${TEAM_ID}" "${JWT_ISSUE_TIME}" | openssl base64 -e -A | tr -- '+/' '-_' | tr -d =)
export JWT_HEADER_CLAIMS="${JWT_HEADER}.${JWT_CLAIMS}"
export JWT_SIGNED_HEADER_CLAIMS=$(printf "${JWT_HEADER_CLAIMS}" | openssl dgst -binary -sha256 -sign "${TOKEN_KEY_FILE_NAME}" | openssl base64 -e -A | tr -- '+/' '-_' | tr -d =)
export AUTHENTICATION_TOKEN="${JWT_HEADER}.${JWT_CLAIMS}.${JWT_SIGNED_HEADER_CLAIMS}"
curl -v
--header "apns-topic:YOUR_BUNDLE_ID.push-type.liveactivity"
--header "apns-push-type:liveactivity"
--header "authorization: bearer $AUTHENTICATION_TOKEN"
--data
'{"Simulator Target Bundle": "YOUR_BUNDLE_ID",
"aps": {
"timestamp":1689648272,
"dismissal-date":0,
"event": "update",
"sound":"default",
"content-state": {
"title": "等候付款",
"content": "请赶快完结下单"
}
}}'
--http2
https://${APNS_HOST_NAME}/3/device/$DEVICE_TOKEN
其间:
apns-topic
:固定为{BundleId}.push-type.liveactivity
apns-push-type
:固定为liveactivity
Simulator Target Bundle
:模拟器推送,设置为对应APP的BundleId
timestamp
:表明推送告诉的发送时刻,假如timestamp
字段的值与当时时刻相差太大,可能会收不到推送。
event
:可填入update、end,对应Live Activity的更新与完毕。
dismissal-date
:当event为end时有用,表明完毕后从锁屏上移除Live Activity的时刻。假如推送内容不包括”dismissal-date”,默认完毕后4小时后消失,但内容不会再产生更新。假如期望Live Activity完毕后当即从锁屏上移除它,可为”dismissal-date”供给一个曩昔的日期。
content-state
:对应灵动岛的Activity.ContentState
;假如push中content-state
的字段和Attributes比较:
-
字段过多,多余的字段可能会被疏忽,不会导致解析失利
-
字段短少,会在解析push告诉时出现问题过错。过错表现为:实时活动会有蒙层,并展现loading菊花UI。
演示:
5. 踩坑记录
-
在模拟器上无法获取到pushToken,无法进行推送模拟?
检查电脑的体系版别号,需求13.0以上
-
更新实时活动时,页面显现加载loadingUI,为什么?
核对push字段和
Activity.ContentState
的字段是否完全一致,字段少了会解析失利 -
在16.1体系上,无法展现实时活动,其他更高体系能展现?
检查Widget里边iOS体系版别号的装备,设置为想要支撑的最低版别
-
dismissal-date
设置为10分钟后才消失,为什么Dynamic Island灵动岛当即消失了?Dynamic Island的显现逻辑可能会愈加复杂,假如push的event=end,Dynamic Island灵动岛会当即消失。期望一起消失,能够在指定时刻再发end,
dismissal-date
设置为曩昔时刻,锁屏UI和Dynamic Island灵动岛会一起消失。 -
推送不期望打扰用户,静默推送,不需求轰动和自动弹出,怎么设置?
将”content-available”设置为1,”sound” 设置为: “”
"aps" = {
"content-available" : 1,
"sound" : ""
}
-
用户体系是深色形式时,怎么适配?
能够运用
@Environment(.colorScheme)
属性包装器来获取当时设备的颜色形式。会返回一个ColorScheme
枚举,它能够是.light
或.dark
。在依据详细的场景进行UI适配
struct ContentView: View {
@Environment(.colorScheme) var colorScheme
var body: some View {
VStack {
if colorScheme == .dark {
Text("深夜形式")
.foregroundColor(.white)
.background(Color.black)
} else {
Text("日间形式")
.foregroundColor(.(.black)
.background(Color.white)
}
}
}
}
5.1 场景约束及建议
- 官方文档提示实时活动最多持续8小时,8小时后数据无法改写,12小时后会强制消失。因而8小时后的数据不精确
- 实时活动的卡片上制止定位以及网络恳求,数据需求小于4KB,不能展现特别担任巨大的数据
- 同场景多卡片因为款式趋同且折叠,不建议一起创立多卡片。用户多次下单时,建议只处理第一个订单
6. 用户APP上线作用
用户端iOS APP灵动岛上线后的部分场景截图:
7. 总结
灵动岛功用自上线以来,经过咱们的数据统计,用户实时活动运用率高达75%以上。这一数据的背后,是灵动岛强大的功用和优异的用户体会。用户能够在锁屏页直接检查订单状况,无需繁琐的操作过程,大大提升了用户体会。这种快捷性,使得灵动岛在用户中的接受度较高。
咱们的方案不只能够应用于当时的事务场景,后续还方案扩展到营销活动,定制化告诉消息等多种事务场景。这种扩展性,使得灵动岛能够更好地满足不同用户的需求,丰厚产品运营战略。
咱们期望经过分享开发过程中遇到的问题和解决方案,能够协助到更多的人。假如你有任何问题或许想法,欢迎在评论区留言。等待咱们在技能的道路上再次相遇。
总的来说,灵动岛以其高效、快捷、灵敏的特性,赢得了用户的广泛好评。咱们将继续尽力,为用户供给更优质的服务,为产品的发展注入更多的活力。