Nozioni di base sulle app

Evoluzione dei riquadri in widget per Wear utilizzando Jetpack Glance e Remote Compose

Altoparlanti

  • François Deschênes

    Product Manager

  • Yuri Schimke

    Software Engineer

Informazioni

Informazioni sulla presentazione

In questa sessione, approfondiremo gli aspetti tecnici dell'evoluzione dalle schede a schermo intero ai widget Wear dinamici ad altezza parziale.

Esploreremo i vantaggi tecnici dell'API Jetpack Glance unificata e del nuovo motore Remote Compose, spiegando in dettaglio come si allineano perfettamente con Modern Android Development.

Infine, condivideremo le ultime linee guida sulla UX e illustreremo strategie di migrazione pratiche per aiutarti a creare la prossima generazione di UI facilmente consultabili.

Riepilogo

  • Wear OS sta evolvendo le schede a schermo intero in widget Wear creati con Jetpack Glance e basati su Remote Compose.
  • Remote Compose condivide lo stesso compilatore e runtime della UI di Jetpack Compose, disaccoppiando in modo sicuro la UI dal processo dell'app.
  • Le dimensioni dei container piccoli e grandi sono allineate ai formati della griglia mobile, mentre le API Jetpack Glance Wear mantengono la compatibilità con le versioni precedenti fino a Wear 4.
  • Per eseguire la migrazione dei riquadri esistenti ai widget, puoi utilizzare una strategia consigliata con due servizi o un singolo servizio di compatibilità.

Skill

Risorse

Gemini Notebook

Argomenti

  • wear-os
  • wear-widgets
  • jetpack-glance
  • remote-compose
  • tiles-migration
  • jetpack-compose

Trascrizione

Scarica la trascrizione

Introduzione

  • Ciao a tutti.

  • Mi chiamo Frank e sono responsabile delle esperienze rapide per Wear OS.

  • Gli smartwatch sono compagni essenziali per i tuoi utenti, che li indossano tutto il giorno. Oggi ti spiegheremo come sfruttare la nuova esperienza dei widget di Wear.

  • Vedremo come fornire le funzionalità più importanti direttamente al polso degli utenti e lo faremo utilizzando le API più recenti, progettate per rendere la creazione di app per Wear OS familiare e intuitiva per gli sviluppatori Android come te.

  • Oggi sul palco con me per esaminare esattamente come lo stiamo facendo c'è il mio brillante collega e compagno di scrivania Yuri.

  • Ciao, sono Yuri Schimke.

  • Sono un ingegnere del team di Wear OS e mi occupo principalmente delle API Remote Compose.

  • Oggi ti presenterò brevemente Remote Compose e ti parlerò anche della procedura di migrazione da Tiles a Wear Widgets.

  • A questo punto, ripasso la parola a Frank.

Evoluzione dei riquadri in widget di Wear OS

  • Fantastico.

  • Grazie, Yuri.

  • Stiamo ufficialmente portando il polso nell'ecosistema unificato dei widget Android, trasformando le nostre schede a schermo intero in widget Wear.

  • E poiché queste esperienze sono ora create utilizzando Jetpack Glance, puoi vedere che si tratta della stessa infrastruttura di base utilizzata per i widget mobile.

  • In futuro, lo sviluppo per Wear diventerà ancora più familiare per te.

Panoramica di Remote Compose

  • Per supportare queste esperienze, stiamo evolvendo lo stack UI, lo stack UI sottostante.

  • I widget per Wear sono basati su Remote Compose, un nuovo framework Android per l'UI remota.

  • Ciò significa che puoi finalmente utilizzare un'API dichiarativa strettamente allineata a Jetpack Compose per creare le tue esperienze esterne all'app, come i widget.

  • Remote Compose offre grafica moderna e layout adattabili ai widget, garantendo al contempo prestazioni ed efficienza della batteria.

  • Inoltre, disaccoppiando la UI dal processo dell'applicazione, i widget vengono serializzati in modo sicuro e visualizzati facilmente su un'ampia gamma di dispositivi Android.

  • Ciò significa che puoi portare queste esperienze complete su quasi tutte le piattaforme remote supportate con il minimo sforzo.

