資訊方塊版本管理

在 Wear OS 裝置上,資訊方塊是由兩個具有獨立版本的關鍵元件轉譯。如要確保應用程式資訊方塊可在所有裝置上正常運作,請務必瞭解這個基礎架構。

  • Jetpack 資訊方塊相關程式庫:這些程式庫 (包括 Wear 資訊方塊和 Wear ProtoLayout) 會嵌入應用程式,而您身為開發人員,可控制其版本。應用程式會使用這些程式庫,在回應系統的 onTileRequest() 呼叫時,建構 TileBuilder.Tile 物件 (代表資訊方塊的資料結構)。
  • ProtoLayout 轉譯器:這個系統元件負責在螢幕上轉譯 Tile 物件,並處理使用者互動。轉譯器的版本並非由應用程式開發人員控制,且可能因裝置而異,即使是硬體相同的裝置也不例外。

資訊方塊的外觀或行為可能會因應用程式的 Jetpack Tiles 程式庫版本,以及使用者裝置上的 ProtoLayout 轉譯器版本而異。舉例來說,某台裝置可能支援旋轉或顯示心率資料,而另一台裝置則不支援。

本文件說明如何確保應用程式與不同版本的方塊程式庫和 ProtoLayout 轉譯器相容,以及如何遷移至較新的 Jetpack 程式庫版本。

考量相容性

如要建立可在多種裝置上正常運作的資訊方塊,請考慮下列事項。

偵測轉譯器版本

  • 使用傳遞至 onTileRequest() 方法的 DeviceParameters 物件 getRendererSchemaVersion() 方法。這個方法會傳回裝置上 ProtoLayout 轉譯器的主要和次要版本號碼。
  • 接著,您可以在 onTileRequest() 實作中使用條件邏輯,根據偵測到的轉譯器版本調整資訊方塊的設計或行為。
    • 舉例來說,如果系統不支援特定動畫,您可以改為顯示靜態圖片。

@RequiresSchemaVersion 註解

  • ProtoLayout 方法上的 @RequiresSchemaVersion 註解會指出該方法所需的最低轉譯器架構版本,以便該方法能如說明所示運作 (範例)。
    • 雖然呼叫需要比裝置上可用版本更高轉譯器版本的方法不會導致應用程式當機,但可能會導致內容未顯示或功能遭到忽略。

範例

override fun onTileRequest(
    requestParams: TileService.TileRequest
): ListenableFuture<Tile> {
    val rendererVersion =
        requestParams.deviceConfiguration.rendererSchemaVersion
    val tile = Tile.Builder()

    if (
        rendererVersion.major > 1 ||
            (rendererVersion.major == 1 && rendererVersion.minor >= 300)
    ) {
        // Use a feature supported in renderer version 1.300 or later
        tile.setTileTimeline(/* ... */ )
    } else {
        // Provide fallback content for older renderers
        tile.setTileTimeline(/* ... */ )
    }

    return Futures.immediateFuture(tile.build())
}

使用不同的轉譯器版本進行測試

如要針對不同轉譯器版本測試資訊方塊,請將資訊方塊部署至不同版本的 Wear OS 模擬器。(在實體裝置上,ProtoLayout 轉譯器更新會透過 Play 商店或系統更新提供。您無法強制安裝特定轉譯器版本。)

Android Studio 的資訊方塊預覽功能會使用程式碼所依附的 Jetpack ProtoLayout 程式庫中嵌入的轉譯器,因此另一種做法是在測試資訊方塊時,依附不同的 Jetpack 程式庫版本。

遷移至 Tiles 1.5 / ProtoLayout 1.3 (Material 3 Expressive)

更新 Jetpack 資訊方塊程式庫,充分運用最新增強功能,包括 UI 變更,讓資訊方塊與系統完美整合。

