wear-widgets

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
Wear OS widgets use
androidx.glance.wear
(
GlanceWearWidget
and
GlanceWearWidgetService
) with
androidx.compose.remote
(Remote Compose). They serialize declarative UI and state documents to the watch host process.
Wear OS 小组件使用
androidx.glance.wear
(
GlanceWearWidget
和
GlanceWearWidgetService
)与
androidx.compose.remote
(Remote Compose)。 它们会将声明式 UI 和状态文档序列化后发送到手表宿主进程。

Prerequisites and setup

前提条件与设置

  1. Resolve library versions : Resolve the latest versions for
    {GLANCE_WEAR_VERSION}
    (
    androidx.glance.wear
    ),
    {COMPOSE_REMOTE_VERSION}
    (
    androidx.compose.remote
    ), and
    {WEAR_COMPOSE_REMOTE_VERSION}
    (
    androidx.wear.compose.remote
    ). Include
    -alpha
    ,
    -beta
    , or
    -rc
    releases when no stable version exists yet. Don't run
    ./gradlew dependencies
    to resolve versions:
  2. SDK and Compose compiler requirements : Ask permission before modifying repo-wide Gradle files unless the user requested widget creation, tile migration, or dependency setup. Set
    compileSdk = 37
    or higher and enable
    buildFeatures { compose = true }
    . Keep the project's existing Android and Kotlin Gradle plugin declarations intact.
    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. 解析库版本:解析
    {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 compiler 要求:除非用户已要求创建小组件、迁移磁贴或配置依赖项,否则在修改仓库级 Gradle 文件前必须征得许可。将
    compileSdk
    设置为
    37
    或更高版本,并启用
    buildFeatures { compose = true }
    。保持项目中现有的 Android 和 Kotlin Gradle plugin 声明不变。
    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}") }

Codebase exploration

代码库探索

  1. Search the module for existing
    TileService
    ,
    Material3TileService
    , or
    GlanceWearWidget
    implementations,
    <service>
    entries in
    app/src/main/AndroidManifest.xml
    , and
    @drawable/
    preview assets under
    app/src/main/res/
    .
  2. When migrating an existing tile or modifying an unfamiliar multi-module project, run
    ./gradlew :app:assembleDebug
    to verify baseline build health.
  1. 在模块中搜索现有的
    TileService
    、
    Material3TileService
    或
    GlanceWearWidget
    实现、
    app/src/main/AndroidManifest.xml
    中的
    <service>
    条目,以及
    app/src/main/res/
    下
    @drawable/
    目录中的预览资源。
  2. 迁移现有磁贴或修改不熟悉的多模块项目时,运行
    ./gradlew :app:assembleDebug
    ,验证基线构建状态。

Workflow

工作流

Step 1: Configure AndroidManifest.xml and provider XML

第 1 步:配置 AndroidManifest.xml 和 provider XML

Register the
GlanceWearWidgetService
subclass in
app/src/main/AndroidManifest.xml
with the
BIND_TILE_PROVIDER
permission and
BIND_WIDGET_PROVIDER
intent action. Attach
<meta-data>
pointing to an
@xml/
<wearwidget-provider>
resource with
SMALL
and
LARGE
<container>
entries. When configuring the service, provider XML, or legacy
TileService
migration, you MUST follow Widget service and manifest reference.
xml
<service
    android:name=".snippets.widget.skill.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>
在
app/src/main/AndroidManifest.xml
中注册
GlanceWearWidgetService
子类,并为其配置
BIND_TILE_PROVIDER
权限和
BIND_WIDGET_PROVIDER
intent action。附加
<meta-data>
,使其指向包含
SMALL
和
LARGE
<container>
条目的
@xml/
<wearwidget-provider>
资源。配置 service、provider XML 或迁移旧版
TileService
时,必须遵循小组件 service 与 manifest 参考文档。
xml
<service
    android:name=".snippets.widget.skill.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>

Step 2: Implement GlanceWearWidget and GlanceWearWidgetService

第 2 步:实现 GlanceWearWidget 和 GlanceWearWidgetService

Extend
GlanceWearWidget
and override
provideWidgetData
returning
WearWidgetDocument
. Annotate the
GlanceWearWidgetService
subclass with
@AssociateWithGlanceWearWidget
for static provider resolution:
kotlin
// WRONG: Mobile GlanceAppWidget API (don't use on Wear OS)
class BrokenWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {}
}

// CORRECT: 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)
        }
}
继承
GlanceWearWidget
并重写
provideWidgetData
,返回
WearWidgetDocument
。为
GlanceWearWidgetService
子类添加
@AssociateWithGlanceWearWidget
注解,以进行静态 provider 解析:
kotlin
// WRONG: Mobile GlanceAppWidget API (don't use on Wear OS)
class BrokenWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {}
}

