Controllo delle versioni delle schede

Sui dispositivi Wear OS, i riquadri vengono visualizzati da due componenti chiave con versionamento indipendente. Per assicurarti che i riquadri delle app funzionino correttamente su tutti i dispositivi, è importante comprendere questa architettura di base.

  • Librerie relative ai riquadri di Jetpack: queste librerie (inclusi Wear Tiles e Wear ProtoLayout) sono incorporate nella tua app e tu, in qualità di sviluppatore, controlli le relative versioni. L'app utilizza queste librerie per creare un oggetto TileBuilder.Tile (la struttura di dati che rappresenta il riquadro) in risposta alla chiamata onTileRequest() del sistema.
  • ProtoLayout Renderer:questo componente di sistema è responsabile del rendering dell'oggetto Tile sul display e della gestione delle interazioni degli utenti. La versione del visualizzatore non è controllata dallo sviluppatore dell'app e può variare da un dispositivo all'altro, anche se hanno hardware identico.

L'aspetto o il comportamento di una scheda può variare in base alle versioni della libreria Jetpack Tiles della tua app e alla versione del Renderer ProtoLayout sul dispositivo dell'utente. Ad esempio, un dispositivo potrebbe supportare la rotazione o la visualizzazione dei dati sulla frequenza cardiaca, mentre un altro potrebbe non farlo.

Questo documento spiega come assicurarti che la tua app sia compatibile con le diverse versioni della libreria Tiles e del Renderer ProtoLayout e come eseguire la migrazione a versioni più recenti della libreria Jetpack.

Prendi in considerazione la compatibilità

Per creare un riquadro che funzioni correttamente su una serie di dispositivi, devi tenere conto di quanto segue.

Rileva la versione del renderer

  • Utilizza il metodo getRendererSchemaVersion() dell'oggetto DeviceParameters passato al metodo onTileRequest(). Questo metodo restituisce i numeri di versione maggiore e minore di ProtoLayout Renderer sul dispositivo.
  • Puoi quindi utilizzare la logica condizionale nell'implementazione di onTileRequest() per adattare il design o il comportamento del riquadro in base alla versione del visualizzatore rilevata.
    • Ad esempio, se un'animazione specifica non è supportata, puoi visualizzare un'immagine statica.

L'annotazione @RequiresSchemaVersion

  • L'annotazione @RequiresSchemaVersion sui metodi ProtoLayout indica la versione minima dello schema del renderer richiesta per il comportamento del metodo come documentato (esempio).
    • L'utilizzo di un metodo che richiede una versione del renderer superiore a quella disponibile sul dispositivo non causerà l'arresto anomalo dell'app, ma potrebbe comportare la mancata visualizzazione dei contenuti o l'ignoranza della funzionalità.

Esempio

override fun onTileRequest(
    requestParams: TileService.TileRequest
): ListenableFuture<Tile> {
    val rendererVersion =
        requestParams.deviceConfiguration.rendererSchemaVersion
    val tile = Tile.Builder()

    if (
        rendererVersion.major > 1 ||
            (rendererVersion.major == 1 && rendererVersion.minor >= 300)
    ) {
        // Use a feature supported in renderer version 1.300 or later
        tile.setTileTimeline(/* ... */ )
    } else {
        // Provide fallback content for older renderers
        tile.setTileTimeline(/* ... */ )
    }

    return Futures.immediateFuture(tile.build())
}

Esegui test con versioni diverse del renderer

Per testare i riquadri con versioni diverse del renderer, esegui il deployment in versioni diverse dell'emulatore Wear OS. Sui dispositivi fisici, gli aggiornamenti di ProtoLayout Renderer vengono forniti dal Play Store o dagli aggiornamenti di sistema. Non è possibile forzare l'installazione di una versione specifica del renderer.

La funzionalità Anteprima riquadri di Android Studio utilizza un visualizzatore incorporato nella libreria Jetpack ProtoLayout da cui dipende il codice, quindi un altro approccio è fare affidamento su versioni diverse della libreria Jetpack durante il test dei riquadri.

Esegui la migrazione a Tiles 1.5 / ProtoLayout 1.3 (Material 3 Expressive)

Aggiorna le librerie Jetpack Tile per usufruire dei più recenti miglioramenti, tra cui le modifiche all'interfaccia utente per integrare perfettamente i riquadri con il sistema.