Jetpack Tiles 1.5 和 Jetpack ProtoLayout 1.3 推出了幾項重大改善和變更。包括:

  • 用於說明 UI 的類似 Compose API。
  • Material 3 Expressive 元件,包括底部緊貼邊緣的按鈕,以及支援強化視覺效果:Lottie 動畫、更多漸層類型,以及新的弧線樣式。 - 注意:即使未遷移至新 API,您也可以使用其中部分功能。

建議

  • 同時遷移所有資訊方塊。請避免在應用程式中混用圖塊版本。雖然 Material 3 元件位於個別構件 (androidx.wear.protolayout:protolayout-material3) 中,因此在同一個應用程式中同時使用 M2.5 和 M3 圖塊在技術上是可行的,但除非絕對必要,否則我們強烈建議您不要這麼做 (例如,如果您的應用程式有大量無法一次遷移的圖塊)。
  • 採用資訊方塊使用者體驗指南。由於資訊方塊具有高度結構化和範本化的特性,請使用現有範例中的設計,做為您自有設計的起點。
  • 針對各種螢幕和字型大小進行測試。資訊方塊通常含有大量資訊,因此文字 (尤其是放在按鈕上時) 很容易溢出和裁剪。為盡量減少這類問題,請使用預先建構的元件,並避免進行大量自訂。使用 Android Studio 的資訊方塊預覽功能和多部實際裝置進行測試。

遷移程序

更新依附元件

首先,請更新 build.gradle.kts 檔案。更新版本,並將 protolayout-material 依附元件變更為 protolayout-material3,如下所示:

// In build.gradle.kts

//val tilesVersion = "1.4.1"
//val protoLayoutVersion = "1.2.1"

// Use these versions for M3.
val tilesVersion = "1.5.0-rc01"
val protoLayoutVersion = "1.3.0-rc01"

 dependencies {
     // Use to implement support for wear tiles
     implementation("androidx.wear.tiles:tiles:$tilesVersion")

     // Use to utilize standard components and layouts in your tiles
     implementation("androidx.wear.protolayout:protolayout:$protoLayoutVersion")

     // Use to utilize components and layouts with Material Design in your tiles
     // implementation("androidx.wear.protolayout:protolayout-material:$protoLayoutVersion")
     implementation("androidx.wear.protolayout:protolayout-material3:$protoLayoutVersion")

     // Use to include dynamic expressions in your tiles
     implementation("androidx.wear.protolayout:protolayout-expression:$protoLayoutVersion")

     // Use to preview wear tiles in your own app
     debugImplementation("androidx.wear.tiles:tiles-renderer:$tilesVersion")

     // Use to fetch tiles from a tile provider in your tests
     testImplementation("androidx.wear.tiles:tiles-testing:$tilesVersion")
 }

TileService 幾乎沒有變動

這項遷移作業的主要變更會影響 UI 元件。因此,您不需要或只需稍微修改 TileService 實作項目 (包括任何資源載入機制)。

主要例外狀況涉及資訊方塊活動追蹤:如果您的應用程式使用 onTileEnterEvent()onTileLeaveEvent(),則應遷移至 onRecentInteractionEventsAsync()。自 API 36 起,這些事件將以批次方式處理。

調整版面配置產生程式碼

在 ProtoLayout 1.2 (M2.5) 中,onTileRequest() 方法會傳回 TileBuilders.Tile。這個物件包含各種元素,包括 TimelineBuilders.Timeline,而後者則會保留描述資訊方塊 UI 的 LayoutElement

在 ProtoLayout 1.3 (M3) 中,雖然整體資料結構和流程並未改變,但 LayoutElement 現在是使用 Compose 啟發的做法建構,其中版面配置會根據定義的空格 (從上到下) 建構,分別是 titleSlot (通常用於主要標題或標頭)、mainSlot (用於核心內容) 和 bottomSlot (通常用於邊緣按鈕等動作或簡短文字等補充資訊)。這個版面配置是由 primaryLayout() 函式建構。

顯示 mainSlot、titleSlot、bottomSlot 的動態磚版面配置
圖 1.:資訊方塊的空格。
比較 M2.5 版面配置和 M3 版面配置函式

