應用程式基礎

使用 Jetpack Glance 和 Remote Compose,將資訊方塊升級為 Wear 小工具

喇叭

  • François Deschênes

    產品經理

  • Yuri Schimke

    軟體工程師

關於

講座簡介

在本課程中,我們將深入探討技術,瞭解全螢幕資訊方塊如何演變成動態、部分高度的 Wear 小工具。

我們將探討統一 Jetpack Glance API 和新 Remote Compose 引擎的技術優勢,並詳細說明這些技術如何與 Modern Android Development 完美搭配。

最後,我們會分享最新的使用者體驗指南,並逐步說明實用的遷移策略,協助您打造新一代的資訊一覽 UI。

摘要

  • Wear OS 正在將全螢幕資訊方塊,演進為使用 Jetpack Glance 建構並由 Remote Compose 支援的 Wear 小工具。
  • Remote Compose 與 Jetpack Compose UI 共用相同的編譯器和執行階段,同時安全地將 UI 與應用程式程序分離。
  • 小型和大型容器尺寸與行動裝置格線格式一致,而 Jetpack Glance Wear API 則可回溯相容至 Wear 4。
  • 如要將現有資訊方塊遷移至小工具,可以使用建議的雙重服務策略,或單一相容性服務。

技能

資源

Gemini Notebook

主題

  • wear-os
  • wear-widgets
  • jetpack-glance
  • remote-compose
  • tiles-migration
  • jetpack-compose

轉錄稿

簡介

  • 大家好!

  • 我是 Frank,負責 Wear OS 的一目瞭然體驗。

  • 手錶是使用者全天候不可或缺的夥伴,今天我們將逐步說明如何運用全新的 Wear 小工具體驗。

  • 我們將探討如何使用最新 API,直接在使用者手腕上提供最重要的功能。這些 API 旨在讓 Android 開發人員 (例如您) 熟悉且直覺地建構 Wear OS。

  • 今天和我一起上台的是我的優秀同事兼鄰座夥伴 Yuri,他將深入探討我們如何做到這一點。

  • 大家好,我是 Yuri Schimke。

  • 我是 Wear OS 團隊的工程師,主要負責 Remote Compose API。

  • 今天我會簡單介紹 Remote Compose,並說明從資訊方塊遷移至 Wear 小工具的程序。

  • 接著,我會將時間交回給 Frank。

將資訊方塊升級為 Wear 小工具

  • 太棒了!

  • 謝謝你,Yuri。

  • 我們正式將手錶納入統一的 Android 小工具生態系統,將全螢幕資訊方塊升級為 Wear 小工具。

  • 由於這些體驗現在是使用 Jetpack Glance 建構,因此您可以看到它與行動裝置小工具使用的基礎架構相同。

  • 您會發現,日後建構 Wear 應用程式會越來越得心應手。

遠端 Compose 總覽

  • 為了提供這些體驗,我們正在改良 UI 堆疊,也就是底層 UI 堆疊。

  • Wear 小工具採用 Remote Compose,這是適用於遠端 UI 的新 Android 架構。

  • 這表示您終於可以使用與 Jetpack Compose 密切配合的宣告式 API,建構應用程式外體驗,例如小工具。

  • Remote Compose 可為小工具提供現代化圖形和回應式版面配置,同時確保效能和電池效率。

  • 此外,將 UI 與應用程式程序分離後,小工具就能安全序列化,並在各種 Android 裝置上輕鬆算繪。

  • 也就是說,您只要花費極少的心力,就能將這種豐富的體驗帶到幾乎所有支援的遠端介面。

版面配置大小和回溯相容性

  • 為了盡可能順暢地從資訊方塊轉換為小工具,我們推出了兩種標準容器大小:小型和大型。

  • 這些格式與您在行動裝置上建構小工具時,所習慣的 2x1 和 2x2 格狀小工具格式非常相似。

  • 在部分硬體製造商的 Wear 7 裝置上,Wear 小工具會與其他應用程式的小工具一起顯示在垂直捲動匣中。

  • 舉例來說,Samsung Galaxy Watch 上的 Wear 小工具會像這樣。

  • 平台架構支援垂直捲動匣,方便硬體製造商日後採用這種模式。

  • 您也不必擔心會遺漏任何使用者或現有使用者。

  • Jetpack Glance Wear API 旨在支援回溯相容性,最低可支援 Wear 4。

  • 如果舊款裝置支援水平小工具匣或資訊方塊匣,系統會自動處理。

  • 您只需在程式碼中聲明要支援全螢幕模式,系統就會在這些裝置上,將大型小工具顯示為全螢幕傳統資訊方塊。

  • 現在,Yuri 將逐步說明程式碼,示範如何將現有資訊方塊遷移至 Wear 小工具。