Jetpack Tiles 1.5 e Jetpack ProtoLayout 1.3 introducono diversi miglioramenti e modifiche significativi. come le seguenti.

  • Un'API simile a Compose per descrivere l'interfaccia utente.
  • Componenti Material 3 Expressive, tra cui il pulsante con bordo che avvolge la parte inferiore e il supporto di immagini migliorate: animazioni Lottie, più tipi di gradiente e nuovi stili di linee curve. - Nota: alcune di queste funzionalità possono essere utilizzate anche senza eseguire la migrazione alla nuova API.

Consigli

  • Esegui la migrazione di tutti i riquadri contemporaneamente. Evita di mescolare le versioni dei riquadri all'interno della tua app. Sebbene i componenti di Material 3 risiedano in un elemento distinto (androidx.wear.protolayout:protolayout-material3), il che consente tecnicamente di utilizzare sia i riquadri M2.5 che quelli M3 nella stessa app, consigliamo vivamente di non adottare questo approccio, a meno che non sia assolutamente necessario (per esempio, se la tua app ha un numero elevato di riquadri di cui non è possibile eseguire la migrazione contemporaneamente).
  • Adotta le linee guida per l'esperienza utente di riquadri. Data la natura altamente strutturata e basata su modelli dei riquadri, utilizza i progetti negli esempi esistenti come punto di partenza per i tuoi progetti.
  • Esegui test su una varietà di schermi e dimensioni dei caratteri. Le schede spesso contengono molte informazioni, il che rende il testo (soprattutto se posizionato sui pulsanti) soggetto a overflow e ritaglio. Per ridurlo al minimo, utilizza i componenti predefiniti ed evita personalizzazioni eccessive. Esegui il test utilizzando la funzionalità di anteprima delle schede di Android Studio e su più dispositivi reali.

Processo di migrazione

Aggiorna le dipendenze

Innanzitutto, aggiorna il file build.gradle.kts. Aggiorna le versioni e modifica la dipendenza protolayout-material in protolayout-material3, come mostrato di seguito:

// In build.gradle.kts

//val tilesVersion = "1.4.1"
//val protoLayoutVersion = "1.2.1"

// Use these versions for M3.
val tilesVersion = "1.5.0-rc01"
val protoLayoutVersion = "1.3.0-rc01"

 dependencies {
     // Use to implement support for wear tiles
     implementation("androidx.wear.tiles:tiles:$tilesVersion")

     // Use to utilize standard components and layouts in your tiles
     implementation("androidx.wear.protolayout:protolayout:$protoLayoutVersion")

     // Use to utilize components and layouts with Material Design in your tiles
     // implementation("androidx.wear.protolayout:protolayout-material:$protoLayoutVersion")
     implementation("androidx.wear.protolayout:protolayout-material3:$protoLayoutVersion")

     // Use to include dynamic expressions in your tiles
     implementation("androidx.wear.protolayout:protolayout-expression:$protoLayoutVersion")

     // Use to preview wear tiles in your own app
     debugImplementation("androidx.wear.tiles:tiles-renderer:$tilesVersion")

     // Use to fetch tiles from a tile provider in your tests
     testImplementation("androidx.wear.tiles:tiles-testing:$tilesVersion")
 }

TileService rimane in gran parte invariato

Le modifiche principali di questa migrazione riguardano i componenti dell'interfaccia utente. Di conseguenza, l'implementazione di TileService, inclusi eventuali meccanismi di caricamento delle risorse, dovrebbe richiedere modifiche minime o nulle.

L'eccezione principale riguarda il monitoraggio delle attività dei riquadri: se la tua app utilizza onTileEnterEvent() o onTileLeaveEvent(), devi eseguire la migrazione a onRecentInteractionEventsAsync(). A partire dall'API 36, questi eventi verranno raggruppati.

Adatta il codice di generazione del layout

In ProtoLayout 1.2 (M2.5), il metodo onTileRequest() restituisce un TileBuilders.Tile. Questo oggetto conteneva vari elementi, tra cui un TimelineBuilders.Timeline, che a sua volta conteneva l'LayoutElement che descrive l'interfaccia utente del riquadro.

Con ProtoLayout 1.3 (M3), anche se la struttura e il flusso dei dati complessivi non sono stati modificati, il LayoutElement viene ora costruito utilizzando un approccio ispirato a Compose con un layout basato su slot definiti che sono (dall'alto verso il basso) il titleSlot (in genere per un titolo o un'intestazione principale), il mainSlot (per i contenuti principali) e il bottomSlot (spesso per azioni come un pulsante laterale o informazioni aggiuntive come un testo breve). Questo layout viene creato dalla funzione primaryLayout().

