帶你走進靈動島

来源:https://www.cnblogs.com/Jcloud/archive/2023/12/05/17876535.html
-Advertisement-
Play Games

蘋果在 iPhone 14 Pro 及 iPhone 14 Pro MAX 上推出了靈動島,是一次交互玩法的革新。本文從靈動島的展現形式、場景限制、適配情況和遠程通知更新數據幾個方面全面帶你走進靈動島 ...


前言

iOS最近幾年新特性

iOS14 視頻畫中畫 AppLibrary 桌面小組件 照片隱私加強 應用限免 智能摺疊 全新siri懸浮顯示
iOS15 FaceTime支持屏幕共用 信息和新增擬我表情 推出專註模式 通知重新設計,圖標變得更大 地圖公共交通路線置頂,增加時間顯示 識別圖片上文字信息 支持照片信息和照片上的文字進行搜索
iOS16 iOS 16 鎖定界面 鎖定界面小組件 鎖屏界面的實時活動 iPhone鎖定全屏幕音樂播放器 電池百分比出來啦 視頻實況文本 快速查詢Wi-Fi密碼
iOS17 設置您的待機屏幕 優先考慮互動式小部件 定製您的聯繫海報 創建您自己的貼紙 設置新的 Safari 配置文件 開啟反追蹤 分享您的 iCloud 鑰匙串密碼

一、簡介

實時活動(Live Activity),是iOS16新增的擴展組件功能,可以在靈動島和鎖定屏幕上顯示應用程式的實時數據。用於追蹤事件和任務進度實時活動的開始和結束都是離散的,具體畫面場景如下:蘋果

蘋果在 iPhone 14 Pro 及 iPhone 14 Pro MAX 上推出了靈動島。靈動島將 iPhone 前置鏡頭和軟體通知結合在一起的全新設計,用出色的交互設計掩蓋硬體的缺陷,是一次交互玩法的革新。靈動島可以通過點按、長按、輕掃來進行交互,最多支持兩個應用同時“登島”。

靈動島全稱 Dynamic Island,作為 iOS 中實時活動(Live Activities)功能的一部分,用來展示需要實時更新的消息。例如外賣配送信息,地圖實時導航信息等。靈動島有 3 種展現形式。

1.1 展現形式

1.1.1 緊湊(Compact)

當系統只有 1 個實時活動的內容時,靈動島預設使用緊湊模式。緊湊模式下UI由頭部(Leading side)和尾部(Trailing side)組成,如圖所示。用戶可以點擊靈動島打開 App 查看實時活動的內容

1.1.2 最小化(Minimal)

當系統有多個實時活動的內容時,靈動島自動切換使用最小化模式。最小化模式下由附著的頭部(Leading(attached))和分割開的尾部(Trailing(detached))組成,如圖所示。和緊湊模式一樣,最小化模式也支持用戶點擊打開 App。

1.1.3擴展(Expanded)

當用戶在緊湊或最小化模式輕掃或長按靈動島時,靈動島可以切換成擴展模式。用於向用戶展示更多信息。擴展模式的 UI

設計儘量保持和緊湊模式一致,用戶從緊湊模式切換到擴展模式會有一個平滑的體驗。

當我們向 App Store 提交了適配靈動島的 App 版本時,以上 3 種模式都需要適配。

二、場景限制

2.1樣式限制

1、實時活動針對鎖定屏幕和靈動島提供了不同的視圖。鎖定屏幕可以出現在所有支持 iOS 16 的設備上。而靈動島在支持設備上,使用以下視圖顯示實時活動:緊湊前視圖、緊湊尾視圖、最小視圖和擴展視圖。

2、當用戶觸摸靈動島,且靈動島中有緊湊或最小視圖,同時實時活動更新時,會出現擴展視圖。在不支持靈動島的設備上,擴展視圖顯示為實時活動更新的橫幅。

3、為確保系統可以在每個位置顯示 App 的實時活動,開發者必須支持所有視圖

建議:同場景多卡片由於樣式趨同且摺疊,不建議同時創建多卡片

靈動島頁面需要實現的部分有4個:

a、不支持靈動島的機型 或 鎖屏時的 顯示

b、緊湊級展示(即左右貼合靈動島的展示)

c、多Live activity時的展示(即極小視圖,左貼合,右分離)

d、擴展視圖(長按靈動島時觸發)

備註:還有一個App同時存在的實時活動面板最多只能創建5個,這也是一個場景約束條件。Error requesting delivery Live Activity The operation couldn’t be completed. Maximum number of activities for target already exists