Dimensioni del layout e compatibilità con le versioni precedenti

  • Per rendere la transizione dalle schede ai widget il più agevole possibile, stiamo introducendo due dimensioni standard per i contenitori: piccola e grande.

  • Questi sono progettati per essere strettamente allineati ai formati di widget basati su griglia 2x1 e 2x2 a cui sei già abituato con la creazione di widget su dispositivi mobili.

  • Inoltre, a partire da Wear 7 su alcuni produttori di hardware, i widget di Wear saranno ora disponibili in una barra a scorrimento verticale insieme ai widget di altre app.

  • Ad esempio, ecco come appaiono i widget Wear su un Samsung Galaxy Watch.

  • L'architettura della piattaforma è progettata per supportare i carrelli a scorrimento verticale, poiché i produttori di hardware adotteranno questo modello in futuro.

  • Inoltre, non devi preoccuparti di lasciare indietro utenti o utenti esistenti.

  • Le API Jetpack Glance Wear sono progettate per supportare la compatibilità con le versioni precedenti fino a Wear 4.

  • Sui dispositivi meno recenti che supportano una barra orizzontale di widget o di riquadri, il sistema gestirà questa operazione per te.

  • Devi semplicemente indicare nel codice che vuoi supportare la modalità a schermo intero e il sistema prenderà il tuo widget di grandi dimensioni e lo mostrerà come una scheda tradizionale a schermo intero su questi dispositivi.

  • Ora Yuri ci guiderà attraverso il codice per mostrarci esattamente come eseguire la migrazione delle schede esistenti in widget Wear.

Strategie di migrazione per i riquadri esistenti

  • Grazie, Frank.

  • Se stai creando un nuovo widget per Wear da zero, è semplice.

  • Devi solo definire un GlanceWearWidgetService e creare la tua UI utilizzando Remote Compose.

  • Tuttavia, se la tua app ha già una scheda in produzione, dovrai eseguire la migrazione di servizi, UI e dati.

  • Per rendere questa transizione il più agevole possibile, abbiamo fornito percorsi per garantire un'esperienza senza interruzioni per gli utenti esistenti.

  • Per il servizio, puoi scegliere tra due strategie: servizio doppio o servizio singolo.

  • Con il doppio servizio, che consigliamo, manterrai il TileService esistente per i dispositivi Wear OS meno recenti e aggiungerai un nuovo GlanceWearWidgetService per Wear OS 7 e versioni successive.

  • Al contrario, con il servizio singolo, crei un nuovo GlanceWearWidgetService singolo che gestisce entrambi i protocolli, in esecuzione in una modalità di compatibilità per tradurre il widget in un riquadro sui dispositivi meno recenti.

  • In entrambi i casi, continuerai a raggiungere i tuoi utenti.

  • Influisce solo sul codice che gestirai in futuro.

  • Abbiamo appena pubblicato una documentazione completa sul sito per sviluppatori Android che spiega esattamente come e quando utilizzare entrambi questi pattern.

  • Dai un'occhiata per scoprire di più sulla strategia migliore per la tua app.

