タイルのバージョニング

Wear OS デバイスでは、タイルは独立したバージョニングを持つ 2 つの主要コンポーネントによってレンダリングされます。アプリのタイルがすべてのデバイスで正しく機能するようにするには、この基盤となるアーキテクチャを理解することが重要です。

  • Jetpack タイル関連のライブラリ: これらのライブラリ(Wear Tiles や Wear ProtoLayout など)はアプリに埋め込まれており、デベロッパーがバージョンを管理します。アプリは、これらのライブラリを使用して、システムの onTileRequest() 呼び出しに応答して TileBuilder.Tile オブジェクト(タイルを表すデータ構造)を作成します。
  • ProtoLayout レンダラ: このシステム コンポーネントは、ディスプレイに Tile オブジェクトをレンダリングし、ユーザー操作を処理します。レンダラ バージョンはアプリ デベロッパーによって制御されず、ハードウェアが同じデバイスでも異なる場合があります。

タイルの外観や動作は、アプリの Jetpack Tiles ライブラリのバージョンと、ユーザーのデバイスの ProtoLayout レンダラ バージョンの両方によって異なる場合があります。たとえば、あるデバイスでは回転や心拍数データの表示がサポートされている一方、別のデバイスではサポートされていない場合があります。

このドキュメントでは、アプリを Tiles ライブラリと 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 レンダラ アップデートは Google Play ストアまたはシステム アップデートによって配信されます。特定のレンダラ バージョンを強制的にインストールすることはできません)。

Android Studio のタイル プレビュー機能は、コードが依存する Jetpack ProtoLayout ライブラリに埋め込まれたレンダラを使用します。別の方法として、タイルをテストするときに異なる Jetpack ライブラリ バージョンに依存することもできます。

Tiles 1.5 / ProtoLayout 1.3(マテリアル 3 Expressive)に移行する

Jetpack Tile ライブラリを更新して、タイルをシステムとシームレスに統合するための UI の変更など、最新の機能強化を活用しましょう。

Jetpack Tiles 1.5 と Jetpack ProtoLayout 1.3 では、いくつかの重要な改善と変更が導入されています。次のものが含まれます。

  • UI を記述するための Compose のような API。
  • マテリアル 3 エクスプレッシブ コンポーネント: 下端を覆うエッジボタン、強化されたビジュアル(Lottie アニメーション、より多くのグラデーション タイプ、新しい円弧線スタイル)のサポートなど。 - 注: これらの機能の一部は、新しい API に移行しなくても使用できます。

推奨事項

  • すべてのタイルを同時に移行する。アプリ内でタイルのバージョンを混在させないでください。マテリアル 3 コンポーネントは別のアーティファクト(androidx.wear.protolayout:protolayout-material3)に存在するため、技術的には同じアプリで M2.5 タイルと M3 タイルの両方を使用できますが、絶対に必要な場合を除き、このアプローチは強くおすすめしません(たとえば、アプリに多数のタイルが含まれており、すべてを一度に移行できない場合など)。
  • タイルに関する UX ガイダンスを採用する。タイルは高度に構造化され、テンプレート化されているため、既存のサンプルのデザインを独自のデザインの出発点として使用してください。
  • さまざまな画面サイズとフォントサイズでテストします。タイルは多くの情報を詰め込むため、テキスト(特にボタンに配置する場合)がオーバーフローやクリッピングが発生しやすくなります。これを最小限に抑えるには、ビルド済みコンポーネントを使用し、大幅なカスタマイズを避けます。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. Builders の廃止。Material3 UI コンポーネントの従来のビルダー パターンは、より宣言的で Compose にインスパイアされた構文に置き換えられます。(String/Color/Modifier などの UI 以外のコンポーネントにも、新しい Kotlin ラッパーが追加されます)。
  2. 標準化された初期化関数とレイアウト関数。M3 レイアウトは、標準化された初期化関数と構造関数(materialScope()primaryLayout())に依存しています。これらの必須関数は、M3 環境(テーマ設定、materialScope によるコンポーネント スコープ)を初期化し、プライマリ スロットベースのレイアウトを定義します(primaryLayout を介して)。どちらも、レイアウトごとに 1 回だけ呼び出す必要があります。

テーマ設定

Material 3 Expressive の際立った機能は「動的テーマ設定」です。この機能を有効にするタイルは、システム提供のテーマで表示されます(利用できるテーマはユーザーのデバイスと設定によって異なります)。

M3 のもう 1 つの変更点は、カラートークンの数を 4 から 29 に増やしたことです。新しいカラー トークンは ColorScheme クラスにあります。

タイポグラフィ

M2.5 と同様に、M3 は事前定義されたフォントサイズ定数に大きく依存しています。フォントサイズを直接指定することは推奨されません。これらの定数は Typography クラスにあり、より表現力豊かなオプションの範囲が少し広がっています。

詳しくは、タイポグラフィのドキュメントをご覧ください。

シェイプ

ほとんどの M3 コンポーネントは、形状と色のディメンションに沿って変更できます。

形状が fulltextButtonmainSlot 内):

タイルの形状が「フル」の場合(角がより丸い)
図 2.: 形状が「フル」のタイル

形状が small の同じ textButton:

タイルの形状が「小さい」(角が丸くなく)
図 3.: 形状が「小さい」タイル

コンポーネント

M3 コンポーネントは、M2.5 コンポーネントよりも柔軟性が高く、構成が容易です。M2.5 では、さまざまな視覚効果に個別のコンポーネントが必要になることが多かったのに対し、M3 では、一般化された、高度に構成可能な「ベース」コンポーネントがよく使用され、デフォルトが適切に設定されています。

この原則は「ルート」レイアウトに適用されます。M2.5 では、これは PrimaryLayout または EdgeContentLayout でした。M3 では、単一のトップレベルの MaterialScope が確立された後、primaryLayout() 関数が呼び出されます。これはルート レイアウトを直接返します(ビルダーは不要)。titleSlotmainSlotbottomSlot などの複数の「スロット」に LayoutElements を受け入れます。これらのスロットには、text()button()card() によって返される具体的な UI コンポーネントや、LayoutElementBuildersRowColumn などのレイアウト構造を配置できます。

テーマは M3 のもう 1 つの重要な機能強化です。デフォルトでは、UI 要素は M3 スタイル設定仕様に自動的に準拠し、動的テーマ設定をサポートします。

M2.5 M3
インタラクティブな要素
Button / Chip
テキスト
Text text()
進行状況インジケーター
CircularProgressIndicator circularProgressIndicator() / segmentedCircularProgressIndicator()
レイアウト
PrimaryLayout / EdgeContentLayout 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() 拡張関数を使用して LayoutModifierModifiersBuilders.Modifier に変換することもできます。

ヘルパー関数

ProtoLayout 1.3 では、Compose にインスパイアされた API を使用して多くの UI コンポーネントを表現できますが、LayoutElementBuildersなどの基本的なレイアウト要素は引き続きビルダー パターンを使用します。このスタイルのギャップを埋めて、新しい M3 コンポーネント API との整合性を高めるには、ヘルパー関数の使用を検討してください。

ヘルパーなし

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

ヘルパーあり

// 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() に変更