2.2 時間限制

實時活動最多可以保持八小時的活動狀態,除非其應用程式或人員在此限制之前結束活動。超過八小時限制後,系統自動結束直播活動,並立即將其移出動態島。但是,實時活動會保留在鎖定屏幕上,直到有人將其刪除,或者在系統將其刪除之前最多再保留四個小時(以先到者為準)。因此,實時活動在鎖定屏幕上保留最多 12 小時。

官方表述:https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities

A Live Activity can be active for up to eight hours unless your app or a person ends it before this limit. After the 8-hour limit, the system automatically ends it. When a Live Activity ends, the system immediately removes it from the Dynamic Island. However, the Live Activity remains on the Lock Screen until a person removes it or for up to four additional hours before the system removes it — whichever comes first. As a result, a Live Activity remains on the Lock Screen for a maximum of twelve hours.

2.3 數據更新

每個實時活動運行在自己的沙盒中,與小組件不同的是,它無法訪問網路或接收位置更新。若要更新實時活動的動態數據,少量(不能超過4KB)數據可通過遠程推送通知發送,或通過ActivityKit 框架後臺活動刷新數據。

ActivityKit 更新和 ActivityKit 推送通知的更新動態數據大小不能超過 4 KB。

2.4 網路限制

a、卡片本身禁止定位以及網路請求,數據刷新依賴本地刷新,實施活動推送刷新,同2)所述;

b、Live Activity內部禁用網路圖片,傳統的服務端傳圖片URL的方式無法滿足實際使用,但是希望傳入訂單圖片來個性化地表達並且區分不同訂單。

iOS 16 beta版創建時可以通過將圖片轉為Data格式傳入卡片,但是iOS16.1該方案僅限傳入4KB左右的圖片(API限制),因此暫時不考慮非本地圖片方案,採用內置圖片方式實現。

2.5 埋點限制

場景情況:由於預設情況點擊是回主程式,而並不是固定頁面,因此有必要自定義widgetUrl(如用於回到訂單頁面),也可以通過Link實現分區域的跳轉,Link和widgetUrl共存時,點擊Link區域會響應Link,因此兩者同時使用即可。

無法在widget內部直接添加埋點,並且靈動島收起時,僅支持添加同一個widgetUrl,對於收起狀態添加Link並沒有響應。

埋點方式:因為點擊直接跳轉到主App,因此考慮將埋點參數加入URL參數即可,主App解析時埋點。但是無法記錄包括用戶查看、用戶關閉(關閉卡片 繼續發送推送也沒有報錯 因此無法判斷)等行為的埋點。

對於靈動島的區分,實際測試發現,在展開模式下,可以加入Link並且可以正常響應,這與官方文檔中的描述一致。

三、適配

3.1 UI適配

1、尺寸

目前只有 iPhone 14 Pro 及 iPhone 14 Pro MAX 具有靈動島功能。在兩種機型上,靈動島的圓角半徑都為 44Points,這個數值和前置深感攝像頭的半徑是一樣的。按照前述的 3 種模式,靈動島的具體參數如下表格所示(表格涉及的數值表示Points)。

機型 屏幕尺寸 緊湊模式(頭部) 緊湊模式(尾部) 最小化模式 展開模式
iPhone 14 Pro 393*852 52.33*36.67 52.33*36.67 36.67*36.67 371*(84-160)
iPhone 14 Pro Max 430*932 62.33*36.67 62.33*36.67 36.67*36.67 408*(84-160)

2、顏色

開發者無法更改靈動島的背景顏色,只能更改文字顏色、素材顏色、靈動島邊框顏色等。UI 適配需要考慮系統的深色模式,必要情況可以使用兩套 UI。

3.2開發適配

3.2.1開發框架簡介

蘋果在 iOS 16.1 正式對外開放了靈動島適配框架ActivityKit,第三方 App 可以使用這些ActivityKit完成靈動島適配工作。註意ActivityKit的 API 目前僅適用於 iPhone。靈動島使用WidgetKitSwiftUI完成 UI 開發工作,ActivityKit在其中扮演創建Activity,請求數據,更新數據,結束Activity的角色。

3.2.2許可權管理

靈動島作為實時活動的一部分,需要實時活動許可權才能正常展示。和通知許可權,相機許可權等類似,實時活動許可權需要 App

3.2.3 生命周期

Request

Update

Observe avtivity state

End

import ActivityKit