現有資訊方塊的遷移策略

  • 謝謝 Frank。

  • 從頭開始建構新的 Wear 小工具非常簡單。

  • 您只需定義 GlanceWearWidgetService,並使用 Remote Compose 建構 UI 即可。

  • 不過,如果應用程式已有正式版資訊方塊,則必須遷移服務、UI 和資料。

  • 為盡可能順利完成轉換,我們提供多種方式,確保現有使用者享有流暢體驗。

  • 服務方面,您可以選擇雙重服務或單一服務策略。

  • 我們建議採用雙重服務,也就是保留現有的 TileService,用於舊版 Wear OS 裝置,並新增 GlanceWearWidgetService,用於 Wear OS 7 以上版本。

  • 相較之下,如果使用單一服務,您會建立新的單一 GlanceWearWidgetService,用於處理這兩種通訊協定,並在相容模式下執行,將小工具轉譯為舊版裝置上的資訊方塊。

  • 無論採用哪種方式,都能繼續觸及使用者。

  • 只會影響日後要維護的程式碼。

  • 我們剛在 Android 開發人員網站上發布了完整說明文件,詳細說明這兩種模式的使用方式和時機。

  • 歡迎參閱,瞭解哪種策略最適合您的應用程式。

使用 Remote Compose 建構 UI

  • 現在來談談 UI 層。

  • 遷移時,您的思考框架會改變。

  • 先前,資訊方塊使用的是 ProtoLayout,這是專為 Wear 資訊方塊建構的程式庫。

  • Wear 小工具則是以 Remote Compose 為基礎。

  • Remote Compose 與 Jetpack Compose UI 採用相同的基礎,使用相同的核心編譯器和執行階段。

  • 此外,這項工具的設計與 Compose UI 程式庫 (例如 Foundation 和 Material 3) 非常相似,因此您能輕鬆上手。

  • 但您只需將方塊、欄或文字換成 RemoteBox、RemoteColumn 或 RemoteText 即可。

  • 在這種情況下,您會經常寫到「remote」。

  • 此外,為了加快工作流程,我們還提供一整套專為小工具設計、可立即使用的 Remote Compose 元件。

  • 也就是說,現有的 Wear Material 3 設計 (包括 Figma 中的設計) 都能輕鬆轉換成小工具,工程師和設計師都能輕鬆上手。

  • 為了瞭解這些架構的一致性,我們來看一個具體範例。

  • 我們將在 Material 3 切換按鈕上建構自己的應用程式元件。

  • 左側是您在應用程式中編寫的標準 Wear Compose 元件,右側則是 Remote Compose 版本。

    // Wear Compose
    @Composable
    fun HistoryEraserButton(
      onClick: () -> Unit,
      modifier: Modifier = Modifier,
      checked: Boolean = true,
      onCheckedChange: (Boolean) -> Unit = {},
    )
    // Wear RemoteCompose
    @RemoteComposable
    @Composable
    fun RemoteHistoryEraserButton(
      onClick: Action,
      modifier: RemoteModifier = RemoteModifier,
      checked: RemoteBoolean = true.rb,
      onCheckedChange: Action = Action.Empty,
    )
  • 請注意兩者的模式有多相似。

  • 不過,編寫遠端 Compose 程式碼時,您會使用 RemoteComposable 註解。

  • 如果您使用修飾符和布林值等熟悉的參數,這些參數會有對應的遠端 Compose 類型,例如 RemoteModifier 和 RemoteBoolean。

  • 並使用動作,而非 lambda。

  • 您不必定義要在 lambda 內執行的程式碼,而是需要宣告動作,例如啟動待處理意圖、呼叫服務或更新值。

  • 接著來看看元件的主體。

  • 您會發現連主題都一致。

  • 您可以將 Material 3 色彩配置套用至遠端 Compose 元件,就像在標準 Compose 中一樣,讓小工具與應用程式的品牌宣傳完全一致。

    // Wear Compose
      val colors = MaterialTheme.colorScheme
      SplitSwitchButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        toggleContentDescription = "Arm Eraser",
        onContainerClick = onClick,
        modifier = modifier.fillMaxWidth(),
        colors =
          SwitchButtonDefaults.splitSwitchButtonColors(
            checkedContainerColor = colors.errorContainer, …
          ),
        label = { Text("History Eraser") },
        secondaryLabel = { Text("Don't touch it!") },
      )
    // Wear RemoteCompose
      val colors = RemoteMaterialTheme.colorScheme
      RemoteSplitSwitchButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        toggleContentDescription = "Arm Eraser".rs,
        onContainerClick = onClick,
        modifier = modifier.fillMaxWidth(),
        colors =
          RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
            checkedContainerColor = colors.errorContainer, …
          ),
        label = { RemoteText("History Eraser".rs) },
        secondaryLabel = { RemoteText("Don't touch it!".rs) },
      )
  • 最後,我們來看看結果。產生的 UI 正如預期,是簡潔、回應式、動畫切換鈕。