Creazione dell'UI con Remote Compose

  • Ora parliamo del livello UI.

  • Durante la migrazione, il tuo modello mentale cambia.

  • In precedenza, i riquadri utilizzavano ProtoLayout, una libreria creata esclusivamente per i riquadri di Wear.

  • Wear Widgets, invece, si basa su Remote Compose.

  • Remote Compose condivide esattamente la stessa base della UI di Jetpack Compose, utilizzando lo stesso compilatore e runtime di base.

  • Inoltre, è progettato per essere familiare, in quanto corrisponde strettamente alle librerie di UI di Compose come Foundation e Material 3.

  • Ma invece di una casella, una colonna o un testo, li scambierai semplicemente con RemoteBox, RemoteColumn o RemoteText.

  • In questo caso, acquisirai familiarità con la scrittura di "remote".

  • Inoltre, per velocizzare il tuo flusso di lavoro, abbiamo incluso un set completo di componenti Remote Compose pronti all'uso progettati specificamente per i widget.

  • Ciò significa che i tuoi progetti Wear Material 3 esistenti, inclusi quelli che hai in Figma, possono essere facilmente adattati ai widget, rendendoli familiari sia agli ingegneri che ai designer.

  • Per capire quanto siano allineati questi framework, diamo un'occhiata a un esempio concreto.

  • Creeremo il nostro componente dell'app sopra il pulsante di attivazione/disattivazione di Material 3.

  • A sinistra abbiamo il componente Wear Compose standard che scriveresti all'interno della tua app, mentre a destra è presente la versione di Remote Compose.

    // Wear Compose
    @Composable
    fun HistoryEraserButton(
      onClick: () -> Unit,
      modifier: Modifier = Modifier,
      checked: Boolean = true,
      onCheckedChange: (Boolean) -> Unit = {},
    )
    // Wear RemoteCompose
    @RemoteComposable
    @Composable
    fun RemoteHistoryEraserButton(
      onClick: Action,
      modifier: RemoteModifier = RemoteModifier,
      checked: RemoteBoolean = true.rb,
      onCheckedChange: Action = Action.Empty,
    )
  • Nota quanto sono simili i pattern.

  • Tuttavia, quando scrivi il codice di Remote Compose, utilizzerai l'annotazione RemoteComposable.

  • E dove utilizzi parametri familiari come modificatore e booleano, esistono tipi di Remote Compose equivalenti come RemoteModifier e RemoteBoolean.

  • Inoltre, utilizzi le azioni anziché le lambda.

  • Anziché definire il codice da eseguire all'interno della funzione lambda, dovrai dichiarare un'azione, ad esempio l'avvio di un pending intent, la chiamata di un servizio o l'aggiornamento di un valore.

  • Passiamo al corpo del nostro componente.

  • Noterai che anche i temi sono allineati.

  • Puoi applicare la combinazione di colori di Material 3 al componente Remote Compose esattamente come faresti in Compose standard, in modo che il widget corrisponda esattamente al branding della tua app.

    // Wear Compose
      val colors = MaterialTheme.colorScheme
      SplitSwitchButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        toggleContentDescription = "Arm Eraser",
        onContainerClick = onClick,
        modifier = modifier.fillMaxWidth(),
        colors =
          SwitchButtonDefaults.splitSwitchButtonColors(
            checkedContainerColor = colors.errorContainer, …
          ),
        label = { Text("History Eraser") },
        secondaryLabel = { Text("Don't touch it!") },
      )
    // Wear RemoteCompose
      val colors = RemoteMaterialTheme.colorScheme
      RemoteSplitSwitchButton(
        checked = checked,
        onCheckedChange = onCheckedChange,
        toggleContentDescription = "Arm Eraser".rs,
        onContainerClick = onClick,
        modifier = modifier.fillMaxWidth(),
        colors =
          RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
            checkedContainerColor = colors.errorContainer, …
          ),
        label = { RemoteText("History Eraser".rs) },
        secondaryLabel = { RemoteText("Don't touch it!".rs) },
      )
  • Infine, vediamo il risultato. L'interfaccia utente risultante è esattamente quella che ti aspetteresti: un pulsante di attivazione/disattivazione pulito, reattivo e animato.

Supporto dell'anteprima di Compose per i widget

  • È difficile distinguere la differenza.

  • Per aiutarti a progettare, ripetere e verificare i layout dei widget senza doverli sempre eseguire su un dispositivo o un emulatore, abbiamo aggiunto il supporto dell'anteprima di Compose per i widget Wear.

  • Poiché i widget dipendono da vincoli del container specifici dell'OEM, come dimensioni, forma, spaziatura interna e raggio degli angoli, ci basiamo sull'annotazione di anteprima standard, ma con un provider di parametri aggiuntivo per inserire queste configurazioni.

    @Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
    @Composable
    fun WeatherWidgetSquirclePreview(
        @PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
    ) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
    
    @Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
    @Composable
    fun WeatherWidgetRoundPreview(
        @PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
    ) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
  • La libreria fornisce implementazioni del provider PreviewParameter preconfigurate che corrispondono ai dispositivi Wear OS reali.

  • Queste annotazioni di anteprima ti consentono di verificare facilmente il layout su diverse forme di hardware.

  • Oltre a testare i layout, puoi utilizzare queste anteprime per generare le immagini statiche richieste per il selettore di widget sul dispositivo.

    @Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
    @Composable
    fun WeatherWidgetRectangularPreview(
        @PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
    ) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
  • La libreria fornisce un parametro per la forma di anteprima rettangolare che emula i contenitori rettangolari completi non ritagliati.

Esempi di strumenti di implementazione e migrazione

  • Se vuoi vedere esattamente come funziona in pratica, abbiamo aggiornato la nostra app di esempio multimediale Horologist per includere un nuovo widget che mostra questa API.

  • Mostriamo come aggiungere sia la versione piccola sia quella grande del widget multimediale.

  • Dai un'occhiata su GitHub per vedere il confronto diretto tra il codice ProtoLayout precedente e la nuova implementazione di Remote Compose.

  • Siamo certi che ti piacerà.

  • Infine, non sarebbe un discorso completo senza menzionare l'AI.

  • Per velocizzare la migrazione, abbiamo pubblicato su GitHub una nuova skill per la migrazione da riquadri a widget.

  • Puoi utilizzarlo con l'agente che preferisci o aggiungerlo direttamente ad Android Studio utilizzando la CLI Android.

    android skills add wear-widgets
    android skills add --all
  • Ora passo la parola a François per concludere.