// CORRECT: 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)
        }
}

Step 3: Build Remote Compose layouts, state, and actions

第 3 步:构建 Remote Compose 布局、状态和操作

Remote Compose evaluates UI and state inside the Wear OS host process rather than the app process. When building adaptive layouts or full-bleed backgrounds, you MUST follow Remote Compose layouts reference. When implementing state or click actions, you MUST follow State and actions reference.
  • Remote value wrappers : Convert primitives using
    .rs
    (
    RemoteString
    ),
    .rc
    (
    RemoteColor
    ),
    .rdp
    (
    RemoteDp
    ), and
    .ri
    (
    RemoteInt
    ). Format integers with the
    RemoteInt.toRemoteString
    member method.
  • Adaptive container sizing : Branch layout density, typography, and item counts on
    params.containerType
    (
    ContainerInfo.CONTAINER_TYPE_SMALL
    versus
    ContainerInfo.CONTAINER_TYPE_LARGE
    ).
  • Unmasked full-bleed backgrounds : Render background bitmaps inside a root
    RemoteBox
    (
    RemoteModifier.fillMaxSize
    ) using
    RemoteImage
    and
    RemoteImageBitmap
    (
    bitmap.asImageBitmap
    ). Keep background artwork unmasked (
    cornerRadius = 0dp
    ) without
    CircleShape
    or
    RoundedCornerShape
    clipping. The host clips edges to the watch shape.
  • Declarative host state and PendingIntent actions : Mutate local widget state with
    rememberMutableRemoteInt
    and
    valueChange(state, newValue)
    instead of in-memory Compose state (
    mutableStateOf
    or
    mutableIntStateOf
    ). Trigger activity launches or background broadcasts using
    pendingIntentAction { ctx -> ... }
    (always passing a
    (Context) -> PendingIntent
    lambda). Refresh active widgets with
    widget.triggerUpdateAll(context)
    .
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 操作:使用
    rememberMutableRemoteInt
    和
    valueChange(state, newValue)
    修改本地小组件状态,而不是使用内存中的 Compose 状态(
    mutableStateOf
    或
    mutableIntStateOf
    )。使用
    pendingIntentAction { ctx -> ... }
    触发 activity 启动或后台广播,并始终传入
    (Context) -> PendingIntent
    lambda。使用
    widget.triggerUpdateAll(context)
    刷新活动中的小组件。

Step 4: Add WearWidgetPreview functions and picker preview PNGs

第 4 步:添加 WearWidgetPreview 函数和选择器预览 PNG

  1. Composable border previews (
    androidx.glance.wear.tooling.preview
    )
    : Import
    WearWidgetPreview
    ,
    SquircleAllWidgetPreviewParams
    ,
    RoundAllWidgetPreviewParams
    , and
    RectangularAllWidgetPreviewParams
    from
    androidx.glance.wear.tooling.preview
    (NEVER
    androidx.glance.wear.testing
    ). Define
    @Preview
    functions invoking
    WearWidgetPreview(widget, params)
    .
  2. Rectangular picker PNGs (
    res/drawable-nodpi/
    )
    : Use
    RectangularAllWidgetPreviewParams
    at
    320 dpi
    or render non-blank, unmasked rectangular PNGs for every
    <container>
    in the provider XML:
    • SMALL
      (
      CONTAINER_TYPE_SMALL
      ):
      448x168
      px
      (
      224x84
      dp at 320 dpi, aspect ratio
      2.67
      ).
    • LARGE
      (
      CONTAINER_TYPE_LARGE
      ):
      464x288
      px
      (
      232x144
      dp at 320 dpi, aspect ratio
      1.61
      ).
    • Each preview PNG MUST depict the widget's actual UI elements, including backgrounds, text labels, icons, avatar initials, and buttons. NEVER use a blank placeholder, empty unlabeled shapes, or a 1:1 tile preview. When adding composable previews, picker PNGs, or unit tests, you MUST follow Previews and testing reference.
  1. Composable 边框预览(
    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/
    )
    :使用
    RectangularAllWidgetPreviewParams
    和
    320 dpi
    ,或为 provider XML 中的每个
    <container>
    渲染非空白、未遮罩的矩形 PNG:
    • SMALL
      (
      CONTAINER_TYPE_SMALL
      ):
      448x168
      像素
      (在 320 dpi 下为
      224x84
      dp,宽高比为
      2.67
      )。
    • LARGE
      (
      CONTAINER_TYPE_LARGE
      ):
      464x288
      像素
      (在 320 dpi 下为
      232x144
      dp,宽高比为
      1.61
      )。
    • 每个预览 PNG 必须呈现小组件的实际 UI 元素,包括背景、文字标签、图标、头像首字母和按钮。绝不使用空白占位图、无标签空形状或 1:1 磁贴预览。添加 Composable 预览、选择器 PNG 或单元测试时,必须遵循预览与测试参考文档。

