mcpField
W
wear-widgets

wear-widgets

github.com/android開発10.0k208 回インストール2 日前に更新
リポジトリ

wear-widgets について

Glance Wear と Remote Compose を使った Wear OS ウィジェットの作成や移行を支援する、Android 開発者向けスキルです。サービス登録、アダプティブレイアウト、リモート状態と操作、プレビュー、ピッカー用素材を扱います。

主な機能

  1. 01Glance Wear ウィジェットの設定
  2. 02Remote Compose のアダプティブレイアウト
  3. 03リモート状態とクリック操作
  4. 04ウィジェットのプレビューとピッカー画像
  5. 05旧タイルからの移行ガイド

活用シーン

  1. 01Wear OS ウィジェットの作成
  2. 02旧 Wear OS タイルの移行
  3. 03ウィジェットのプレビューとピッカー素材の追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/android/skills --skill wear-widgets

インストール後、Claude Code で/wear-widgetsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
previews-and-testing.md
remote-compose-layouts.md
state-and-actions.md
widget-service-and-manifest.md

詳細

翻訳後に原文が更新されています。最新の内容は原文をご確認ください。

Wear OS ウィジェットでは、androidx.compose.remote(Remote Compose)とともに androidx.glance.wear(GlanceWearWidget および GlanceWearWidgetService)を使用します。 宣言型 UI と状態のドキュメントをシリアライズして、ウォッチのホストプロセスに送信します。

前提条件とセットアップ

  1. ライブラリのバージョンを解決する:{GLANCE_WEAR_VERSION}(androidx.glance.wear)、{COMPOSE_REMOTE_VERSION}(androidx.compose.remote)、{WEAR_COMPOSE_REMOTE_VERSION}(androidx.wear.compose.remote)の最新バージョンを解決します。安定版がまだない場合は、-alpha、-beta、または -rc リリースも含めます。バージョン解決のために ./gradlew dependencies を実行しないでください。
  2. SDK と Compose コンパイラの要件:ユーザーがウィジェットの作成、タイルの移行、または依存関係のセットアップを依頼していない限り、リポジトリ全体に適用される Gradle ファイルを変更する前に許可を求めます。compileSdk = 37 以上を設定し、buildFeatures { compose = true } を有効にします。プロジェクト既存の Android および Kotlin Gradle プラグインの宣言はそのまま維持します。

dependencies {
    implementation("androidx.glance.wear:wear:{GLANCE_WEAR_VERSION}")
    implementation("androidx.glance.wear:wear-core:{GLANCE_WEAR_VERSION}")
    implementation("androidx.glance.wear:wear-tooling-preview:{GLANCE_WEAR_VERSION}")
    implementation("androidx.compose.remote:remote-creation-compose:{COMPOSE_REMOTE_VERSION}")
    implementation("androidx.compose.remote:remote-creation:{COMPOSE_REMOTE_VERSION}")
    implementation("androidx.compose.remote:remote-core:{COMPOSE_REMOTE_VERSION}")
    implementation("androidx.compose.remote:remote-tooling-preview:{COMPOSE_REMOTE_VERSION}")
    implementation("androidx.wear.compose.remote:remote-material3:{WEAR_COMPOSE_REMOTE_VERSION}")
}

コードベースの調査

  1. モジュール内で、既存の TileService、Material3TileService、または GlanceWearWidget の実装、app/src/main/AndroidManifest.xml 内の <service> エントリ、および app/src/main/res/ 配下の @drawable/ プレビューアセットを検索します。
  2. 既存のタイルを移行する場合、または構成を把握していないマルチモジュールプロジェクトを変更する場合は、./gradlew :app:assembleDebug を実行して、変更前のビルド状態を確認します。

ワークフロー

ステップ 1:AndroidManifest.xml とプロバイダー XML を設定する

BIND_TILE_PROVIDER 権限と BIND_WIDGET_PROVIDER インテントアクションを指定して、 GlanceWearWidgetService のサブクラスを app/src/main/AndroidManifest.xml に登録します。SMALL と LARGE の <container> エントリを含む @xml/ の <wearwidget-provider> リソースを指す <meta-data> を追加します。サービス、プロバイダー XML、または従来の TileService の移行を設定する際は、必ず ウィジェットサービスとマニフェストのリファレンス に従ってください。


<service
  android:name=".MyWidgetService"
  android:exported="true"
  android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"
  >
  <intent-filter>
    <action android:name="androidx.glance.wear.action.BIND_WIDGET_PROVIDER" />
  </intent-filter>
  <meta-data
    android:name="androidx.glance.wear.widget.provider"
    android:resource="@xml/my_widget_info" />
</service>
ステップ 2:GlanceWearWidget と GlanceWearWidgetService を実装する