struct AdventureAttributes: ActivityAttributes {
//不可變
    let hero: EmojiRanger
    /// The associated type that describes the dynamic content of a Live Activity.
    ///
    /// The dynamic data of a Live Activity that's encoded by `ContentState` can't exceed 4KB.
    struct ContentState: Codable & Hashable {
        let currentHealthLevel: Double
        let eventDescription: String
    }
}





let adventure = AdventureAttributes(hero: hero)

let initialState = AdventureAttributes.ContentState(
    currentHealthLevel: hero.healthLevel,
    eventDescription: "Adventure has begun!"
)
let content = ActivityContent(state: initialState, staleDate: nil, relevanceScore: 0.0)

let activity = try Activity.request(
    attributes: adventure,
    content: content,
    pushType: nil
)





let heroName = activity.attributes.hero.name               
let contentState = AdventureAttributes.ContentState(
    currentHealthLevel: hero.healthLevel,
    eventDescription: "\(heroName) has taken a critical hit!"
)

var alertConfig = AlertConfiguration(
    title: "\(heroName) has taken a critical hit!",
    body: "Open the app and use a potion to heal \(heroName)",
    sound: .default
)  
     
activity.update(
    ActivityContent<AdventureAttributes.ContentState>(
        state: contentState,
        staleDate: nil
    ),
    alertConfiguration: alertConfig
)





// Observe activity state asynchronously
func observeActivity(activity: Activity<AdventureAttributes>) {
    Task {
        for await activityState in activity.activityStateUpdates {
            if activityState == .dismissed {
                self.cleanUpDismissedActivity()
            }
        }
    }
}

// Observe activity state synchronously
let activityState = activity.activityState
if activityState == .dismissed {
    self.cleanUpDismissedActivity()
}





let hero = activity.attributes.hero

let finalContent = AdventureAttributes.ContentState(
    currentHealthLevel: hero.healthLevel,
    eventDescription: "Adventure over! \(hero.name) has defeated the boss! Congrats!"
)

let dismissalPolicy: ActivityUIDismissalPolicy = .default

activity.end(
    ActivityContent(state: finalContent, staleDate: nil),
    dismissalPolicy: dismissalPolicy)
}

3.2.4UI



import WidgetKit
import SwiftUI

@main
struct EmojiRangersWidgetBundle: WidgetBundle {
    var body: some Widget {
        EmojiRangerWidget()
        LeaderboardWidget()
        AdventureActivityConfiguration()
    }
}





struct AdventureActivityConfiguration: Widget {
    var body: some WidgetConfiguration {
        ActivityConfiguration(for: AdventureAttributes.self) { context in
            // ...
            // Create the view that appears on the Lock Screen and as a
            // banner on the Home Screen of devices that don't support the
            // Dynamic Island.
        } dynamicIsland: { context in
 // Create the views that appear in the Dynamic Island.
            DynamicIsland {
                // Create the expanded view.
                // Leading region
                

                // Expanded region
                

                // Bottom region
                 
            } compactLeading: {
                // Create the compact leading view.
                // ...
            } compactTrailing: {
                // Create the compact trailing view.
                // ...
            } minimal: {
                // Create the minimal view.
                // ...
            }
        }
    }
}





四、遠程通知更新數據

實時活動也支持遠程推送更新,根據文檔以下9點要求實現(avtivity遠程推送每小時有通知預算(數量未明確),超出後系統將關閉通知)