Riepilogo e tempo di wrap up

  • Grazie.

  • Grazie, Yuri.

  • Come puoi vedere, trasformare le tue schede in widget Wear è un processo molto semplice.

  • In sintesi, eseguendo la migrazione a Jetpack Glance Wear e Remote Compose, non stai semplicemente aggiornando la tua UI, ma stai entrando a far parte di un ecosistema di widget Android più unificato.

  • Ora puoi creare widget accattivanti e compatibili con le versioni precedenti utilizzando un framework moderno e dichiarativo completamente allineato a Jetpack Compose.

  • Puoi iniziare a eseguire la migrazione dei tuoi riquadri oggi stesso consultando la guida introduttiva sul sito per sviluppatori Android per tutti i dettagli.

  • Non vediamo l'ora di vedere tutte le esperienze espressive e di facile lettura che creerai per gli smartwatch.

  • Grazie mille per aver partecipato oggi, questa mattina, e ci auguriamo che il resto della conferenza sia di tuo gradimento.

  • Grazie.

Codice

Snippet di codice

Snippet Kotlin alle 06:40 in "Creazione dell'interfaccia utente con Remote Compose"
// Wear Compose
@Composable
fun HistoryEraserButton(
  onClick: () -> Unit,
  modifier: Modifier = Modifier,
  checked: Boolean = true,
  onCheckedChange: (Boolean) -> Unit = {},
)
Snippet di Kotlin al minuto 06:40 in "Creazione di UI con Remote Compose"
// Wear RemoteCompose
@RemoteComposable
@Composable
fun RemoteHistoryEraserButton(
  onClick: Action,
  modifier: RemoteModifier = RemoteModifier,
  checked: RemoteBoolean = true.rb,
  onCheckedChange: Action = Action.Empty,
)
Snippet di Kotlin al minuto 07:39 in "Building UI with Remote Compose"
// Wear Compose
  val colors = MaterialTheme.colorScheme
  SplitSwitchButton(
    checked = checked,
    onCheckedChange = onCheckedChange,
    toggleContentDescription = "Arm Eraser",
    onContainerClick = onClick,
    modifier = modifier.fillMaxWidth(),
    colors =
      SwitchButtonDefaults.splitSwitchButtonColors(
        checkedContainerColor = colors.errorContainer, …
      ),
    label = { Text("History Eraser") },
    secondaryLabel = { Text("Don't touch it!") },
  )
Snippet Kotlin al minuto 07:39 in "Building UI with Remote Compose"
// Wear RemoteCompose
  val colors = RemoteMaterialTheme.colorScheme
  RemoteSplitSwitchButton(
    checked = checked,
    onCheckedChange = onCheckedChange,
    toggleContentDescription = "Arm Eraser".rs,
    onContainerClick = onClick,
    modifier = modifier.fillMaxWidth(),
    colors =
      RemoteSplitSwitchButtonDefaults.splitSwitchButtonColors(
        checkedContainerColor = colors.errorContainer, …
      ),
    label = { RemoteText("History Eraser".rs) },
    secondaryLabel = { RemoteText("Don't touch it!".rs) },
  )
Snippet di Kotlin alle 08:20 in "Compose preview support for widgets"
@Preview(name = "Squircle Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetSquirclePreview(
    @PreviewParameter(SquircleAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)

@Preview(name = "Round Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRoundPreview(
    @PreviewParameter(RoundAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
Snippet di Kotlin al minuto 08:58 in "Supporto dell'anteprima di Compose per i widget"
@Preview(name = "Widget Picker Preview", device = "spec:width=1000dp,height=1000dp,dpi=320")
@Composable
fun WeatherWidgetRectangularPreview(
    @PreviewParameter(RectangularAllWidgetPreviewParams::class) params: WearWidgetParams
) = WearWidgetPreview(MockWeatherWidget(65, WeatherCondition.CLOUDY), params)
Snippet di shell al minuto 09:58 in "Sample implementation and migration tools"
android skills add wear-widgets
android skills add --all