GlanceWearWidget を拡張し、WearWidgetDocument を返す provideWidgetData をオーバーライドします。静的なプロバイダー解決のため、 GlanceWearWidgetService のサブクラスに @AssociateWithGlanceWearWidget を付与します。


// 誤り:モバイル向け GlanceAppWidget API(Wear OS では使用しないでください)
class BrokenWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {}
}

// 正しい例:Wear OS の GlanceWearWidget + GlanceWearWidgetService
@AssociateWithGlanceWearWidget(MyWidget::class)
class MyWidgetService : GlanceWearWidgetService() {
    override val widget: GlanceWearWidget = MyWidget()
}

class MyWidget : GlanceWearWidget() {
    override suspend fun provideWidgetData(
        context: Context,
        params: WearWidgetParams,
    ): WearWidgetData = WearWidgetDocument(
        background = WearWidgetBrush.color(Color(0xFF1C1B1F).rc)
    ) {
        MyWidgetContent(params = params)
    }
}
ステップ 3:Remote Compose のレイアウト、状態、アクションを構築する

Remote Compose は、アプリのプロセスではなく Wear OS ホストのプロセス内で UI と状態を評価します。アダプティブレイアウトや画面全体に広がる背景を構築する場合は、必ず Remote Compose レイアウトのリファレンスに従ってください。状態やクリックアクションを実装する場合は、必ず 状態とアクションのリファレンスに従ってください。

  • Remote の値ラッパー:.rs(RemoteString)、.rc(RemoteColor)、.rdp(RemoteDp)、.ri(RemoteInt)を使ってプリミティブ値を変換します。整数の書式設定には、RemoteInt.toRemoteString メンバーメソッドを使います。
  • アダプティブなコンテナーサイズ:params.containerType(ContainerInfo.CONTAINER_TYPE_SMALL と ContainerInfo.CONTAINER_TYPE_LARGE)に応じて、レイアウト密度、タイポグラフィ、項目数を切り替えます。
  • マスクされない画面全体に広がる背景:ルートの RemoteBox(RemoteModifier.fillMaxSize)内で RemoteImage と RemoteImageBitmap(bitmap.asImageBitmap)を使って背景ビットマップを描画します。cornerRadius = 0dp を指定し、CircleShape や RoundedCornerShape でクリッピングせず、背景アートワークをマスクしないでください。ホストが端をウォッチの形状に合わせてクリッピングします。
  • 宣言的なホスト状態と PendingIntent アクション:メモリ内の Compose 状態(mutableStateOf や mutableIntStateOf)ではなく、rememberMutableRemoteInt と valueChange(state, newValue) を使ってウィジェットのローカル状態を変更します。pendingIntentAction { ctx -> ... }(常に (Context) -> PendingIntent ラムダを渡します)を使って、アクティビティの起動やバックグラウンドブロードキャストを実行します。widget.triggerUpdateAll(context) を使って、アクティブなウィジェットを更新します。
ステップ 4:WearWidgetPreview 関数とピッカープレビュー PNG を追加する
  1. コンポーザブルの境界線プレビュー(androidx.glance.wear.tooling.preview):androidx.glance.wear.tooling.preview から WearWidgetPreview、SquircleAllWidgetPreviewParams、RoundAllWidgetPreviewParams、RectangularAllWidgetPreviewParams をインポートします(androidx.glance.wear.testing は絶対に使用しないでください)。WearWidgetPreview(widget, params) を呼び出す @Preview 関数を定義します。
  2. 長方形のピッカー PNG(res/drawable-nodpi/):320 dpi で RectangularAllWidgetPreviewParams を使うか、プロバイダー XML 内のすべての <container> に対して、空白ではなくマスクされていない長方形の PNG を作成します。
    • SMALL(CONTAINER_TYPE_SMALL):448x168 px(320 dpi で 224x84 dp、アスペクト比 2.67)。
    • LARGE(CONTAINER_TYPE_LARGE):464x288 px(320 dpi で 232x144 dp、アスペクト比 1.61)。
    • 各プレビュー PNG には、背景、テキストラベル、アイコン、アバターのイニシャル、ボタンなど、ウィジェットの実際の UI 要素を必ず描画してください。空白のプレースホルダー、ラベルのない空の図形、1:1 のタイルプレビューは絶対に使用しないでください。コンポーザブルプレビュー、ピッカー PNG、ユニットテストを追加する場合は、必ずプレビューとテストのリファレンスに従ってください。

コンポーネントの対応関係

次のサンプル表を使って、実装パターンとインポートの全体を確認してください。

