关于 wear-widgets
面向 Android 开发者的技能,用于通过 Glance Wear 和 Remote Compose 创建或迁移 Wear OS 小组件,涵盖服务注册、自适应布局、远程状态与操作、预览及选择器资源。
主要功能
- 01配置 Glance Wear 小组件
- 02Remote Compose 自适应布局
- 03远程状态与点击操作
- 04小组件预览和选择器图片
- 05旧版 Tile 迁移指导
适用场景
- 01创建 Wear OS 小组件
- 02迁移旧版 Wear OS Tile
- 03添加小组件预览和选择器资源
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ android/ skills --skill wear-widgets安装后在 Claude Code 中输入/wear-widgets确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/previews-and-testing.mdremote-compose-layouts.mdstate-and-actions.mdwidget-service-and-manifest.md详细介绍
Wear OS 微件使用 androidx.glance.wear(GlanceWearWidget 和
GlanceWearWidgetService)与 androidx.compose.remote(Remote Compose)。
它们会将声明式 UI 和状态文档序列化到手表宿主进程。
前提条件和设置
-
确定库版本:为
{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来确定版本:- 如果有可用的依赖项查询工具,请使用该工具。
- 否则,请从 Google Maven 元数据获取最新版本(Glance Wear 元数据、Compose Remote 元数据、Wear Compose Remote 元数据)。
-
SDK 和 Compose 编译器要求:除非用户要求创建微件、迁移 Tile 或设置依赖项,否则修改整个代码库的 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}") }
探索代码库
- 在模块中搜索现有的
TileService、Material3TileService或GlanceWearWidget实现、app/src/main/AndroidManifest.xml中的<service>条目,以及app/src/main/res/下的@drawable/预览资源。 - 迁移现有 Tile 或修改不熟悉的多模块项目时,运行
./gradlew :app:assembleDebug,以验证基线构建状态。
工作流
步骤 1:配置 AndroidManifest.xml 和 provider XML
在 app/src/main/AndroidManifest.xml 中注册 GlanceWearWidgetService 子类,并设置 BIND_TILE_PROVIDER 权限和 BIND_WIDGET_PROVIDER intent 操作。添加 <meta-data>,指向包含 SMALL 和 LARGE <container> 条目的 @xml/ <wearwidget-provider> 资源。配置服务、provider XML 或迁移旧版 TileService 时,必须遵循微件服务和清单参考。
<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>
步骤 2:实现 GlanceWearWidget 和 GlanceWearWidgetService
扩展 GlanceWearWidget,并重写 provideWidgetData 以返回
WearWidgetDocument。为 GlanceWearWidgetService 子类添加 @AssociateWithGlanceWearWidget 注解,以便静态解析 provider:
// 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)
}
}
步骤 3:构建 Remote Compose 布局、状态和操作
Remote Compose 会在 Wear OS 宿主进程中评估 UI 和状态,而不是在应用进程中。构建自适应布局或全出血背景时,必须遵循 Remote Compose layouts reference。实现状态或点击操作时,必须遵循 State and actions reference。
- 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) -> PendingIntentlambda)。使用widget.triggerUpdateAll(context)刷新处于活动状态的微件。
步骤 4:添加 WearWidgetPreview 函数和选择器预览 PNG
- 可组合边框预览(
androidx.glance.wear.tooling.preview):从androidx.glance.wear.tooling.preview导入WearWidgetPreview、SquircleAllWidgetPreviewParams、RoundAllWidgetPreviewParams和RectangularAllWidgetPreviewParams(绝不要使用androidx.glance.wear.testing)。定义调用WearWidgetPreview(widget, params)的@Preview函数。 - 矩形选择器 PNG(
res/drawable-nodpi/):使用320 dpi下的RectangularAllWidgetPreviewParams,或为提供程序 XML 中的每个<container>渲染非空白、未遮罩的矩形 PNG:SMALL(CONTAINER_TYPE_SMALL):448x168px(320 dpi下为224x84dp,宽高比为2.67)。LARGE(CONTAINER_TYPE_LARGE):464x288px(320 dpi下为232x144dp,宽高比为1.61)。- 每张预览 PNG 都必须呈现微件的实际 UI 元素,包括背景、文本标签、图标、头像首字母和按钮。绝不要使用空白占位图、没有标签的空形状或
1:1平铺预览。添加可组合预览、选择器 PNG 或单元测试时,必须遵循 Previews and testing reference。
组件映射
使用此示例表加载完整的实现模式和导入项:
| 功能或 API 范围 | 参考指南 |
|---|---|
GlanceWearWidget、GlanceWearWidgetService、AndroidManifest.xml、<wearwidget-provider>、旧版 TileService 迁移 | Widget service and manifest reference |
RemoteBox、RemoteColumn、RemoteRow、RemoteText、RemoteImage、ContainerInfo(SMALL 和 LARGE 自适应布局) | Remote Compose layouts reference |
RemoteButton、rememberMutableRemoteInt、valueChange、pendingIntentAction、BroadcastReceiver、triggerUpdateAll | State and actions reference |
WearWidgetPreview、SquircleAllWidgetPreviewParams、RoundAllWidgetPreviewParams、RectangularAllWidgetPreviewParams、选择器 PNG、captureRawContent 测试 | Previews and testing reference |
旧版 ProtoLayout 和移动端 Glance 对应项
| 旧版或移动端 API | Wear OS 小组件 API | 要采取的操作 |
|---|---|---|
androidx.wear.tiles.TileService | GlanceWearWidgetService + GlanceWearWidget | 替换服务,并添加 @AssociateWithGlanceWearWidget 注解。 |
GlanceAppWidget / provideGlance | GlanceWearWidget / provideWidgetData | 从 provideWidgetData 返回 WearWidgetDocument。 |
LayoutElementBuilders / primaryLayout | RemoteColumn、RemoteRow、RemoteBox | 使用 @RemoteComposable 函数构建布局。 |
mutableStateOf / mutableIntStateOf | rememberMutableRemoteInt + valueChange | 使用 valueChange 以声明式方式更改远程状态。 |
ModifiersBuilders.Clickable | RemoteModifier.clickable(pendingIntentAction { ... }) | 将 (Context) -> PendingIntent lambda 传给 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,而不是 lambda | 将其包装在 lambda 中:pendingIntentAction { ctx -> pendingIntent }。 |
迁移后仍有无法解析的 wear.tiles 或 protolayout 引用 | 模块中的其他类或源集仍在使用旧版磁贴 API | 从 build.gradle.kts 移除旧版 wear.tiles 和 protolayout 依赖之前,先迁移或更新剩余引用。 |
验证
- 运行
./gradlew :app:assembleDebug,验证小组件、服务、AndroidManifest.xml声明和@xml/<wearwidget-provider>资源均可编译和链接,且没有错误。 - 如果项目包含单元测试或新增的小组件测试,运行
./gradlew :app:testDebugUnitTest并确认所有测试均通过。添加可组合项预览、选择器 PNG 或单元测试时,必须遵循预览和测试参考。
反模式
- 绝不可扩展移动端
GlanceAppWidget或AppWidgetProvider,也不可在 Wear OS 小组件中使用已弃用的GlanceTileService或TileService。 - 绝不可在 Remote Compose UI 中使用内存中的客户端 Compose 状态(
mutableStateOf、mutableIntStateOf)或进程内点击 lambda。 - 绝不可将裸
PendingIntent实例传给pendingIntentAction;始终传入(Context) -> PendingIntentlambda。 - 绝不可对全出血小组件背景图应用
CircleShape或RoundedCornerShape裁剪。绝不可将 1:1(400x400)磁贴预览或纯色空白占位图复用于小组件选择器 PNG。
最佳实践
- 必须在
<service>上声明com.google.android.wearable.permission.BIND_TILE_PROVIDER和androidx.glance.wear.action.BIND_WIDGET_PROVIDER。 - 必须在
@xml/中声明SMALL和LARGE<container>条目,并在res/drawable-nodpi/中提供符合实际内容的448x168和464x288PNG。 - 必须根据
params.containerType调整布局内容,并为SquircleAllWidgetPreviewParams和RoundAllWidgetPreviewParams分别添加@Preview函数。