Il layout di un riquadro che mostra mainSlot, titleSlot, bottomSlot
Figura 1.: Le caselle di una scheda.
Confronto delle funzioni di layout M2.5 e M3

M2,5

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters
) =
    PrimaryLayout.Builder(deviceConfiguration)
        .setResponsiveContentInsetEnabled(true)
        .setContent(
            Text.Builder(context, "Hello World!")
                .setTypography(Typography.TYPOGRAPHY_BODY1)
                .setColor(argb(0xFFFFFFFF.toInt()))
                .build()
        )
        .build()

M3

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
) =
    materialScope(context, deviceConfiguration) {
        primaryLayout(mainSlot = { text("Hello, World!".layoutString) })
    }

Per evidenziare le differenze principali:

  1. Eliminazione degli sviluppatori. Il pattern di builder tradizionale per i componenti UI di Material3 viene sostituito da una sintassi più dichiarativa ispirata a Compose. Anche i componenti non UI come String/Color/Modifiers ricevono nuovi wrapper Kotlin.
  2. Funzioni di inizializzazione e layout standardizzate. I layout M3 si basano su funzioni di inizializzazione e struttura standardizzate: materialScope() e primaryLayout(). Queste funzioni obbligatorie inizializzano l'ambiente M3 (tema, ambito del componente tramite materialScope) e definiscono il layout principale basato su slot (tramite primaryLayout). Entrambe devono essere chiamate esattamente una volta per layout.

Applicazione tema

Colore