M2.5

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters
) =
    PrimaryLayout.Builder(deviceConfiguration)
        .setResponsiveContentInsetEnabled(true)
        .setContent(
            Text.Builder(context, "Hello World!")
                .setTypography(Typography.TYPOGRAPHY_BODY1)
                .setColor(argb(0xFFFFFFFF.toInt()))
                .build()
        )
        .build()

M3

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
) =
    materialScope(context, deviceConfiguration) {
        primaryLayout(mainSlot = { text("Hello, World!".layoutString) })
    }

以下是兩者的主要差異:

  1. 建構工具的淘汰。Material3 UI 元件的傳統建構函式模式已改為更具宣告性的 Compose 架構語法。(String/Color/Modifiers 等非 UI 元件也會取得新的 Kotlin 包裝函式)。
  2. 標準化初始化和版面配置功能。M3 版面配置會依賴標準化的初始化和結構函式:materialScope()primaryLayout()。這些必要函式會初始化 M3 環境 (主題設定、透過 materialScope 的元件範圍),並定義以主要版位為基礎的版面配置 (透過 primaryLayout)。每個版面配置都必須呼叫這兩個函式一次。

主題設定

顏色

Material 3 Expressive 的一大特色是「動態主題設定」方塊,啟用這項功能 (預設為開啟) 後,系統提供的主題會顯示在方塊中 (可用性取決於使用者的裝置和設定)。

M3 的另一項變更是擴充顏色符記數量,從 4 增加到 29。新的色彩符記可在 ColorScheme 類別中找到。

Typography

與 M2.5 類似,M3 也大量依賴預先定義的字型大小常數,因此不建議直接指定字型大小。這些常數位於 Typography 類別中,提供稍微擴充的範圍,可提供更具表達力的選項。

如需完整詳細資訊,請參閱字體排版說明文件

形狀

大多數 M3 元件可依形狀和顏色維度變化。

形狀為 fulltextButton (位於 mainSlot 中):

使用「full」形狀的圖塊 (圓角更多)
圖 2.:使用「full」形狀的圖塊

同一個 textButton,形狀為 small

使用「小」形狀的圖塊 (圓角較少)
圖 3.:形狀為「small」的資訊方塊

元件

M3 元件比 M2.5 元件更具彈性,也更容易設定。在 M2.5 中,為處理各種視覺效果,通常需要使用不同的元件,但 M3 經常會採用通用且可高度設定的「基礎」元件,並提供良好的預設值。

這個原則適用於「根」版面配置。在 M2.5 中,這會是 PrimaryLayoutEdgeContentLayout。在 M3 中,建立單一頂層 MaterialScope 後,系統會呼叫 primaryLayout() 函式。這個方法會直接傳回根版面配置 (不需要建構工具),並接受 LayoutElements 的多個「版位」,例如 titleSlotmainSlotbottomSlot。這些版位可填入具體的 UI 元件,例如 text()button()card() 所傳回的內容,或是版面配置結構,例如 LayoutElementBuilders 中的 RowColumn

主題是 M3 的另一項重要增強功能。根據預設,UI 元素會自動遵循 M3 樣式規格,並支援動態主題設定。

M2.5 M3
互動式元素
ButtonChip
Text
Text text()
進度指標
CircularProgressIndicator circularProgressIndicator()segmentedCircularProgressIndicator()
版面配置
PrimaryLayoutEdgeContentLayout primaryLayout()
buttonGroup()
圖片
icon()avatarImage()backgroundImage()

修飾符

在 M3 中,用於裝飾或擴充元件的 Modifiers 更類似 Compose。這項變更可自動建構適當的內部類型,以減少固定格式。(這項變更與 M3 UI 元件的使用方式無關;如有需要,您可以使用 ProtoLayout 1.2 中的建構工具樣式修飾符搭配 M3 UI 元件,反之亦然)。

M2.5

// A Builder-style modifier to set the opacity of an element to 0.5
fun myModifier(): ModifiersBuilders.Modifiers =
    ModifiersBuilders.Modifiers.Builder()
        .setOpacity(TypeBuilders.FloatProp.Builder(0.5F).build())
        .build()