1、確保啟動activity時[request(attributes:contentState:pushType:)傳入pushType參數(.token);

2、獲取啟動後的activity的推送令牌pushToken,傳給服務端用來推送更新activity;(實時活動的pushToken不是消息通知的token,這個是獨立出來的)

3、服務端推送的更新內容欄位需要和ActivityAttributes的ContentState中定義的動態數據欄位對應;

4、設置推送的報頭apns-push-type的值為liveactivity;

5、設置推送的報頭apns-topic的值為.push-type.liveactivity;

6、正確的推送對應的內容和狀態;

7、使用pushTokenUpdates監聽pushToken變化,如有變化,就令牌失效,需要將新的令牌傳給伺服器;

8、當Activity結束時,伺服器端的pushToken將失效;

{
    "aps": {
        "timestamp": 1685952000,
        "event": "update",
        "content-state": {
            "currentHealthLevel": 0.0,
            "eventDescription": "Power Panda has been knocked down!"
        },
        "alert": {
            "title": "Power Panda is knocked down!",
            "body": "Use a potion to heal Power Panda!",
            "sound": "default"
        }
    }
}





註意:

1、不用為推送提供聲音 , 如果推送延遲,在activity結束後收到時將被忽略,avtivity每小時有通知預算(數量未明確),超出後系統將關閉通知;

2、實時活動的pushToken不是消息通知的token,這個token上報到JDPush服務,需要單獨管理和歸類。

備註:

  1. 靈動島的實時信息要有明確的開始和結束時間點

  2. 當一個實時信息持續超過 8 小時,系統會從靈動島移除這個 App 的信息

  3. 當一個實時活動結束時,靈動島上的展示信息也會立即被系統移除

  4. 避免在靈動島上顯示廣告,畢竟引起用戶反感可以被直接關閉

  5. App 要能夠響應靈動島的點擊信息,跳轉到 App 中的正確子頁面,而不是停留在 App 的首頁

運用場景

1、需在屏幕駐留的文字、圖像為主的信息:如地圖導航、airdrop 傳輸情況等;

2、後臺進行的音頻類:如接電話、放音樂、錄音、倒計時等;

3、即時交互反饋:如充電、靜音、人臉識別等。超過這三類信息後,桌面可能會變得雜亂無章

參考文章

ActivityKit官方文檔

https://developer.apple.com/videos/play/wwdc2023/10194

https://developer.apple.com/videos/play/wwdc2023/10184

https://www.jianshu.com/p/f410eba6c392

https://www.bilibili.com/read/cv18549307/

作者:京東零售 李艷敏

來源:京東雲開發者社區 轉載請註明來源


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 想要確保你的Windows服務即使在崩潰後也能自動重啟嗎?這篇文章教你如何用一個小巧的批處理腳本來實現這一點。教你怎麼設置定時檢查,如果發現服務掛了,就立刻拉起來。跟著步驟做,讓你的服務穩定運行不再是難題! ...
  • 背景 Redis是一種基於客戶端-服務端模型以及請求/響應協議的TCP服務。一個請求會遵循以下步驟: 1 客戶端向服務端發送命令分四步(發送命令→命令排隊→命令執行→返回結果),並監聽Socket返回,通常以阻塞模式等待服務端響應。 2 服務端處理命令,並將結果返回給客戶端。 上述兩步稱為:Roun ...
  • 課程中,第二章是MySQL環境搭建,因為我是網上找的博客,下載zip,直接安裝的,就沒看視頻,所以沒有第二章筆記。這裡給出MySQL社區版下載地址。 C-03.基本的SELECT語句 1.SQL概述 1.1 SQL背景知識 1974年,IBM研究員發佈了一篇揭開資料庫技術的論文《SEQUEL:一門結 ...
  • SQL CREATE DATABASE 語句 SQL CREATE DATABASE 語句用於創建一個新的 SQL 資料庫。 語法 CREATE DATABASE 資料庫名稱; 示例 以下 SQL 語句創建了一個名為 "testDB" 的資料庫: CREATE DATABASE testDB; 通過 ...
  • 單體架構下鎖的實現方案 1. ReentrantLock全局鎖 ReentrantLock(可重入鎖),指的是一個線程再次對已持有的鎖保護的臨界資源時,重入請求將會成功。 簡單的與我們常用的Synchronized進行比較: ReentrantLock Synchronized 鎖實現機制 依賴AQ ...
  • 如今,大規模、高時效、智能化數據處理已是“剛需”,企業需要更強大的數據平臺,來應對數據查詢、數據處理、數據挖掘、數據展示以及多種計算模型並行的挑戰,湖倉一體方案應運而生。 《實時湖倉實踐五講》是袋鼠雲打造的系列直播活動,將圍繞實時湖倉的建設趨勢和通用問題,邀請奮戰於企業數字化一線的核心產品&技術專家 ...
  • 隨著業務飛速發展,某汽車製造企業業務系統數量、複雜度和數據量都在呈幾何級數的上漲,這就對於企業IT能力和IT架構模式的要求越來越高。加之企業大力發展數字化營銷、新能源車等業務,希望通過持續優化客戶體驗,創造可持續發展的數字化轉型之路。 為更好應對數字化變革所帶來的挑戰,現有的豎井架構的數據體系難以滿 ...
  • 大家好,我是獨孤風,從本周開始,爭取每周為大家帶來一個優秀的開源項目推薦。 開源項目不僅促進了技術的發展和普及,還為全球範圍內的開發者和用戶社區建立了一個共用知識、協作和創新的平臺。站在巨人的肩膀上才能看的更遠,我們平時也應該多多關註開源項目,不僅學習其豐富的知識,也要找機會為開源事業做出自己的貢獻 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...