Em dispositivos Wear OS, os blocos são renderizados por dois componentes principais com versão independente. Para garantir que os blocos de apps funcionem corretamente em todos os dispositivos, é importante entender essa arquitetura.
- Bibliotecas relacionadas a blocos do Jetpack: essas bibliotecas (incluindo os blocos do Wear
e o Wear ProtoLayout) são incorporadas ao app, e você, como desenvolvedor,
controla as versões delas. O app usa essas bibliotecas para construir um objeto
TileBuilder.Tile
(a estrutura de dados que representa seu Bloco) em resposta à chamadaonTileRequest()
do sistema. - ProtoLayout Renderer:esse componente do sistema é responsável por renderizar
o objeto
Tile
na tela e processar as interações do usuário. A versão do renderizador não é controlada pelo desenvolvedor do app e pode variar entre dispositivos, mesmo aqueles com hardware idêntico.
A aparência ou o comportamento de um Bloco pode variar com base nas versões da biblioteca Jetpack Tiles do app e na versão do ProtoLayout Renderer no dispositivo do usuário. Por exemplo, um dispositivo pode oferecer suporte à rotação ou à exibição de dados de frequência cardíaca, enquanto outro não.
Este documento explica como garantir que seu app seja compatível com diferentes versões da biblioteca Tiles e do ProtoLayout Renderer e como migrar para versões mais recentes da biblioteca do Jetpack.
Considere a compatibilidade
Para criar um Bloco que funcione corretamente em vários dispositivos, considere o seguinte:
Detectar a versão do renderizador
- Use o método
getRendererSchemaVersion()
do objetoDeviceParameters
transmitido para o método onTileRequest(). Esse método retorna os números de versão principal e secundária do renderizador ProtoLayout no dispositivo. - Em seguida, use a lógica condicional na implementação de
onTileRequest()
para adaptar o design ou o comportamento do Bloco com base na versão do renderizador detectada.- Por exemplo, se uma animação específica não tiver suporte, você poderá mostrar uma imagem estática.
A anotação @RequiresSchemaVersion
- A anotação
@RequiresSchemaVersion
em métodos ProtoLayout indica a versão mínima do esquema do renderizador necessária para que esse método se comporte como documentado (exemplo).- Chamar um método que exige uma versão mais recente do renderizador do que está disponível no dispositivo não faz com que o app falhe, mas pode fazer com que o conteúdo não seja exibido ou o recurso seja ignorado.
Exemplo
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())
}
Testar com diferentes versões do renderizador
Para testar os Blocos em diferentes versões do renderizador, implante-os em diferentes versões do emulador do Wear OS. Em dispositivos físicos, as atualizações do ProtoLayout Renderer são enviadas pela Play Store ou pelo sistema. Não é possível forçar a instalação de uma versão específica do renderizador.
O recurso de visualização de blocos do Android Studio usa um renderizador incorporado na biblioteca Jetpack ProtoLayout da qual seu código depende. Portanto, outra abordagem é depender de diferentes versões da biblioteca do Jetpack ao testar blocos.
Migrar para o Tiles 1.5 / ProtoLayout 1.3 (Material 3 Expressivo)
Atualize as bibliotecas de blocos do Jetpack para aproveitar os aprimoramentos mais recentes, incluindo mudanças na interface para integrar os blocos ao sistema.
O Jetpack Tiles 1.5 e o Jetpack ProtoLayout 1.3 apresentam várias melhorias e mudanças importantes. São eles:
- Uma API semelhante ao Compose para descrever a interface.
- Componentes Expressivo do Material 3, incluindo o botão de borda inferior e suporte a recursos visuais aprimorados: animações Lottie, mais tipos de gradiente e novos estilos de linha de arco. - Observação: alguns desses recursos também podem ser usados sem migrar para a nova API.
Recomendações
- Migrar todos os blocos ao mesmo tempo. Evite misturar versões de blocos
no app. Embora os componentes do Material 3 residam em um artefato
separado (
androidx.wear.protolayout:protolayout-material3
), o que torna tecnicamente possível usar os blocos M2.5 e M3 no mesmo app, recomendamos fortemente essa abordagem, a menos que seja absolutamente necessário (por exemplo, se o app tiver um grande número de blocos que não podem ser migrados de uma só vez). - Adotar a orientação de UX dos Blocos. Dada a natureza altamente estruturada e de modelo dos blocos, use os designs nas amostras atuais como pontos de partida para seus próprios designs.
- Teste em vários tamanhos de tela e fontes. Os blocos geralmente têm muitas informações, o que faz com que o texto (especialmente quando colocado em botões) seja suscetível a transbordamento e recorte. Para minimizar isso, use os componentes pré-criados e evite a personalização excessiva. Teste usando o recurso de visualização de blocos do Android Studio e em vários dispositivos reais.
Processo de migração
Atualizar dependências
Primeiro, atualize o arquivo build.gradle.kts
. Atualize as versões e mude a
dependência protolayout-material
para protolayout-material3
, conforme mostrado:
// 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")
}
O TileService permanece praticamente inalterado
As principais mudanças nessa migração afetam os componentes da interface. Consequentemente,
a implementação de TileService
, incluindo mecanismos de carregamento de recursos,
precisa de poucas ou nenhuma modificação.
A principal exceção envolve o rastreamento de atividades de blocos: se o app usa
onTileEnterEvent()
ou onTileLeaveEvent()
, migre para
onRecentInteractionEventsAsync()
. A partir da API 36, esses eventos
serão agrupados.
Adaptar o código de geração de layout
No ProtoLayout 1.2 (M2.5), o método onTileRequest()
retorna um
TileBuilders.Tile
. Esse objeto continha vários elementos, incluindo um
TimelineBuilders.Timeline
, que, por sua vez, continha o LayoutElement
que descreve a interface do bloco.
Com o ProtoLayout 1.3 (M3), embora a estrutura e o fluxo de dados gerais não tenham
mudado, o LayoutElement
agora é construído usando uma abordagem inspirada no Compose
com um layout baseado em slots definidos, que são (de cima para baixo)
titleSlot
(normalmente para um título ou cabeçalho principal), mainSlot
(para o
conteúdo principal) e bottomSlot
(geralmente para ações como um botão de borda ou
informações complementares, como texto curto). Esse layout é construído pela função
primaryLayout()
.

