Wear OS デバイスでは、タイルは独立したバージョン管理を持つ 2 つの主要なコンポーネントによってレンダリングされます。アプリのタイルがすべてのデバイスで正しく機能するようにするには、この基盤となるアーキテクチャを理解することが重要です。
- Jetpack タイル関連ライブラリ: これらのライブラリ(Wear Tiles や Wear ProtoLayout など)はアプリに埋め込まれており、デベロッパーがバージョンを管理します。アプリはこれらのライブラリを使用して、システムの
onTileRequest()
呼び出しに応答してTileBuilder.Tile
オブジェクト(タイルを表すデータ構造)を構築します。 - ProtoLayout レンダラ: このシステム コンポーネントは、ディスプレイに
Tile
オブジェクトをレンダリングし、ユーザー インタラクションを処理します。レンダラのバージョンはアプリ デベロッパーによって制御されず、ハードウェアが同一のデバイスでも異なる場合があります。
タイルの外観や動作は、アプリの Jetpack Tiles ライブラリのバージョンと、ユーザーのデバイスの ProtoLayout Renderer のバージョンの両方によって異なります。たとえば、あるデバイスは回転や心拍数データの表示をサポートしているが、別のデバイスはサポートしていない場合があります。
このドキュメントでは、アプリがさまざまなバージョンの Tiles ライブラリと ProtoLayout Renderer に対応していることを確認する方法と、より高い Jetpack ライブラリ バージョンに移行する方法について説明します。
互換性を考慮する
さまざまなデバイスで正しく機能するタイルを作成するには、さまざまな機能のサポートを考慮してください。これを行うには、主に次の 2 つの方法があります。ランタイムでレンダラ機能を検出する方法と、組み込みのフォールバックを提供する方法です。
レンダラの機能を検出する
特定のデバイスで利用可能な機能に基づいて、タイルのレイアウトを動的に変更できます。
レンダラのバージョンを検出する
- onTileRequest() メソッドに渡された
DeviceParameters
オブジェクトのgetRendererSchemaVersion()
メソッドを使用します。このメソッドは、デバイス上の ProtoLayout Renderer のメジャー バージョン番号とマイナー バージョン番号を返します。 - 検出されたレンダラ バージョンに基づいてタイルのデザインや動作を調整するには、
onTileRequest()
実装で条件付きロジックを使用します。
@RequiresSchemaVersion
アノテーション
- ProtoLayout メソッドの
@RequiresSchemaVersion
アノテーションは、そのメソッドがドキュメントに記載されているとおりに動作するために必要な最小レンダラ スキーマ バージョンを示します(例)。- デバイスで利用可能なレンダラ バージョンよりも高いバージョンを必要とするメソッドを呼び出しても、アプリがクラッシュすることはありませんが、コンテンツが表示されなかったり、機能が無視されたりする可能性があります。
バージョン検出の例
val rendererVersion = requestParams.deviceConfiguration.rendererSchemaVersion val arcElement = // DashedArcLine has the annotation @RequiresSchemaVersion(major = 1, minor = 500) // and so is supported by renderer versions 1.500 and greater if ( rendererVersion.major > 1 || (rendererVersion.major == 1 && rendererVersion.minor >= 500) ) { // Use DashedArcLine if the renderer supports it … DashedArcLine.Builder() .setLength(degrees(270f)) .setThickness(8f) .setLinePattern( LayoutElementBuilders.DashedLinePattern.Builder() .setGapSize(8f) .setGapInterval(10f) .build() ) .build() } else { // … otherwise use ArcLine. ArcLine.Builder().setLength(degrees(270f)).setThickness(dp(8f)).build() }
フォールバックを提供する
一部のリソースでは、ビルダーで直接フォールバックを定義できます。これは、レンダラ バージョンを確認するよりも簡単なことが多く、利用可能な場合は推奨されるアプローチです。
一般的なユースケースは、Lottie アニメーションのフォールバックとして静止画像を提供することです。デバイスが Lottie アニメーションをサポートしていない場合は、代わりに静止画像がレンダリングされます。
val lottieImage = ResourceBuilders.ImageResource.Builder() .setAndroidLottieResourceByResId( ResourceBuilders.AndroidLottieResourceByResId.Builder(R.raw.lottie) .setStartTrigger(createOnVisibleTrigger()) .build() ) // Fallback if lottie is not supported .setAndroidResourceByResId( ResourceBuilders.AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.lottie_fallback) .build() ) .build()
さまざまなレンダラ バージョンでテストする
さまざまなレンダラ バージョンに対してタイルをテストするには、Wear OS エミュレータのさまざまなバージョンにタイルをデプロイします。(実機では、ProtoLayout Renderer のアップデートは Google Play ストアまたはシステム アップデートによって配信されます。特定のレンダラ バージョンのインストールを強制することはできません)。
Android Studio のタイル プレビュー機能は、コードが依存する Jetpack ProtoLayout ライブラリに埋め込まれたレンダラを使用します。そのため、別の方法として、タイルをテストする際に異なる Jetpack ライブラリ バージョンに依存することもできます。
Tiles 1.5 / ProtoLayout 1.3(マテリアル 3 エクスプレッシブ)に移行する
Jetpack Tile ライブラリを更新して、タイルをシステムとシームレスに統合するための 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 タイルの両方を使用できますが、どうしても必要な場合(アプリに多数のタイルがあり、すべてを一度に移行できない場合など)を除き、このアプローチは強く推奨されません。 - タイル 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
を含むさまざまな要素が含まれていました。この TimelineBuilders.Timeline
には、タイルの UI を記述する LayoutElement
が含まれていました。
ProtoLayout 1.3(M3)では、データ構造とフロー全体は変更されていませんが、LayoutElement
は、定義されたスロットに基づくレイアウトで、Compose にインスパイアされたアプローチを使用して構築されるようになりました。スロットは(上から下へ)titleSlot
(省略可。通常はメインのタイトルまたはヘッダー用)、mainSlot
(必須。コア コンテンツ用)、bottomSlot
(省略可。多くの場合、エッジボタンなどのアクションや、短いテキストなどの補足情報用)です。このレイアウトは primaryLayout()
関数によって構築されます。

