Comienza a usar widgets

Requisitos previos y configuración

Antes de comenzar, asegúrate de que tu entorno cumpla con los siguientes requisitos.

Requisitos de tiempo de ejecución

Los Wear Widgets requieren la versión 1.6.1 o posterior del APK de com.google.android.wearable.protolayout.renderer en el dispositivo de destino.

Obtén una versión compatible del renderizador de una de las siguientes maneras:

  • Emulador de Wear OS 7: Usa la imagen del emulador de Wear OS 7. Las versiones inferiores a 7 no son adecuadas. Para obtener instrucciones de configuración, consulta Cómo configurar el emulador de Wear OS 7.
  • Dispositivo físico: Usa un dispositivo Wear OS físico que reciba actualizaciones automáticas de Google Play Store o un dispositivo para desarrolladores en el que se haya accedido a Google Play Store.

Para verificar qué versión tienes instalada en tu dispositivo, usa el siguiente comando:

adb shell dumpsys package com.google.android.wearable.protolayout.renderer | \
  grep -m 1 versionName | \
  awk -F= '{print $2}'

Configuración de Gradle

Las bibliotecas de Wear Widgets están disponibles en Google Maven.

1. Configurar la versión del SDK

Asegúrate de que compileSdk y targetSdk estén configurados en 37 o un valor superior.

android {
    compileSdk = 37
    // ...
    defaultConfig {
        targetSdk = 37
        // ...
    }
}

2. Agregar dependencias

Incluye las siguientes dependencias en el archivo build.gradle.kts de tu app:

Groovy

dependencies {
    // Core Wear Widget and Remote Compose libraries
    implementation "androidx.compose.remote:remote-creation-compose:1.0.0-alpha20"
    implementation "androidx.compose.remote:remote-core:1.0.0-alpha20"
    implementation "androidx.glance.wear:wear:1.0.0-alpha19"
    implementation "androidx.glance.wear:wear-core:1.0.0-alpha19"
    implementation "androidx.wear.compose.remote:remote-material3:1.0.0-alpha12"

    // Tooling for previews (optional, but recommended)
    implementation "androidx.compose.remote:remote-tooling-preview:1.0.0-alpha20"
    implementation "androidx.wear.compose:compose-ui-tooling:1.7.0"
    implementation "androidx.wear.tiles:tiles-tooling-preview:1.6.2"
    debugImplementation "androidx.wear.tiles:tiles-renderer:1.6.2"
}

Kotlin

dependencies {
    // Core Wear Widget and Remote Compose libraries
    implementation("androidx.compose.remote:remote-creation-compose:1.0.0-alpha20")
    implementation("androidx.compose.remote:remote-core:1.0.0-alpha20")
    implementation("androidx.glance.wear:wear:1.0.0-alpha19")
    implementation("androidx.glance.wear:wear-core:1.0.0-alpha19")
    implementation("androidx.wear.compose.remote:remote-material3:1.0.0-alpha12")

    // Tooling for previews (optional, but recommended)
    implementation("androidx.compose.remote:remote-tooling-preview:1.0.0-alpha20")
    implementation("androidx.wear.compose:compose-ui-tooling:1.7.0")
    implementation("androidx.wear.tiles:tiles-tooling-preview:1.6.2")
    debugImplementation("androidx.wear.tiles:tiles-renderer:1.6.2")
}

Cómo compilar un widget de Hello World

Un widget para Wear consta de un servicio que extiende GlanceWearWidgetService y una clase de widget que extiende GlanceWearWidget. Defines la IU con funciones @RemoteComposable.

Cómo definir el servicio

El servicio es el punto de entrada al que se vincula el sistema.

Para definir tu widget, crea un servicio que extienda GlanceWearWidgetService y anótalo con @AssociateWithGlanceWearWidget para asociar el servicio con la clase GlanceWearWidget adecuada.

@AssociateWithGlanceWearWidget(HelloWidget::class)
class HelloWidgetService : GlanceWearWidgetService() {
    override val widget: GlanceWearWidget = HelloWidget()
}

Define el widget

La clase de widget proporciona los datos y el diseño del widget.

class HelloWidget : GlanceWearWidget() {
    override suspend fun provideWidgetData(
        context: Context,
        params: WearWidgetParams,
    ): WearWidgetData {
        return WearWidgetDocument(
            background = WearWidgetBrush.color(Color.Blue.rc),
        ) {
            HelloWidgetContent()
        }
    }
}

Define el contenido

El contenido se compila con componentes de Remote Compose.

@RemoteComposable
@Composable
fun HelloWidgetContent() {
    RemoteBox(
        modifier = RemoteModifier.fillMaxSize(),
        contentAlignment = RemoteAlignment.Center,
    ) {
        RemoteText(
            text = "Hello World".rs,
            color = Color.White.rc,
        )
    }
}

Obtén una vista previa de tu widget en Android Studio

Puedes obtener una vista previa de los diseños de tus widgets directamente en el panel Design de Android Studio con androidx.glance.wear:wear-tooling-preview.

Conjuntos de vistas previas predefinidos

