1.背景
對(duì)于IoT行業(yè),iPhone14 Pro及Max的靈動(dòng)島可以用于展示設(shè)備的各種動(dòng)作和計(jì)時(shí),在iPhone鎖定屏幕和動(dòng)態(tài)島上顯示App的最新數(shù)據(jù),這讓人們可以一目了然地看到實(shí)時(shí)信息。
2.名詞解釋
詞匯 | 含義 | |
---|---|---|
1 | Widget | 組件,iOS 14 重磅推出的新功能,使得用戶(hù)可以在主屏幕添加小組件,快速瀏覽 app 提供的重要信息 |
2 | Dynamic Island | 靈動(dòng)島,iOS16.1推出的針對(duì)iphone14 pro系列機(jī)型的聯(lián)動(dòng)功能,快速瀏覽 app 提供的重要信息 |
3 | Live Activity | 實(shí)時(shí)活動(dòng),展示在靈動(dòng)島和鎖屏界面的信息活動(dòng) |
Dynamic Island是ActivitiesKit的一部分,而它是Widget Extension的一部分。
3.配置條件
- 需要至少Xcode 14.1 Beta版及iOS16.1才能使用ActivityKit 框架,iOS16.1是第一個(gè)開(kāi)放ActivityKit的正式版本。
- 在主工程的info.plist中加入鍵值NSSupportsLiveActivities ,并將其布爾值設(shè)置為YES
-
因?yàn)殪`動(dòng)島是屬于小組件的一部分,所以項(xiàng)目中如果沒(méi)有小組件的話(huà)要先創(chuàng)建小組件。有小組件的話(huà)可以添加些代碼即可適配。
16645173953743.png
4.詳細(xì)介紹
4.1 布局
上圖依次是
- 緊湊視圖:分為leading和traling視圖,只有一個(gè)live activity事件時(shí)
- 最小視圖:兩個(gè)及以上live activity事件時(shí),左右顯示的都是minmal視圖
- 擴(kuò)展視圖:分為leading、traling、center、bottom
- 鎖屏視圖:鎖屏的時(shí)候會(huì)展示在鎖屏下方
var body: some WidgetConfiguration {
ActivityConfiguration(for: GroceryDeliveryAppAttributes.self) { context in
LockScreenView(context: context) //鎖屏視圖
} dynamicIsland: { context in
DynamicIsland {
//擴(kuò)展視圖
DynamicIslandExpandedRegion(.leading) {
dynamicIslandExpandedLeadingView(context: context)
}
DynamicIslandExpandedRegion(.trailing) {
dynamicIslandExpandedTrailingView(context: context)
}
DynamicIslandExpandedRegion(.center) {
dynamicIslandExpandedCenterView(context: context)
}
DynamicIslandExpandedRegion(.bottom) {
dynamicIslandExpandedBottomView(context: context)
}
} compactLeading: {//單個(gè)前視圖
compactLeadingView(context: context)
} compactTrailing: {//單個(gè)后視圖
compactTrailingView(context: context)
} minimal: { //最小化視圖
minimalView(context: context)
}
.keylineTint(.cyan) //靈動(dòng)島邊緣顏色
}
}
當(dāng)只有一個(gè)live activity事件時(shí)
因?yàn)檫@個(gè)靈動(dòng)島左右是對(duì)稱(chēng)的,左邊布局的拉寬會(huì)帶動(dòng)右邊也拉寬,進(jìn)而占據(jù)時(shí)間、信號(hào)、電量等圖標(biāo)。而用戶(hù)肯定會(huì)對(duì)這種占據(jù)過(guò)多空間的live activity深?lèi)和唇^,可能會(huì)立馬干掉。
靈動(dòng)島:只能在App處于前臺(tái)時(shí)從其啟動(dòng)實(shí)時(shí)活動(dòng)。目前最多只能展示兩個(gè)live activity,后來(lái)的不會(huì)顯示,除非用戶(hù)上下滑動(dòng)移除了當(dāng)前顯示的live activity或者在鎖屏界面移除或者代碼調(diào)用移除,后來(lái)的才會(huì)依次展示在上面,因?yàn)橛玫哪M器調(diào)研,不知道系統(tǒng)的打電話(huà)功能是否優(yōu)先級(jí)最高。注意這里的上下滑動(dòng)只是隱藏了當(dāng)前的live activity,他其實(shí)還在,鎖屏的時(shí)候依然會(huì)顯示。
鎖屏: 沒(méi)有靈動(dòng)島的設(shè)備同樣會(huì)展示鎖屏視圖,高度最多顯示160,其余會(huì)被系統(tǒng)裁剪掉。移除鎖屏狀態(tài)的視圖,就相當(dāng)于停止了live activity。
4.2 更新策略
每個(gè)“Live Activity”都在自己的沙盒中運(yùn)行,雖然它是依托于小組件但是與小組件的時(shí)間線(xiàn)timeline更新不同,它無(wú)法訪問(wèn)網(wǎng)絡(luò)或接收位置更新。要更新活動(dòng)現(xiàn)場(chǎng)活動(dòng)的動(dòng)態(tài)數(shù)據(jù),請(qǐng)使用應(yīng)用程序中的ActivityKit框架,或允許您的現(xiàn)場(chǎng)活動(dòng)接收遠(yuǎn)程推送通知。 ActivityKit 更新后和遠(yuǎn)程推送通知更新的動(dòng)態(tài)數(shù)據(jù)大小不得超過(guò) 4KB。
4.2.1 live activity更新
-
手動(dòng)代碼更新:16645187695082.png
推送通知更新:需要和服務(wù)端配置推送類(lèi)型pushType,詳情可見(jiàn)相關(guān)鏈接。如果通知被用戶(hù)關(guān)閉了權(quán)限,應(yīng)該只能采用手動(dòng)更新來(lái)保證吧。
4.2.2 對(duì)比widget更新
Widget 的刷新方式是很特別的,相當(dāng)?shù)目酥啤R韵抡怨俜轿臋n:
Updating every minute is far too aggressive. Widgets have a limited number of updates and if you were to try to update every minute, you'll quickly run out of updates. While debugging with Xcode these limits are not imposed, but if you're running your app outside of Xcode you'd see the behavior you're describing where your widget would stop updating.
意思是一個(gè)組件一天會(huì)有一定限制的刷新頻次數(shù),超過(guò)這個(gè)次數(shù),系統(tǒng)將不保證刷新是否成功。
WidgetKit通過(guò)以下兩種方式之一要求時(shí)間線(xiàn)條目:
- 單個(gè)即時(shí)快照,表示小部件的當(dāng)前狀態(tài)。
- 條目數(shù)組,包括當(dāng)前時(shí)刻,以及(如果已知)小部件狀態(tài)將更改的任何未來(lái)日期。
其實(shí)就是Widget引入了timeline時(shí)間線(xiàn)的概念,如果已知這個(gè)小組件現(xiàn)在及未來(lái)一段時(shí)間的狀態(tài),就可以在getTimeline提供內(nèi)容展示的entry組。并且更新策略選.atEnd就是提供的entry都展示完再去請(qǐng)求新的。
WidgetKit 在一個(gè)單獨(dú)的進(jìn)程中呈現(xiàn)視圖。因此,即使小部件在屏幕上,小部件擴(kuò)展也不會(huì)一直處于活動(dòng)狀態(tài)。盡管小部件并不總是處于活動(dòng)狀態(tài),但可以通過(guò)多種方式使其內(nèi)容保持最新。
被動(dòng):
- WidgetKit 有時(shí)會(huì)重新加載小部件以幫助保持其內(nèi)容最新。一些常見(jiàn)的場(chǎng)景包括:
- 如果小部件位于用戶(hù)很少訪問(wèn)的主屏幕頁(yè)面上,則 WidgetKit 可能會(huì)降低該小部件的重新加載頻率。稍后,當(dāng)用戶(hù)查看頁(yè)面時(shí),WidgetKit 可能會(huì)在小部件可見(jiàn)時(shí)重新加載它。
- 對(duì)于使用位置服務(wù)的小部件,WidgetKit 會(huì)在位置發(fā)生重大變化后重新加載它們。
主動(dòng):
主程序調(diào)用的主動(dòng)刷新:
WidgetCenter.shared.reloadTimelines(ofKind: "com.mygame.character-detail")
官方示例:
如果已知一個(gè)人健康狀態(tài)當(dāng)前為25%,且每小時(shí)固定增長(zhǎng)25%,則可以安排一個(gè)如下計(jì)劃生成timeline
//@escaping修飾則可以進(jìn)行異步網(wǎng)絡(luò)請(qǐng)求,下面的例子是靜態(tài)的時(shí)候的
func getTimeline(in context: Context, completion: @escaping (Timeline<CharacterDetailEntry>) -> Void) {
var date = Date()
var healthLevel = 0.25
var entries: [CharacterDetailEntry] = []
while healthLevel <= 1 {
entries.append(CharacterDetailEntry(date: date, healthLevel: healthLevel)) //添加當(dāng)前狀態(tài)的entry 是要立馬展示出來(lái)的
healthLevel = min(1, healthLevel + 0.25) // 每次把健康狀態(tài)升高0.25,最高為1
date = Calendar.current.date(byAdding: .hour, value: 1, to: date)! // TiimeLine提供一段Entry,而entry的最小間隔是1分鐘,及時(shí)設(shè)置成秒也沒(méi)用。
}
let timeline = Timeline(entries: entries, policy: .atEnd) // .after .never
completion(timeline)
}
4.3 移除策略
在靈動(dòng)島leading視圖部位上下滑動(dòng)可以隱藏當(dāng)前的live activity , 也可以在應(yīng)用的設(shè)置里面禁止live activity。
default:“實(shí)時(shí)活動(dòng)”會(huì)在鎖定屏幕上顯示一段時(shí)間,以便用戶(hù)一目了然地查看手機(jī)以查看最新信息。用戶(hù)可以選擇隨時(shí)刪除“實(shí)時(shí)活動(dòng)”,或者系統(tǒng)會(huì)在“實(shí)時(shí)活動(dòng)”結(jié)束后四小時(shí)自動(dòng)移除它。
immediate:立即移除從鎖定屏幕結(jié)束的“實(shí)時(shí)活動(dòng)”
after: 系統(tǒng)會(huì)在給定日期后或自“實(shí)時(shí)活動(dòng)”結(jié)束起四小時(shí)后刪除已結(jié)束的現(xiàn)場(chǎng)活動(dòng)——以先到者為準(zhǔn)
除非App主動(dòng)結(jié)束或用戶(hù)手動(dòng)結(jié)束,否則展現(xiàn)在靈動(dòng)島的“l(fā)ive activity”活動(dòng)在不操作的情況下最多可以活躍8小時(shí)。如果在第8小時(shí)的時(shí)候用戶(hù)主動(dòng)關(guān)閉了default或after策略的live activity,鎖定屏幕上的可以再多顯示4個(gè)小時(shí)。所以即實(shí)時(shí)活動(dòng)會(huì)靈動(dòng)上島最多保留八小時(shí),在鎖定屏幕上最多保留十二小時(shí)。 殺死App不會(huì)停止live activity.
歡迎大家交流并指出錯(cuò)誤,謝謝