Comparação das funções de 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) })
}
Para destacar as principais diferenças:
- Eliminação de Builders. O padrão de builder tradicional para componentes da interface do Material3 é substituído por uma sintaxe mais declarativa inspirada no Compose. Os componentes que não são da interface, como String/Color/Modifiers, também recebem novos wrappers do Kotlin.
- Funções de inicialização e layout padronizadas. Os layouts do M3 dependem de
funções de inicialização e estrutura padronizadas:
materialScope()
eprimaryLayout()
. Essas funções obrigatórias inicializam o ambiente M3 (tema, escopo do componente pelomaterialScope
) e definem o layout principal baseado em slot (peloprimaryLayout
). Ambas precisam ser chamadas exatamente uma vez por layout.
Temas
Cor
Um recurso de destaque do Material 3 Expressivo é a "aplicação de temas dinâmicos": os blocos que ativam esse recurso (ativado por padrão) serão mostrados no tema fornecido pelo sistema (a disponibilidade depende do dispositivo e da configuração do usuário).
Outra mudança no M3 é a expansão do número de tokens de cor, que aumentou
de 4 para 29. Os novos tokens de cor podem ser encontrados na
classe ColorScheme
.
Tipografia
Assim como o M2.5, o M3 depende muito de constantes de tamanho de fonte predefinidas. Não é recomendável
especificar diretamente um tamanho de fonte. Essas constantes estão localizadas na classe
Typography
e oferecem uma gama um pouco mais ampla de opções
mais expressivas.
Para mais detalhes, consulte a documentação sobre tipografia.
Forma
A maioria dos componentes do M3 pode variar de acordo com a dimensão da forma e da cor.
Um textButton
(no mainSlot
) com a forma full
:

O mesmo textButton com a forma small
:

Componentes
Os componentes do M3 são muito mais flexíveis e configuráveis do que os equivalentes do M2.5. Enquanto a M2.5 geralmente exigia componentes distintos para tratamentos visuais variados, a M3 frequentemente emprega um componente "base" generalizado, mas altamente configurável, com bons padrões.
Esse princípio se aplica ao layout "raiz". No M2.5, era um
PrimaryLayout
ou um EdgeContentLayout
. No M3, depois que uma única
MaterialScope
de nível superior é estabelecida, a função
primaryLayout()
é chamada. Isso retorna o layout raiz diretamente (sem necessidade de builders) e
aceita LayoutElements
para vários "slots", como titleSlot
, mainSlot
e bottomSlot
. Esses slots podem ser preenchidos com componentes de interface concretos, como
os retornados por text(), button() ou card(), ou estruturas
de layout, como Row
ou Column
de LayoutElementBuilders
.
Os temas são outra melhoria importante do M3. Por padrão, os elementos da interface atendem automaticamente às especificações de estilo do M3 e oferecem suporte a temas dinâmicos.
M2.5 | M3 |
---|---|
Elementos interativos | |
Button ou Chip |
|
Texto | |
Text |
text() |
Indicadores de progresso | |
CircularProgressIndicator |
circularProgressIndicator() ou segmentedCircularProgressIndicator() |
Layout | |
PrimaryLayout ou EdgeContentLayout |
primaryLayout() |
— | buttonGroup() |
Imagens | |
— | icon() , avatarImage() ou backgroundImage() |
Modificadores
No M3, o Modifiers
, que você usa para decorar ou aumentar um componente, é
mais parecido com o Compose. Essa mudança pode reduzir o modelo padrão ao construir
automaticamente
os tipos internos apropriados. Essa mudança é ortogonal ao uso de componentes de interface
M3. Se necessário, use modificadores no estilo de builder do
ProtoLayout 1.2 com componentes de interface M3 e vice-versa.
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)
É possível criar modificadores usando qualquer estilo de API e também usar a
função de extensão toProtoLayoutModifiers()
para converter um
LayoutModifier
em um ModifiersBuilders.Modifier
.
Funções auxiliares
Embora o ProtoLayout 1.3 permita que muitos componentes da interface sejam expressos usando uma
API inspirada no Compose, elementos de layout básicos, como linhas e
colunas do LayoutElementBuilders
, continuam usando o padrão
do builder. Para preencher essa lacuna estilística e promover a consistência com as
novas APIs de componentes M3, use funções auxiliares.
Sem auxiliares
primaryLayout(
mainSlot = {
LayoutElementBuilders.Column.Builder()
.setWidth(expand())
.setHeight(expand())
.addContent(text("A".layoutString))
.addContent(text("B".layoutString))
.addContent(text("C".layoutString))
.build()
}
)
Com ajudantes
// 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))
}
}
)
Migrar para Tiles 1.2 / ProtoLayout 1.0
Na versão 1.2 e mais recentes, a maioria das APIs de layout de blocos está no namespace
androidx.wear.protolayout
. Para usar as APIs mais recentes, siga as etapas de migração abaixo no seu código.
Atualizar dependências
No arquivo de build do módulo do app, faça estas mudanças:
Groovy
// Removeimplementation '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
// Removeimplementation("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")
Atualizar namespaces
Nos arquivos de código com base em Kotlin e Java do seu app, faça estas mudanças. Como alternativa, execute este script de renomeação de namespace (link em inglês).
- Substitua todas as importações
androidx.wear.tiles.material.*
porandroidx.wear.protolayout.material.*
. Conclua essa etapa para a bibliotecaandroidx.wear.tiles.material.layouts
também. Substitua a maioria das outras importações
androidx.wear.tiles.*
porandroidx.wear.protolayout.*
.As importações para
androidx.wear.tiles.EventBuilders
,androidx.wear.tiles.RequestBuilders
,androidx.wear.tiles.TileBuilders
eandroidx.wear.tiles.TileService
precisam ser as mesmas.Renomeie alguns métodos descontinuados das classes TileService e TileBuilder:
TileBuilders
:getTimeline()
paragetTileTimeline()
esetTimeline()
parasetTileTimeline()
TileService
:onResourcesRequest()
paraonTileResourcesRequest()
RequestBuilders.TileRequest
:getDeviceParameters()
paragetDeviceConfiguration()
,setDeviceParameters()
parasetDeviceConfiguration()
,getState()
paragetCurrentState()
esetState()
parasetCurrentState()