Compose 預覽支援小工具

  • 很難分辨兩者差異。

  • 為了協助您設計、疊代及驗證小工具版面配置,而不必一律在裝置或模擬器上執行,我們新增了 Wear 小工具的 Compose 預覽支援。

  • 由於小工具取決於原始設備製造商 (OEM) 特定的容器限制 (例如大小、形狀、邊框間距、圓角半徑),因此我們以標準預覽註解為基礎,但使用額外的參數提供者來插入這些設定。

    @Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
    @Composable
    fun WeatherWidgetSquirclePreview(
        @PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
    ) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
    
    @Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
    @Composable
    fun WeatherWidgetRoundPreview(
        @PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
    ) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
  • 程式庫提供預先設定的 PreviewParameter 供應器實作,與實際的 Wear OS 裝置相符。

  • 這些預覽註解可讓您輕鬆驗證各種硬體形狀的版面配置。

  • 除了測試版面配置外,您也可以使用這些預覽畫面,產生裝置端小工具挑選器所需的靜態圖片。

    @Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
    @Composable
    fun WeatherWidgetRectangularPreview(
        @PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
    ) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
  • 程式庫提供矩形預覽形狀的參數,可模擬完整未裁剪的矩形容器。

實作範例和遷移工具

  • 如果想瞭解實際運作方式,可以查看 Horologist 媒體範例應用程式,我們已更新這個應用程式,加入展示這個 API 的新小工具。

  • 我們會說明如何新增小型和大型媒體小工具。

  • 請前往 GitHub 查看,並排比較舊版 ProtoLayout 程式碼和新的 Remote Compose 實作。

  • 相信你會喜歡。

  • 最後,這場演講當然少不了 AI。

  • 為加快遷移速度,我們在 GitHub 上發布了新的「將資訊方塊遷移至小工具」技能。

  • 您可以搭配偏好的代理使用,也可以透過 Android CLI 直接新增至 Android Studio。

    android skills add wear-widgets
    android skills add --all
  • 現在,我將交棒給 François,由他為大家總結。

摘要和收尾

  • 感謝您!

  • 謝謝你,Yuri。

  • 如您所見,將資訊方塊演變成 Wear 小工具的過程非常簡單。

  • 總結來說,遷移至 Jetpack Glance Wear 和 Remote Compose 不僅能更新 UI,還能加入更統一的 Android 小工具生態系統。

  • 現在,您可以使用與 Jetpack Compose 完全一致的新式宣告式架構,建構美觀且回溯相容的小工具。

  • 您可以立即開始遷移資訊方塊,請前往 Android 開發人員網站參閱入門指南,瞭解所有詳細資訊。

  • 期待看到您為手錶打造出各種一目瞭然、表現力豐富的體驗。

  • 非常感謝各位今天早上參與這場活動,希望大家能盡情享受接下來的會議。

  • 感謝您!

程式碼

程式碼片段

「使用 Remote Compose 建構 UI」影片 06:40 處的 Kotlin 程式碼片段
// Wear Compose
@Composable
fun HistoryEraserButton(
  onClick: () -> Unit,
  modifier: Modifier = Modifier,
  checked: Boolean = true,
  onCheckedChange: (Boolean) -> Unit = {},
)
「使用 Remote Compose 建構 UI」影片 06:40 處的 Kotlin 程式碼片段
// Wear RemoteCompose
@RemoteComposable
@Composable
fun RemoteHistoryEraserButton(
  onClick: Action,
  modifier: RemoteModifier = RemoteModifier,
  checked: RemoteBoolean = true.rb,
  onCheckedChange: Action = Action.Empty,
)
「使用 Remote Compose 建構 UI」影片 07:39 處的 Kotlin 程式碼片段
// Wear Compose
  val colors = MaterialTheme.colorScheme
  SplitSwitchButton(
    checked = checked,
    onCheckedChange = onCheckedChange,
    toggleContentDescription = "Arm Eraser",
    onContainerClick = onClick,
    modifier = modifier.fillMaxWidth(),
    colors =
      SwitchButtonDefaults.splitSwitchButtonColors(
        checkedContainerColor = colors.errorContainer, …
      ),
    label = { Text("History Eraser") },
    secondaryLabel = { Text("Don't touch it!") },
  )
「使用遠端 Compose 建構 UI」中 07:39 的 Kotlin 程式碼片段
// Wear RemoteCompose
  val colors = RemoteMaterialTheme.colorScheme
  RemoteSplitSwitchButton(
    checked = checked,
    onCheckedChange = onCheckedChange,
    toggleContentDescription = "Arm Eraser".rs,
    onContainerClick = onClick,
    modifier = modifier.fillMaxWidth(),
    colors =
      RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
        checkedContainerColor = colors.errorContainer, …
      ),
    label = { RemoteText("History Eraser".rs) },
    secondaryLabel = { RemoteText("Don't touch it!".rs) },
  )
「Compose preview support for widgets」影片 08:20 處的 Kotlin 程式碼片段
@Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetSquirclePreview(
    @PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)

@Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRoundPreview(
    @PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
「Compose preview support for widgets」影片 08:58 處的 Kotlin 程式碼片段
@Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRectangularPreview(
    @PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
「Sample implementation and migration tools」影片 09:58 處的殼層程式碼片段
android skills add wear-widgets
android skills add --all