La biblioteca wear-tooling-preview proporciona conjuntos de PreviewParameterProvider predefinidos para probar tus diseños en diferentes formas de contenedores y configuraciones de dispositivos:

  • Squircle Suite (SquircleAllWidgetPreviewParams): Contenedores rectangulares redondeados.
  • Round Suite (RoundAllWidgetPreviewParams): Contenedores en forma de píldora.
  • Rectangular Suite (RectangularAllWidgetPreviewParams): Contenedores rectangulares sin recortar con relleno seguro. Las imágenes generadas con esta configuración de vista previa son adecuadas para usarse como imágenes de vista previa incorporadas en el APK que usa el selector de widgets (consulta Cómo generar recursos de imágenes de vista previa).

Para obtener una vista previa de tu widget en Android Studio, usa @WearWidgetPreview:

@Preview
@Composable
fun HelloWidgetPreview(
    @PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams,
) {
    WearWidgetPreview(
        widget = HelloWidget(),
        params = params,
    )
}

Crea el XML de configuración del widget

Crea un archivo res/xml/hello_widget_info.xml nuevo para definir las propiedades y los tamaños admitidos del widget. Para obtener una referencia completa de los atributos XML compatibles en la etiqueta <wearwidget-provider>, consulta la documentación de WearWidgetProviderInfo.

<wearwidget-provider
    description="@string/hello_widget_description"
    icon="@mipmap/ic_launcher"
    label="@string/hello_widget_label"
    preferredType="SMALL">

    <container
        type="SMALL"
        previewImage="@drawable/widget_preview_small" />
    <container
        type="LARGE"
        previewImage="@drawable/widget_preview_large" />
</wearwidget-provider>

Genera recursos de imagen de vista previa

El atributo previewImage del elemento <container> hace referencia a un recurso de diseño que se muestra en el selector de widgets del sistema. Para generar recursos de vista previa con los límites y la densidad correctos, usa las vistas previas de Android Studio con RectangularAllWidgetPreviewParams (que genera variantes de vista previa para contenedores pequeños y grandes) y especifica una densidad de pantalla de smartwatch de 320 DPI:

@Preview(
    name = "Widget Preview Asset",
    device = "spec:width=1000dp,height=1000dp,dpi=320",
)
@Composable
fun HelloWidgetCatalogPreview(
    @PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams,
) {
    WearWidgetPreview(
        widget = HelloWidget(),
        params = params,
    )
}

Para extraer las imágenes de vista previa renderizadas, completa los siguientes pasos:

  1. En Android Studio, abre la superficie de diseño para el elemento componible de vista previa.
  2. En la ventana de vista previa, haz clic con el botón derecho en la vista previa renderizada o usa la barra de herramientas de vista previa para seleccionar Copiar imagen o guardar la imagen. Como alternativa, usa herramientas de la CLI o secuencias de comandos automatizadas para extraer vistas previas de Compose.
  3. Guarda los archivos de imágenes pequeñas y grandes en el directorio res/drawable-nodpi/ de tu app, como res/drawable-nodpi/widget_preview_small.png y res/drawable-nodpi/widget_preview_large.png.

Registro en AndroidManifest.xml

Registra el servicio en tu AndroidManifest.xml con los filtros de intents y los metadatos requeridos.

<service
    android:name=".snippets.widget.HelloWidgetService"
    android:exported="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/hello_widget_label"
    android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">

    <intent-filter>
        <action android:name="androidx.glance.wear.action.BIND_WIDGET_PROVIDER" />
        <!-- If you already have a Tile, omit the following line. -->
        <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
    </intent-filter>

    <meta-data
        android:name="androidx.glance.wear.widget.provider"
        android:resource="@xml/hello_widget_info" />

    <meta-data
        android:name="androidx.wear.tiles.PREVIEW"
        android:resource="@drawable/tile_preview" />
</service>

Compile e implemente

Después de definir tu servicio y widget, puedes compilar tu proyecto y, luego, implementarlo en un dispositivo o emulador.

Compilación e instalación

Compila el proyecto e instala el APK de depuración en el emulador o dispositivo conectado:

./gradlew :app:installDebug

Agrega tu widget y obtén una vista previa

Después de instalar la app, usa adb para agregar el widget al carrusel de forma programática y mostrarlo en la pantalla.

Nota: Los widgets para Wear usan la infraestructura de tarjetas subyacente para la depuración. Como resultado, los comandos adb requieren las operaciones add-tile y show-tile.

1. Agrega el widget al carrusel:

adb shell am broadcast \
  -a com.google.android.wearable.app.DEBUG_SURFACE \
  --es operation add-tile \
  --ecn component <your_package_name>/.HelloWidgetService

2. Mostrar el widget:

adb shell am broadcast \
  -a com.google.android.wearable.app.DEBUG_SYSUI \
  --es operation show-tile \
  --ei index 0

Actualiza el contenido del widget de forma programática

Cuando cambien los datos subyacentes de tu app (por ejemplo, cuando recibas una sincronización de datos, una notificación push o una acción del usuario), notifica al sistema que actualice el contenido del widget.

Para solicitar una actualización de todas las instancias activas de tu widget, llama a triggerUpdateAll en la clase del widget:

// Request a content update for all active HelloWidget instances
HelloWidget().triggerUpdateAll(context)

Para actualizar una instancia de widget específica sin actualizar todas las instancias activas, llama a triggerUpdate con el ID de la instancia de destino.