Component mapping

组件映射

Use this sample table to load complete implementation patterns and imports:
Capability or API surfaceReference guide
GlanceWearWidget
,
GlanceWearWidgetService
,
AndroidManifest.xml
,
<wearwidget-provider>
, legacy
TileService
migration
Widget service and manifest reference
RemoteBox
,
RemoteColumn
,
RemoteRow
,
RemoteText
,
RemoteImage
,
ContainerInfo
(
SMALL
and
LARGE
adaptive layouts)
Remote Compose layouts reference
RemoteButton
,
rememberMutableRemoteInt
,
valueChange
,
pendingIntentAction
,
BroadcastReceiver
,
triggerUpdateAll
State and actions reference
WearWidgetPreview
,
SquircleAllWidgetPreviewParams
,
RoundAllWidgetPreviewParams
,
RectangularAllWidgetPreviewParams
, picker PNGs,
captureRawContent
tests
Previews and testing reference
参考下表获取完整的实现模式和导入项:
功能或 API 接口参考指南
GlanceWearWidget
、
GlanceWearWidgetService
、
AndroidManifest.xml
、
<wearwidget-provider>
、旧版
TileService
迁移
小组件 service 与 manifest 参考文档
RemoteBox
、
RemoteColumn
、
RemoteRow
、
RemoteText
、
RemoteImage
、
ContainerInfo
(
SMALL
和
LARGE
自适应布局)
Remote Compose 布局参考文档
RemoteButton
、
rememberMutableRemoteInt
、
valueChange
、
pendingIntentAction
、
BroadcastReceiver
、
triggerUpdateAll
状态与操作参考文档
WearWidgetPreview
、
SquircleAllWidgetPreviewParams
、
RoundAllWidgetPreviewParams
、
RectangularAllWidgetPreviewParams
、选择器 PNG、
captureRawContent
测试
预览与测试参考文档

Legacy ProtoLayout and mobile Glance equivalents

旧版 ProtoLayout 和移动端 Glance 等价项

Legacy or mobile APIWear OS widget APIAction to take
androidx.wear.tiles.TileService
GlanceWearWidgetService
+
GlanceWearWidget
Replace service and annotate with
@AssociateWithGlanceWearWidget
.
GlanceAppWidget
/
provideGlance
GlanceWearWidget
/
provideWidgetData
Return
WearWidgetDocument
from
provideWidgetData
.
LayoutElementBuilders
/
primaryLayout
RemoteColumn
,
RemoteRow
,
RemoteBox
Build layouts with
@RemoteComposable
functions.
mutableStateOf
/
mutableIntStateOf
rememberMutableRemoteInt
+
valueChange
Mutate remote state declaratively using
valueChange
.
ModifiersBuilders.Clickable
RemoteModifier.clickable(pendingIntentAction { ... })
Pass a
(Context) -> PendingIntent
lambda to
pendingIntentAction
.
旧版或移动端 APIWear OS 小组件 API执行操作
androidx.wear.tiles.TileService
GlanceWearWidgetService
+
GlanceWearWidget
替换 service,并添加
@AssociateWithGlanceWearWidget
注解。
GlanceAppWidget
/
provideGlance
GlanceWearWidget
/
provideWidgetData
从
provideWidgetData
返回
WearWidgetDocument
。
LayoutElementBuilders
/
primaryLayout
RemoteColumn
、
RemoteRow
、
RemoteBox
使用
@RemoteComposable
函数构建布局。
mutableStateOf
/
mutableIntStateOf
rememberMutableRemoteInt
+
valueChange
使用
valueChange
以声明式方式修改 remote 状态。
ModifiersBuilders.Clickable
RemoteModifier.clickable(pendingIntentAction { ... })
向
pendingIntentAction
传入
(Context) -> PendingIntent
lambda。

Troubleshooting

故障排查