M3

// The equivalent Compose-like modifier is much simpler
fun myModifier(): LayoutModifier = LayoutModifier.opacity(0.5F)

您可以使用任一種 API 樣式建構修飾符,也可以使用 toProtoLayoutModifiers() 擴充功能函式將 LayoutModifier 轉換為 ModifiersBuilders.Modifier

輔助函式

雖然 ProtoLayout 1.3 允許許多 UI 元件使用 Compose 風格的 API 表達,但 LayoutElementBuilders 中的rowscolumns等基礎版面配置元素仍會繼續使用建構函式模式。為彌補這種風格差異,並提升與新 M3 元件 API 的一致性,建議您使用輔助函式。

不含輔助程式

primaryLayout(
    mainSlot = {
        LayoutElementBuilders.Column.Builder()
            .setWidth(expand())
            .setHeight(expand())
            .addContent(text("A".layoutString))
            .addContent(text("B".layoutString))
            .addContent(text("C".layoutString))
            .build()
    }
)

使用 Helpers

// Function literal with receiver helper function
fun column(builder: Column.Builder.() -> Unit) =
    Column.Builder().apply(builder).build()

primaryLayout(
    mainSlot = {
        column {
            setWidth(expand())
            setHeight(expand())
            addContent(text("A".layoutString))
            addContent(text("B".layoutString))
            addContent(text("C".layoutString))
        }
    }
)

遷移至 Tiles 1.2 / ProtoLayout 1.0

自 1.2 版起,大多數的資訊方塊版面配置 API 都位於 androidx.wear.protolayout 命名空間中。如要使用最新的 API,請完成下列程式碼遷移步驟。

更新依附元件

在應用程式模組的建構檔案中進行下列變更:

Groovy

  // Remove
  implementation 'androidx.wear.tiles:tiles-material:version'

  // Include additional dependencies
  implementation "androidx.wear.protolayout:protolayout:1.2.1"
  implementation "androidx.wear.protolayout:protolayout-material:1.2.1"
  implementation "androidx.wear.protolayout:protolayout-expression:1.2.1"

  // Update
  implementation "androidx.wear.tiles:tiles:1.4.1"

Kotlin

  // Remove
  implementation("androidx.wear.tiles:tiles-material:version")

  // Include additional dependencies
  implementation("androidx.wear.protolayout:protolayout:1.2.1")
  implementation("androidx.wear.protolayout:protolayout-material:1.2.1")
  implementation("androidx.wear.protolayout:protolayout-expression:1.2.1")

  // Update
  implementation("androidx.wear.tiles:tiles:1.4.1")

更新命名空間

在應用程式的 Kotlin 和 Java 程式碼檔案中進行下列更新。或者,您也可以執行這段命名空間重新命名指令碼

  1. 將所有的 androidx.wear.tiles.material.* 匯入項目替換為 androidx.wear.protolayout.material.*。請同時為 androidx.wear.tiles.material.layouts 程式庫完成這個步驟。
  2. 將大多數其他 androidx.wear.tiles.* 匯入項目替換為 androidx.wear.protolayout.*

    androidx.wear.tiles.EventBuildersandroidx.wear.tiles.RequestBuildersandroidx.wear.tiles.TileBuildersandroidx.wear.tiles.TileService 的匯入項目應維持不變。

  3. 重新命名 TileService 和 TileBuilder 類別的幾個已淘汰的方法:

    1. TileBuilders:將 getTimeline() 重新命名為 getTileTimeline()setTimeline() 重新命名為 setTileTimeline()
    2. TileService:將 onResourcesRequest() 重新命名為 onTileResourcesRequest()
    3. RequestBuilders.TileRequest:將 getDeviceParameters() 重新命名為 getDeviceConfiguration()setDeviceParameters() 重新命名為 setDeviceConfiguration()getState() 重新命名為 getCurrentState(),以及 setState() 重新命名為 setCurrentState()