機能または API サーフェスリファレンスガイド
GlanceWearWidget、GlanceWearWidgetService、AndroidManifest.xml、<wearwidget-provider>、レガシーな TileService からの移行ウィジェットサービスとマニフェストのリファレンス
RemoteBox、RemoteColumn、RemoteRow、RemoteText、RemoteImage、ContainerInfo(SMALL と LARGE のアダプティブレイアウト)Remote Compose レイアウトのリファレンス
RemoteButton、rememberMutableRemoteInt、valueChange、pendingIntentAction、BroadcastReceiver、triggerUpdateAll状態とアクションのリファレンス
WearWidgetPreview、SquircleAllWidgetPreviewParams、RoundAllWidgetPreviewParams、RectangularAllWidgetPreviewParams、ピッカー用 PNG、captureRawContent テストプレビューとテストのリファレンス
レガシーな ProtoLayout とモバイル版 Glance の対応 API
レガシー API またはモバイル APIWear OS ウィジェット API対応内容
androidx.wear.tiles.TileServiceGlanceWearWidgetService + GlanceWearWidgetサービスを置き換え、@AssociateWithGlanceWearWidget を付与します。
GlanceAppWidget / provideGlanceGlanceWearWidget / provideWidgetDataprovideWidgetData から WearWidgetDocument を返します。
LayoutElementBuilders / primaryLayoutRemoteColumn、RemoteRow、RemoteBox@RemoteComposable 関数でレイアウトを構築します。
mutableStateOf / mutableIntStateOfrememberMutableRemoteInt + valueChangevalueChange を使って、リモート状態を宣言的に変更します。
ModifiersBuilders.ClickableRemoteModifier.clickable(pendingIntentAction { ... })(Context) -> PendingIntent ラムダを pendingIntentAction に渡します。

トラブルシューティング

症状原因修正方法
GlanceWearWidget の参照を解決できないandroidx.glance.wear:wear:{GLANCE_WEAR_VERSION} がない、または compileSdk が古いcompileSdk = 37 を設定し、androidx.glance.wear:wear:{GLANCE_WEAR_VERSION} を追加します。
toRemoteString の参照を解決できないtoRemoteString をトップレベルの拡張関数としてインポートしたインポートを削除し、メンバーメソッドとして remoteInt.toRemoteString を呼び出します。
pendingIntentAction で型が一致しないラムダではなく、PendingIntent をそのまま渡したラムダでラップします:pendingIntentAction { ctx -> pendingIntent }。
移行後に wear.tiles または protolayout の参照を解決できないモジュール内の他のクラスまたはソースセットが、まだレガシーなタイル API を使っているbuild.gradle.kts からレガシーな wear.tiles と protolayout の依存関係を削除する前に、残りの参照を移行または更新します。

検証

  1. ./gradlew :app:assembleDebug を実行し、ウィジェット、サービス、AndroidManifest.xml の宣言、および @xml/ の <wearwidget-provider> リソースがエラーなくコンパイルされ、リンクされることを確認します。
  2. プロジェクトにユニットテストまたは新しいウィジェットテストが含まれている場合は、./gradlew :app:testDebugUnitTest を実行し、すべてのテストが成功することを確認します。コンポーザブルのプレビュー、ピッカー用 PNG、またはユニットテストを追加する場合は、必ず プレビューとテストのリファレンス に従ってください。

アンチパターン

  • 絶対に、モバイル版の GlanceAppWidget または AppWidgetProvider を継承したり、Wear OS ウィジェットに非推奨の GlanceTileService または TileService を使ったりしないでください。
  • 絶対に、Remote Compose UI でメモリ内のクライアント Compose 状態(mutableStateOf、mutableIntStateOf)やプロセス内のクリックラムダを使わないでください。
  • 絶対に、PendingIntent インスタンスをそのまま pendingIntentAction に渡さないでください。必ず (Context) -> PendingIntent ラムダを渡してください。
  • ウィジェットの全面背景アートに CircleShape または RoundedCornerShape のクリッピングを絶対に適用しないでください。ウィジェットピッカー用 PNG に 1:1(400x400)のタイルプレビューや、単色の空のプレースホルダーを絶対に再利用しないでください。

ベストプラクティス

  • <service> に com.google.android.wearable.permission.BIND_TILE_PROVIDER と androidx.glance.wear.action.BIND_WIDGET_PROVIDER を宣言する必要があります。
  • ドメインに適した 448x168 および 464x288 の PNG を res/drawable-nodpi/ に配置し、@xml/ に SMALL と LARGE の <container> エントリーを宣言する必要があります。
  • レイアウトのコンテンツを params.containerType に合わせて調整し、SquircleAllWidgetPreviewParams と RoundAllWidgetPreviewParams の両方を対象とした @Preview 関数を含める必要があります。

コメント