Una funzionalità di spicco di Material 3 Expressive è la "tecnologia di temi dinamici": i riquadri che attivano questa funzionalità (attiva per impostazione predefinita) verranno visualizzati nel tema fornito dal sistema (la disponibilità dipende dal dispositivo e dalla configurazione dell'utente).

Un'altra modifica in M3 è l'espansione del numero di token di colore, che è aumentato da 4 a 29. I nuovi token di colore sono disponibili nella classe ColorScheme.

Caratteri

Come M2.5, M3 si basa molto sulle costanti delle dimensioni dei caratteri predefinite. Si sconsiglia di specificare direttamente una dimensione del carattere. Queste costanti si trovano nella classe Typography e offrono una gamma leggermente più ampia di opzioni più espressive.

Per tutti i dettagli, consulta la documentazione relativa alla tipografia.

Forma

La maggior parte dei componenti M3 può variare in termini di forma e colore.

Un textButton (in mainSlot) con forma full:

Riquadro con forma &quot;completa&quot; (angoli più arrotondati)
Figura 2: Riquadro con forma "completa"

Lo stesso pulsante di testo con forma small:

Riquadro con forma &quot;piccola&quot; (angoli meno arrotondati)
Figura 3.: Riquadro con forma "Piccola"

Componenti

I componenti M3 sono molto più flessibili e configurabili rispetto ai loro omologhi M2.5. Mentre M2.5 spesso richiedeva componenti distinti per diversi trattamenti visivi, M3 utilizza spesso un componente "base" generalizzato, ma altamente configurabile, con valori predefiniti efficaci.

Questo principio si applica al layout "root". In M2.5, era un PrimaryLayout o un EdgeContentLayout. In M3, dopo aver stabilito un singolo MaterialScope di primo livello, viene chiamata la funzione primaryLayout(). Restituisce direttamente il layout principale (non sono necessari builder) e accetta LayoutElements per diversi "slot", come titleSlot, mainSlot e bottomSlot. Questi slot possono essere compilati con componenti UI specifici, come quelli restituiti da text(), button() o card(), oppure con strutture di layout, come Row o Column di LayoutElementBuilders.

I temi rappresentano un altro importante miglioramento di M3. Per impostazione predefinita, gli elementi dell'interfaccia utente si conformano automaticamente alle specifiche di stile di M3 e supportano i temi dinamici.

M2,5 M3
Elementi interattivi
Button o Chip
Testo
Text text()
Indicatori di avanzamento
CircularProgressIndicator circularProgressIndicator() o segmentedCircularProgressIndicator()
Layout
PrimaryLayout o EdgeContentLayout primaryLayout()
buttonGroup()
Immagini
icon(), avatarImage() o backgroundImage()

Modificatori

In M3, Modifiers, che utilizzi per decorare o aumentare un componente, sono più simili a Compose. Questa modifica può ridurre il codice boilerplate costruendo automaticamente i tipi interni appropriati. Questa modifica è ortogonale all'utilizzo dei componenti dell'interfaccia utente di M3. Se necessario, puoi utilizzare i modificatori in stile builder di ProtoLayout 1.2 con i componenti dell'interfaccia utente di M3 e viceversa.

M2,5

// A Builder-style modifier to set the opacity of an element to 0.5
fun myModifier(): ModifiersBuilders.Modifiers =
    ModifiersBuilders.Modifiers.Builder()
        .setOpacity(TypeBuilders.FloatProp.Builder(0.5F).build())
        .build()

M3

// The equivalent Compose-like modifier is much simpler
fun myModifier(): LayoutModifier = LayoutModifier.opacity(0.5F)

Puoi creare modificatori utilizzando entrambi gli stili API e puoi anche utilizzare la funzione di estensione toProtoLayoutModifiers() per convertire un LayoutModifier in un ModifiersBuilders.Modifier.

Funzioni di supporto

Sebbene ProtoLayout 1.3 consenta di esprimere molti componenti dell'interfaccia utente utilizzando un'API ispirata a Compose, gli elementi di layout di base come rows e columns di LayoutElementBuilders continuano a utilizzare il pattern del costruttore. Per colmare questa differenza stilistica e promuovere la coerenza con le nuove API dei componenti M3, ti consigliamo di utilizzare le funzioni di supporto.

Senza assistenti

primaryLayout(
    mainSlot = {
        LayoutElementBuilders.Column.Builder()
            .setWidth(expand())
            .setHeight(expand())
            .addContent(text("A".layoutString))
            .addContent(text("B".layoutString))
            .addContent(text("C".layoutString))
            .build()
    }
)

Con collaboratori

// Function literal with receiver helper function
fun column(builder: Column.Builder.() -> Unit) =
    Column.Builder().apply(builder).build()

primaryLayout(
    mainSlot = {
        column {
            setWidth(expand())
            setHeight(expand())
            addContent(text("A".layoutString))
            addContent(text("B".layoutString))
            addContent(text("C".layoutString))
        }
    }
)

Eseguire la migrazione a Tiles 1.2 / ProtoLayout 1.0

A partire dalla versione 1.2, la maggior parte delle API di layout delle riquadri si trova nello spazio dei nomi androidx.wear.protolayout. Per utilizzare le API più recenti, completa i seguenti passaggi di migrazione nel tuo codice.

Aggiorna le dipendenze

Nel file di build del modulo dell'app, apporta le seguenti modifiche:

Groovy

  // Remove
  implementation 'androidx.wear.tiles:tiles-material:version'

  // Include additional dependencies
  implementation "androidx.wear.protolayout:protolayout:1.2.1"
  implementation "androidx.wear.protolayout:protolayout-material:1.2.1"
  implementation "androidx.wear.protolayout:protolayout-expression:1.2.1"

  // Update
  implementation "androidx.wear.tiles:tiles:1.4.1"

Kotlin

  // Remove
  implementation("androidx.wear.tiles:tiles-material:version")

  // Include additional dependencies
  implementation("androidx.wear.protolayout:protolayout:1.2.1")
  implementation("androidx.wear.protolayout:protolayout-material:1.2.1")
  implementation("androidx.wear.protolayout:protolayout-expression:1.2.1")

  // Update
  implementation("androidx.wear.tiles:tiles:1.4.1")

Aggiorna gli spazi dei nomi

Apporta i seguenti aggiornamenti ai file di codice basati su Kotlin e Java della tua app. In alternativa, puoi eseguire questo script di rinominazione dello spazio dei nomi.

  1. Sostituisci tutte le importazioni di androidx.wear.tiles.material.* con androidx.wear.protolayout.material.*. Completa questo passaggio anche per la biblioteca androidx.wear.tiles.material.layouts.
  2. Sostituisci la maggior parte delle altre importazioni di androidx.wear.tiles.* con androidx.wear.protolayout.*.

    Le importazioni per androidx.wear.tiles.EventBuilders, androidx.wear.tiles.RequestBuilders, androidx.wear.tiles.TileBuilders e androidx.wear.tiles.TileService dovrebbero rimanere invariate.

  3. Rinomina alcuni metodi deprecati delle classi TileService e TileBuilder:

    1. TileBuilders: da getTimeline() a getTileTimeline() e da setTimeline() a setTileTimeline()
    2. TileService: da onResourcesRequest() a onTileResourcesRequest()
    3. RequestBuilders.TileRequest: da getDeviceParameters() a getDeviceConfiguration(), da setDeviceParameters() a setDeviceConfiguration(), da getState() a getCurrentState() e da setState() a setCurrentState()