レイアウト 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) })
}
主な違いをまとめると次のようになります。
- Builders の廃止。Material3 UI コンポーネントの従来のビルダー パターンは、より宣言的な Compose 風の構文に置き換えられます。(String、Color、Modifiers などの UI 以外のコンポーネントにも新しい Kotlin ラッパーが追加されます)。
- 標準化された初期化関数とレイアウト関数。M3 レイアウトは、標準化された初期化関数と構造関数(
materialScope()
とprimaryLayout()
)に依存しています。これらの必須関数は、M3 環境(テーマ設定、materialScope
によるコンポーネント スコープ)を初期化し、プライマリ スロットベースのレイアウト(primaryLayout
による)を定義します。どちらもレイアウトごとに 1 回だけ呼び出す必要があります。
テーマ設定
色
Material 3 Expressive の特徴的な機能は「動的テーマ設定」です。この機能を有効にするタイル(デフォルトでオン)は、システム提供のテーマで表示されます(利用可能かどうかはユーザーのデバイスと構成によって異なります)。
M3 では、カラー トークンの数も 4 から 29 に増えました。新しいカラー トークンは ColorScheme
クラスにあります。
タイポグラフィ
M2.5 と同様に、M3 は定義済みのフォントサイズ定数に大きく依存しています。フォントサイズを直接指定することは推奨されません。これらの定数は Typography
クラスにあり、より表現力豊かなオプションの範囲をわずかに拡大します。
詳しくは、タイポグラフィのドキュメントをご覧ください。
シェイプ
ほとんどの M3 コンポーネントは、色だけでなく形状のディメンションも変更できます。
形状 full
の textButton
(mainSlot
内):

形状 small
の同じ textButton:

コンポーネント
M3 コンポーネントは、M2.5 の同等のコンポーネントよりも柔軟性が高く、構成の自由度も高くなっています。M2.5 では、さまざまなビジュアル トリートメントに個別のコンポーネントが必要になることが多かったのに対し、M3 では、優れたデフォルトを備えた汎用性の高い構成可能な「ベース」コンポーネントが頻繁に使用されます。
この原則は「ルート」レイアウトに適用されます。M2.5 では、これは PrimaryLayout
または EdgeContentLayout
のいずれかでした。M3 では、単一の最上位 MaterialScope
が確立された後、primaryLayout()
関数が呼び出されます。これにより、ルート レイアウトが直接返され(ビルダーは不要)、titleSlot
、mainSlot
、bottomSlot
などの複数の「スロット」に LayoutElements
が渡されます。これらのスロットには、text()、button()、card() などから返される具体的な UI コンポーネントや、LayoutElementBuilders
の Row
や Column
などのレイアウト構造を設定できます。
テーマは、M3 のもう一つの重要な機能強化です。デフォルトでは、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()
拡張関数を使用して LayoutModifier
を ModifiersBuilders.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
// Removeimplementation 'androidx.wear.tiles:tiles-material:version'// Include additional dependencies implementation "androidx.wear.protolayout:protolayout:1.3.0" implementation "androidx.wear.protolayout:protolayout-material:1.3.0" implementation "androidx.wear.protolayout:protolayout-expression:1.3.0" // Update implementation "androidx.wear.tiles:tiles:1.5.0"
Kotlin
// Removeimplementation("androidx.wear.tiles:tiles-material:version")// Include additional dependencies implementation("androidx.wear.protolayout:protolayout:1.3.0") implementation("androidx.wear.protolayout:protolayout-material:1.3.0") implementation("androidx.wear.protolayout:protolayout-expression:1.3.0") // Update implementation("androidx.wear.tiles:tiles:1.5.0")
名前空間を更新する
アプリの Kotlin ベースと Java ベースのコードファイルを次のように更新します。または、こちらの名前空間名変更スクリプトを実行することもできます。
- すべての
androidx.wear.tiles.material.*
インポートをandroidx.wear.protolayout.material.*
に置き換えます。androidx.wear.tiles.material.layouts
ライブラリでもこのステップを実行します。 他の
androidx.wear.tiles.*
インポートのほとんどをandroidx.wear.protolayout.*
に置き換えます。androidx.wear.tiles.EventBuilders
、androidx.wear.tiles.RequestBuilders
、androidx.wear.tiles.TileBuilders
、androidx.wear.tiles.TileService
のインポートはそのままにします。TileService クラスと TileBuilder クラスの非推奨のメソッドの名前を変更します。
TileBuilders
:getTimeline()
からgetTileTimeline()
、setTimeline()
からsetTileTimeline()
に変更TileService
:onResourcesRequest()
からonTileResourcesRequest()
に変更RequestBuilders.TileRequest
:getDeviceParameters()
からgetDeviceConfiguration()
、setDeviceParameters()
からsetDeviceConfiguration()
、getState()
からgetCurrentState()
、setState()
からsetCurrentState()
に変更