SymptomCauseFix
Unresolved reference
GlanceWearWidget
Missing
androidx.glance.wear:wear:{GLANCE_WEAR_VERSION}
or low
compileSdk
Set
compileSdk = 37
and add
androidx.glance.wear:wear:{GLANCE_WEAR_VERSION}
.
Unresolved reference
toRemoteString
Imported
toRemoteString
as top-level extension
Remove the import; call
remoteInt.toRemoteString
as a member method.
Type mismatch on
pendingIntentAction
Passed bare
PendingIntent
instead of lambda
Wrap in a lambda:
pendingIntentAction { ctx -> pendingIntent }
.
Unresolved
wear.tiles
or
protolayout
references after migration
Other classes or source sets in the module still use legacy tile APIsMigrate or update the remaining references before removing legacy
wear.tiles
and
protolayout
dependencies from
build.gradle.kts
.
症状原因修复方式
无法解析
GlanceWearWidget
缺少
androidx.glance.wear:wear:{GLANCE_WEAR_VERSION}
,或
compileSdk
版本过低
将
compileSdk
设置为
37
,并添加
androidx.glance.wear:wear:{GLANCE_WEAR_VERSION}
。
无法解析
toRemoteString
将
toRemoteString
作为顶层扩展函数导入
移除该导入;将其作为成员方法调用:
remoteInt.toRemoteString
。
pendingIntentAction
出现类型不匹配
传入了裸
PendingIntent
,而不是 lambda
使用 lambda 包装:
pendingIntentAction { ctx -> pendingIntent }
。
迁移后仍无法解析
wear.tiles
或
protolayout
引用
模块中的其他类或 source set 仍在使用旧版磁贴 API在从
build.gradle.kts
中移除旧版
wear.tiles
和
protolayout
依赖项之前,迁移或更新剩余引用。

Verification

验证

  1. Run
    ./gradlew :app:assembleDebug
    to verify that the widget, service,
    AndroidManifest.xml
    declarations, and
    @xml/
    <wearwidget-provider>
    resources compile and link without errors.
  2. If the project includes unit tests or new widget tests, run
    ./gradlew :app:testDebugUnitTest
    and confirm all tests pass. When adding composable previews, picker PNGs, or unit tests, you MUST follow Previews and testing reference.
  1. 运行
    ./gradlew :app:assembleDebug
    ,验证小组件、service、
    AndroidManifest.xml
    声明以及
    @xml/
    <wearwidget-provider>
    资源能够成功编译和链接,且没有错误。
  2. 如果项目包含单元测试或新增了小组件测试,运行
    ./gradlew :app:testDebugUnitTest
    并确认所有测试均通过。添加 Composable 预览、选择器 PNG 或单元测试时,必须遵循预览与测试参考文档。

Antipatterns

反模式

  • NEVER extend mobile
    GlanceAppWidget
    or
    AppWidgetProvider
    , or use deprecated
    GlanceTileService
    or
    TileService
    for Wear OS widgets.
  • NEVER use in-memory client Compose state (
    mutableStateOf
    ,
    mutableIntStateOf
    ) or in-process click lambdas for Remote Compose UI.
  • NEVER pass a bare
    PendingIntent
    instance to
    pendingIntentAction
    ; always pass a
    (Context) -> PendingIntent
    lambda.
  • NEVER apply
    CircleShape
    or
    RoundedCornerShape
    clipping to full-bleed widget background artwork. NEVER reuse 1:1 (
    400x400
    ) tile previews or blank solid-color placeholders for widget picker PNGs.
  • 绝不继承移动端
    GlanceAppWidget
    或
    AppWidgetProvider
    ,也不要在 Wear OS 小组件中使用已弃用的
    GlanceTileService
    或
    TileService
    。
  • 绝不在 Remote Compose UI 中使用内存中的客户端 Compose 状态(
    mutableStateOf
    、
    mutableIntStateOf
    )或进程内点击 lambda。
  • 绝不向
    pendingIntentAction
    传入裸
    PendingIntent
    实例;始终传入
    (Context) -> PendingIntent
    lambda。
  • 绝不对全幅小组件背景图应用
    CircleShape
    或
    RoundedCornerShape
    裁剪。绝不将 1:1(
    400x400
    )磁贴预览或纯色空白占位图用作小组件选择器 PNG。

Best practices

最佳实践

  • MUST declare
    com.google.android.wearable.permission.BIND_TILE_PROVIDER
    and
    androidx.glance.wear.action.BIND_WIDGET_PROVIDER
    on
    <service>
    .
  • MUST declare
    SMALL
    and
    LARGE
    <container>
    entries in
    @xml/
    with domain-accurate
    448x168
    and
    464x288
    PNGs in
    res/drawable-nodpi/
    .
  • MUST adapt layout content to
    params.containerType
    and include
    @Preview
    functions for both
    SquircleAllWidgetPreviewParams
    and
    RoundAllWidgetPreviewParams
    .
  • 必须在
    <service>
    上声明
    com.google.android.wearable.permission.BIND_TILE_PROVIDER
    和
    androidx.glance.wear.action.BIND_WIDGET_PROVIDER
    。
  • 必须在
    @xml/
    中声明
    SMALL
    和
    LARGE
    <container>
    条目,并在
    res/drawable-nodpi/
    中提供与实际尺寸匹配的
    448x168
    和
    464x288
    PNG。
  • 必须根据
    params.containerType
    调整布局内容,并为
    SquircleAllWidgetPreviewParams
    和
    RoundAllWidgetPreviewParams
    包含
    @Preview
    函数。