0x00 前言
2020 年 6 月 22 日,蘋果召開了第一次線上的開發者大會 - WWDC20。這可謂是一次可以載入史冊的釋出會,宣佈了 ARM 架構 Mac 晶片、軟硬體的生態大統一、iOS 14 系統介面大改等一系列激動人心的訊息。
當然,最讓我感興趣的就是讓 iOS 介面大改的 Widget 了。過去幾年,iOS 的桌面互動體驗可謂是一言難盡,Widget 的加入無疑是一次比較大的破局。在看釋出會的時候,我的腦海裡就浮現出一個問題:“這會是下一個網際網路公司競爭的流量入口嗎?”
先不拋結論,讓我們先看一下 WWDC20 介紹了哪些關於 Widget 的新東西。
( WWDC 2020精彩內容思否專欄:https://segmentfault.com/blog...
本篇內容來自於阿里巴巴淘系技術部,高階無線開發工程師柘劍。
更多精彩內容可關注【淘系技術】公眾號。)
0x01 什麼是 Widget?
Widget 不是一個小型的 App,它是一種新的桌面內容展現形式,主要是用於彌補主應用程式無法及時展示使用者所關心的資料。如下圖所示:
一個優秀的 Widget 需要有三個特點:簡單明瞭(Glanceable)、恰當展示(Relevant)、個性化定製(Personalized)
簡單明瞭(Glanceable)
Widget 不是一個小型的 App,這句話被反覆提起。一般使用者每天進入主螢幕的次數超過 90 次,但停留的總時長不過幾分鐘。通常來說使用者只會在主螢幕上停留片刻時間,就會跳轉到其他地方,所以並不需要任何複雜的互動設計來增強 Widget 的作用,也不需要複雜的樣式來豐富 Widget 的內容,簡單明瞭的內容才是 Widget 的關鍵。
和安卓的 Widget 不太一樣,蘋果設計的 Widget 並不支援任何互動行為,也不建議大家設計過於複雜的樣式來呈現內容,這也非常符合蘋果對於主螢幕的改進一直保持克制的特點。
恰當展示(Relevant)
蘋果期望 Widget 可以和正在執行或者考慮的事情緊密的結合。比如,早上起床,使用者最關心天氣怎麼樣,Widget 可以展示一下天氣情況;起床後,使用者就要了解一下一天的行程,Widget 可以展示一下 Reminders 中的內容;等到一天忙完了,準備睡覺的時候,可以用 Widget 開啟音樂稍微放鬆一下。為此,蘋果系統提供了一個叫智慧疊放(Smart Stacks)的功能,智慧疊放是一個 Widgets 的集合。系統會根據每個人的習慣,藉助端智慧的能力,自動的顯示準確的 Widget 在最頂部。
當然,蘋果也考慮到了一些特殊的場景,比如 Widget Gallery 瀏覽時,提供了 Snapshot 的能力給到開發者可以定製展示樣式,當載入內容的時候提供了 Placeholder UI API 而不是單調的 loading 載入框來避免過多的白屏的尷尬局面。這些設計的目的只有一個,蘋果期望 Widget 可以在任何特定的場景都可以展示合理的樣式。
個性化定製(Personalized)
Widget 需要一定的定製能力,比如當我新增一個天氣 Widget,我只需要關心杭州的天氣怎麼樣。為了實現這個能力,蘋果給 Widget 提供了 Configuration 的能力。顧名思義,就是可配置。一共有兩種配置型別:
- StaticConfiguration,也就是使用者無需配置,展示的內容只和使用者資訊有關係。
- IntentConfiguration,支援使用者配置及使用者意圖的推測功能。
IntentConfiguration 的實現是基於 Intents.framework,開發過 SiriKit 和 Shortcuts 一定知道 Intents API 是用於瞭解使用者意圖的。其實就是一個智慧的表單系統,開發者建立一個 SiriKit Intent Definition File 之後,只需要簡單的配置,Xcode 會自動幫你生成對應的程式碼和型別。
當開發者編寫完配置之後,會藉助 Intents.framework 的能力,在執行的時候直接繪製出一個配置頁面(如下圖所示),開發者並不需要關心如果編寫這個頁面。
0x02 Widget 的重新整理方式
Widget 的重新整理方式是很特別的,相當的剋制。在展開講重新整理方式之前,要講一個概念,叫 Timeline。顧名思義,就是時間線,下面的圖就是一條 Timeline。
當系統的 WidgetKit 呼叫 Reload Timeline API 之後,會要求 Widget Extension 的 Timeline Provider 提供一組 TimelineEntry 和 ReloadPolicy,用來後續重新整理頁面。
這裡的概念比較多,我們一個一個來解釋。
首先,Widget 的重新整理完全由 WidgetCenter 控制。開發者無法通過任何 API 去主動重新整理 Widget 的頁面,只能告知 WidgetCenter,Timeline 需要重新整理了。
系統提供了兩種方式來驅動 Timeline 的 Reload。System Reloads 和 App-Driven Reloads。
System Reloads: 這個行為由系統主動發起,會呼叫一次 Reload Timeline 向 Widget 請求下一階段重新整理的資料。系統除了會按時發起 System Reloads 之外,還會藉助端智慧的能力,動態決策每個不同的 TimeLine 的 System Reloads 的頻次。例如被檢視次數很大程度上直接決定了 System Reloads 的頻率。當然還有一些由於裝置環境變化觸發的行為也會觸發 System Reloads,比如裝置時間進行了變更。
App-Driven Reloads:指的是 App 請求 Widget 下一階段重新整理的資料。這裡也要分兩種場景,應用在前臺執行和應用在後臺執行。當應用在前臺執行的時候,App 可以直接請求 WidgetCenter 的 API 來觸發 Reload Timeline;而當應用處於後臺時,後臺推送(Background Notification)也可以觸發 Reload Timeline。
注意,前面所提到的 Reload Timeline 並不是直接重新整理 Widget,而是 WidgetCenter 重新向 Widget 請求下一階段的資料。而 Timeline Provider 就是提供這個資料的物件。
而 Timeline Provider 提供的資料有兩部分,一部分是 TimelineEntry,另外一部分是 ReloadPolicy。
TimelineEntry 是某個時間節點下 Widget 需要呈現的檢視資訊和時間點。
而 ReloadPolicy 則是接下來這段時間 Timeline 的重新整理策略,一共有三種:
- atEnd: 是指 Timeline 執行到最後一個時間片的時候再重新整理。
- atAfter: 是指在某個時間以後有規律的重新整理。
- never:是指以後不需要重新整理了。什麼時候需要重新重新整理需要 App 重新告知 Widget。
當 Timeline Provider 提供完下一階段的資料之後,就會停止執行。系統也會根據 entry 的資訊,到點對 Widget 的展示內容進行重新整理。值得一提的是,WidgetKit 會把 Timelines 所定義的 Entries 對應的 Views 結構資訊快取到磁碟,然後在重新整理的時候才通過 JIT 的方式來渲染。這使得系統可以在極低電量開銷下為眾多 Widgets 處理 Timelines 資訊。
簡而言之,蘋果對 Widget 的重新整理相當的剋制。開發者無法直接決定 Widget 重新整理,只能提供重新整理策略。具體的時間和節奏全部由系統來控制。蘋果這麼做,大概率是為了提高主螢幕的效能和減少電量開銷上的考慮。
0x03 Widget 和 SwiftUI
Widget 只能用 SwiftUI 來進行開發,確切的說,Widget 的本質是一個隨著時間線而更新的 SwiftUI 檢視。
當我最開始知道這個限制的時候,說實話是相當震驚的。眾所周知,SwiftUI 是一個去年才釋出的新技術,而且最開始的時候 SwiftUI 是相當不穩定的,以至於蘋果自己都是建議開發者暫時不要用到生產環境上,Widget 作為系統主螢幕的功能,強制使用這麼新的技術,會不會太激進了?
顯然是不會。蘋果要求 Widget 只能使用 SwiftUI 主要是基於幾點考慮:
- SwiftUI 經過一年的發展,有了很大的提升,不僅可以使用 SwiftUI 來構建整個應用程式,而且在一些方面已經優於基於 UIKit 的開發方式了。具體的內容,大家可以看一下 《詳解 WWDC 20 SwiftUI 的重大改變及核心優勢》
- 蘋果正在佈局跨平臺,大統一的策略。Widget 作為系統的核心功能,使用 SwiftUI 是唯一的選擇。SwiftUI 精美的 DSL 設計,使得開發者使用一套程式碼在 iOS、iPadOS、macOS、watchOS 和 tvOS 等多個平臺展示不同的樣式可以輕鬆的實現。(Widget 只會在 iOS、iPadOS 以及 macOS 上展示)
- 使用了 SwiftUI 使得 Dynamic Type 和 Dark Mode 等問題適配起來成本很低。
- 只有使用 SwiftUI 才能達到很多對於 Widget 的限制。倘若可以使用 UIKit 開發者可能有無數種辦法繞過蘋果的限制。比如開發無法使用 UIViewRepresentable 來橋接 UIKit,只要使用任何 UIKit 的元素會直接 Crash。
- 將 Swift 語言和 SwiftUI 的重要程度提升了一大截。
0x04 Widget 的展示形式
一個 App 可以對應多個 Widget Extension
你可以使用 WidgetBundle 來進行組裝。蘋果並沒有對 Widget Extension 有數量上的限制。所以為了避免大家開發過多的 Widget Extension 導致搜尋起來麻煩,在 Widget Gallery 中只能看到一個條目。
一個 Widget Extension 一共只有三種尺寸。
考慮到簡單明瞭的特點以及手機螢幕的空間有限的問題。蘋果只提供了三種樣式可以選擇,systemSmall(2 * 2 icon 區域)、systemMedium(2*4 icon 區域)、systemLarge(4 * 4 icon 區域)
同一種 Widget 可以被多次新增到主螢幕中
而且對於每一個 Widget 來說,都有其對應的獨立 TimeLine,相互獨立,互不干擾。
開發者無法開發智慧疊放(Smart Stacks)
開發者無法開發一個 Widget 的集合。智慧疊放(Smart Stacks)是一個系統特有的能力,對於開發者來說,唯一可以做的就是主動提供相關性資訊。前文提到了 Timeline 的資料又一組 TimelineEntry 組成,而每個 TimelineEntry 除了包含時間點和檢視資訊以外,還可以包含一個 TimelineEntryRelevance 物件,用來表示這個 entry 的相關性。
不可互動,只可點選
Widget 的 UI 是無狀態的,不支援滾動,也不支援像 Switch 一樣的互動元素。唯一開放的能力只有通過點選和DeepLink 來喚起主 App。
蘋果提供了兩種 API 給到開發者,第一種是 SwiftUI widgetURL API),程式碼如下所示:
而 widgetURL 的可點選區域如下:
對於 systemSmall 型別來說,只支援 widgetURL 的方式,但是 systemMedium 和 systemLarge 還可以使用 SwiftUI Link API,程式碼如下所示:
而 Link 的可點選區域如下:
同時,為了效能和耗電量的考慮。Widget 不能展示視訊和動態影像。所以期待通過動效吸引使用者眼球的方式可以暫時息熄火了~
0x03 總結與展望
Widget 的出現,讓 iOS 系統的桌面有了破局,一定會有很多產品都期待藉助 Widget 來豐富自己產品的內容表達。
但是,Widget 設計的初衷是簡單明瞭的在恰當的時機展示一些帶有個性化定製的內容,為了不讓主螢幕的整體使用體驗變得複雜,Widget 從技術上就做的很剋制,限制了很多很多的能力。因此我認為Widget 不會成為下一個網際網路公司競爭的流量入口,它會成為 App 提高使用者體驗的利器。
從技術角度看,SwiftUI Only 這種看似“激進”的策略其實也是一種訊號,其實也是在告訴大家蘋果對於 Swift 以及 SwiftUI 的重視程度。
雖然,從目前來看 Pure SwiftUI 的設計,可以做的事情真的很少,但是我也相信,蘋果會不斷優化 Pure SwiftUI 的能力。讓開發者可以以最低的開發成本,適配更多的平臺。
最後,也期待大家可以好好研究一下 Widget,結合自己的產品,給到使用者極致的使用者體驗。
( WWDC 2020精彩內容思否專欄:https://segmentfault.com/blog...
本篇內容來自於阿里巴巴淘系技術部,高階無線開發工程師柘劍。
更多精彩內容可關注【淘系技術】公眾號。)
參考
iOS 14 Preview: https://www.apple.com.cn/ios/ios-14-preview/
Widgets code-along: https://developer.apple.com/news/?id=yv6so7ie
Meet WidgetKit: https://developer.apple.com/videos/play/wwdc2020/10028/
What's new in SwiftUI: https://developer.apple.com/videos/play/wwdc2020/10041/
Add configuration and intelligence to your widgets:https://developer.apple.com/videos/play/wwdc2020/10194/
Build SwiftUI views for widgets: https://developer.apple.com/videos/play/wwdc2020/10033/
Creating a Widget Extension: https://developer.apple.com/documentation/widgetkit/creating-a-widget-extension
Building Widgets Using WidgetKit and SwiftUI:https://developer.apple.com/documentation/widgetkit/building_widgets_using_widgetkit_and_swiftui
Making a Configurable Widget: https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget
Keeping a Widget Up To Date: https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date
團隊招人
負責手淘移動端的基礎PaaS及平臺技術。涉及移動閘道器、網路加速、長連通道、圖片體驗等基礎技術,以及海量訊息推送、浮層搭投全域觸達等平臺型技術,並對移動端系統進行前沿探索,打造了全站IPv6、iOS使用者態網路棧、Android最小核、自適應執行緒排程等高效能技術和架構。
在這裡,你會面臨超級App在效能、體驗、安全等方面的極致追求;在這裡,你會站在業務和資料視角針對目標進行充分了解和深入優化;在這裡,你會與業界各領域大牛並肩作戰、快速成長。
我們期待有技術、有理想的你加入,與我們共享積極、透明、開放的團隊氛圍,伴隨著各種乾貨滿滿的分享培訓以及業務和技術挑戰,我們將一同在技術領域不斷攻堅、推陳出新,共同駛向屬於我們的星辰大海。
職位:iOS 開發、Android 開發、C++開發、Java 服務端開發、前端開發、資料工程師、演算法工程師
感興趣的同學可將簡歷傳送到:zhejian.wzj@alibaba-inc.com,獲取優先內推資格!