Como parte de nosso trabalho para modernizar as orientações sobre arquitetura de apps, queremos experimentar diferentes padrões de IU para ver o que funciona melhor, encontrar semelhanças e diferenças entre as alternativas e consolidar nossas descobertas como práticas recomendadas.
Para facilitar ao máximo a aplicação de nossas descobertas, precisávamos de uma amostra com um caso de negócios familiar e que não fosse muito complicada. E quem é que não conhece os apps TODO ? Escolhemos o Architecture Blueprints! O Blueprints sempre serviu como um playground experimental para escolhas de arquitetura. E ele é ótimo para isso!
Os padrões com os quais queremos fazer experiências são claramente afetados pelas diferentes APIs disponíveis atualmente. E a novidade são as APIs de estado do Jetpack Compose! Como o Compose funciona perfeitamente com qualquer padrão de fluxo de dados unidirecional , vamos utilizá-lo para renderizar a IU e fazer uma comparação justa.
Esta postagem do blog conta como a equipe migrou o Architecture Blueprints para o Jetpack Compose. Como o LiveData também é considerado uma alternativa em nossos experimentos, deixamos a amostra no estado em que se encontrava no momento da migração. Nessa refatoração, as classes ViewModel e a camada de dados permaneceram inalteradas.
⚠️ A arquitetura usada nesta base de código baseada no LiveData não segue totalmente as práticas recomendadas de arquitetura mais recentes. Em particular, o LiveData não deve ser usado nas camadas de dados ou de domínios. Devem-se usar fluxos e corrotinas.
Agora que o contexto já ficou claro, vamos detalhar como abordamos a refatoração do Blueprints para o Jetpack Compose. Confira o código completo na ramificação dev-compose.
Antes de realizar qualquer codificação real, a equipe criou um plano de migração para garantir que todos concordassem com as mudanças propostas. O objetivo final era que o Blueprints fosse um aplicativo de atividade única, com telas como funções que podem ser compostas e usando a biblioteca Compose Navigation recomendada para a movimentação entre as telas.
Felizmente, o Blueprints já era um app de atividade única que usava o Jetpack Navigation para a movimentação entre diferentes telas implementadas com fragmentos. Para migrar para o Compose, seguimos as orientações de interoperabilidade do Navigation, que recomendam que os apps híbridos usem o componente Navigation baseado em fragmentos para conter telas baseadas em visualização, telas do Compose e telas que usam tanto as visualizações quanto o Compose. Infelizmente, não é possível combinar os destinos dos fragmentos e do Compose no mesmo gráfico do Navigation.
O objetivo de uma migração gradual é facilitar as revisões de código e manter um produto em condições de entrega ao longo de toda a migração. O plano de migração envolvia três passos:
E foi isso o que fizemos! 🧑💻 Depois ⏩ de duas semanas, migramos as telas Statistics (PR), Add/Edit task (PR), Task detail (PR) e Tasks (PR) e mesclamos a PR final que migrou a lógica Activity e Navigation para o Compose, incluindo a remoção das dependências do sistema de visualização não utilizadas.
Durante a migração, encontramos algumas peculiaridades específicas do Compose que valem destaque:
Assim que você começa a adicionar o Compose ao app, os testes que declaram IUs do Compose precisam usar APIs de teste do Compose.
Para os testes de IU no nível de tela, em vez de usar a API launchFragmentInContainer<FragmentType>, usamos a API createAndroidComposeRule<ComponentActivity>, que permite capturar recursos de strings nos testes. Esses testes são executados no Espresso e no Robolectric. Como o Compose já tem suporte para tudo isso, nenhuma mudança adicional foi necessária. Por exemplo, é possível comparar o código em AddEditTaskFragmentTest que foi migrado para AddEditTaskScreenTest. Observe que, se você usar o ComponentActivity, precisará contar com o artefato androidx.compose.ui:ui-test-manifest.
Nos testes completos ou de integração, também não tivemos nenhum problema. Graças à interoperabilidade do Espresso e do Compose, usamos as declarações do Espresso para verificar as visualizações e as APIs do Compose para verificar a IU do Compose. Aqui, podemos ver a aparência de AppNavigationTest em um ponto durante a migração para o Compose.
Tivemos problemas com o modo como os eventos do ViewModel eram manipulados no Blueprints. O Blueprints implementava uma solução de wrapper de evento para enviar comandos do ViewModel para a IU. No entanto, isso não funciona no Compose. Nossas orientações recentes recomendam a modelagem desses "eventos" como estado, e foi isso o que fizemos durante a migração.
Se observarmos o caso de uso do evento de exibição de mensagens na tela , substituímos o tipo Event<Int>do LiveData por "Int?". Isso também modela o cenário no qual não há mensagens a serem exibidas para o usuário. Nesse caso de uso em particular, o ViewModel também exige uma confirmação da IU sempre que a mensagem é exibida. Veja a diferença entre as duas implementações no seguinte código:
Embora isso possa parecer um trabalho adicional, à primeira vista, é uma garantia de que a mensagem seja exibida na tela.
No código da IU, a forma de assegurar que o evento seja manipulado apenas uma vez é fazer uma chamada para event.getContentIfNotHandled(). Essa abordagem funciona mais ou menos nos fragmentos, mas falha totalmente no Compose. Como as recomposições podem ocorrer a qualquer momento no Compose, o wrapper de evento não é uma solução válida. Se o evento for processado e a função for recomposta (algo que aconteceu bastante durante o teste dessa abordagem), o snackbar será cancelado, e o usuário poderá perder a mensagem. Esse é um problema de UX inaceitável! A solução wrapper de evento não deve ser usada em apps do Compose.
Veja o snippet de código a seguir com o antes (wrapper de evento) e o depois (evento como estado) do código. Como a exibição de mensagens na tela envolve a lógica de IU e as funções de tela que podem ser compostas estavam se tornando mais complexas, usamos uma classe detentora de estado simples para gerenciar essa complexidade (veja, por exemplo, AddEditTaskState).
Durante a refatoração, pode ser tentador migrar tudo para o Compose. Embora não haja nenhum problema nisso, você não deve sacrificar a experiência do usuário nem a precisão do app. A finalidade de fazer uma migração gradual é que o app esteja sempre em condições de entrega.
Isso aconteceu conosco durante a migração de algumas telas para o Compose. Não queríamos fazer um monte de migrações ao mesmo tempo, então migramos algumas das telas para o Compose antes da migração do wrapper de evento. Em vez de manipular o wrapper de evento no Compose e entregar uma experiência insatisfatória, continuamos manipulando essas mensagens no fragmento, enquanto o restante do código da tela estava no Compose. Veja, por exemplo, o estado de TasksFragment durante a migração.
Nem tudo correu tão bem quanto parecia. 🫤 Embora a conversão de conteúdo de fragmentos para o Compose seja direta, a migração dos fragmentos do Navigation para o Navigation Compose exigiu um pouco mais de tempo e raciocínio.
É necessário expandir e melhorar as orientações quanto a diferentes aspectos que tornarão a migração para o Compose mais simples no futuro. Esse trabalho provocou várias conversas, e esperamos ter novas orientações sobre isso em breve! 🎊
Por ser iniciante em Navigation ✋ e a pessoa que lidou com a migração para o Navigation Compose, enfrentei os seguintes desafios:
Em geral, a migração de fragmentos do Navigation para o Navigation Compose foi bem divertida! O mais engraçado é que gastamos mais tempo aguardando revisões de pares do que fazendo a migração do projeto em si! Criar o plano de migração e sincronizar todo mundo com certeza ajudou a definir as expectativas logo no começo e alertar os pares sobre futuras revisões demoradas.
Esperamos que você tenha gostado de ler sobre nossa abordagem da migração para o Compose, e queremos compartilhar em breve mais informações sobre os experimentos e as melhorias que faremos no Architecture Blueprints.
Caso tenha interesse em ver o Blueprints com o código do Compose, confira a ramificação dev-compose. E, caso deseje ver todas as PRs da migração gradual, esta é a lista:
Postado por Marwa Mabrouk, gerente de produtos da plataforma de câmera do Android
A câmera do Android é um recurso apaixonante. A câmera é um dos principais motivos pelos quais as pessoas compram um smartphone. A câmera do Android beneficia os desenvolvedores atuais por meio de várias ferramentas. Camera 2 é a API de framework que faz parte do Android desde a versão 5.0 Lollipop, e CameraX é uma biblioteca de suporte do Jetpack executada com base no Camera 2 e disponibilizada para todos os desenvolvedores Android. Essas soluções foram criadas para se complementar mutuamente a fim de atender às necessidades do ecossistema de câmera do Android.
Para os desenvolvedores que estão começando a trabalhar com a câmera do Android, atualizando apps ou migrando apps do Camera 1, o CameraX é a melhor ferramenta para começar. O CameraX oferece benefícios importantes que dão mais poder aos desenvolvedores e lidam com as complexidades do ecossistema.
Para os desenvolvedores que estão criando funcionalidades altamente especializadas com a câmera para o controle detalhado do fluxo de captura, no qual devem ser levadas em conta as variações de dispositivos, o Camera 2 deve ser utilizado.
Camera 2 é a API comum que ativa o hardware da câmera de todos os dispositivos Android e é implantada em todos os bilhões de dispositivos Android atualmente existentes no mercado mundial. Por ser uma API de framework, o Camera 2 permite que os desenvolvedores utilizem seu profundo conhecimento em fotografia e implementações em dispositivos. Para assegurar a qualidade do Camera 2, os fabricantes de dispositivos demonstram a conformidade por meio de testes em seus dispositivos. As variações dos dispositivos aparecem na API com base nas escolhas dos fabricantes dos dispositivos, permitindo que recursos personalizados se beneficiem dessas variações em dispositivos específicos da melhor forma possível.
Vejamos um exemplo que ajuda a explicar isso. Vamos comparar recursos de captura com a câmera. O Camera 2 oferece um controle especial do pipeline individual de captura para cada uma das câmeras no telefone ao mesmo tempo, além de configurações manuais muito detalhadas. O CameraX permite a captura de fotos de alta resolução e qualidade, além de oferecer funcionalidades de balanço automático de branco, exposição automática e foco automático e controles manuais simples para a câmera.
Exemplos relacionados a aplicativos: a Samsung usa a API de framework da câmera para ajudar o sistema avançado de câmera profissional a capturar fotos com qualidade de estúdio em vários tipos de iluminação e ambientes usando dispositivos Samsung Galaxy. Embora a API seja comum, a Samsung ativou variações que são exclusivas para os recursos de cada um dos dispositivos, e ela se beneficia da API no app de câmera de cada um deles, também. A API de framework da câmera permite que a Samsung faça uso dos recursos mais avançados da câmera e adapte o app nativo para o dispositivo.
Como outro exemplo, a Microsoft decidiu integrar o CameraX a todos os apps de produtividade nos quais o Microsoft Lens é utilizado (ou seja, Office, Outlook e OneDrive), para assegurar o uso de imagens de alta qualidade em todos esses aplicativos. Com a mudança para o CameraX, a equipe do Microsoft Lens conseguiu não só melhorar a experiência dos desenvolvedores devido à simplicidade da API, como também melhorar o desempenho, elevar a produtividade dos desenvolvedores e reduzir o tempo de entrada no mercado. Saiba mais aqui.
Esta é uma fase muito empolgante para a câmera do Android, e há muitos recursos novos nas duas APIs:
À medida que avançamos, compartilharemos com os desenvolvedores mais detalhes sobre os grandes recursos planejados para a câmera do Android. Esperamos interagir com vocês e receber seu feedback por meio da lista de e-mails do CameraX, camerax-developers@android.com, e do Issue Tracker do AOSP.
Agradecemos o interesse contínuo na câmera do Android, e esperamos criar experiências incríveis com a câmera para os usuários por meio da colaboração com vocês!
Postado por Lauren Mytton, gerente de produtos, Google Play
A qualidade é fundamental para o sucesso de um jogo ou app no Google Play, e o Android Vitals no Google Play Console é uma excelente maneira de monitorar o desempenho dos apps. Na verdade, mais de mais de 80% dos milhares de desenvolvedores experientes verificam o Android Vitals pelo menos uma vez por mês para monitorar a qualidade técnica e resolver problemas, e muitos deles fazem isso diariamente.Embora a visão geral do Android Vitals no Play Console permita verificar rapidamente a qualidade de um jogo ou app, muitos desenvolvedores nos disseram que também queriam trabalhar com os dados do Vitals fora do Play Console. Os casos de uso incluem:
A partir de hoje, esses casos de uso são possíveis com a nova API Play Developer Reporting.
Com a API Play Developer Reporting, os desenvolvedores podem trabalhar com dados no nível do app em suas contas de desenvolvedor fora do Play Console. Nesta versão inicial, você tem acesso às quatro principais métricas de bateria e estabilidade do Android Vitals: taxa de falhas, taxa de ANR, taxa de ativações excessivas e taxa de wake-locks em segundo plano travados, além de problemas de ANR e falhas e stack traces. Também é possível visualizar anomalias, detalhamentos (inclusive novos filtros de país no Vitals) e três anos de histórico de métricas.
Configuração do acesso à nova API Play Developer Reporting na página API Access do Play Console.
Para ativar a API, você deve ter uma conta de desenvolvedor no Play Console. Depois, é possível configurar o acesso rapidamente na página API Access do Play Console. Nossa documentação contém tudo o que você precisa saber para dar os primeiros passos.
Na documentação da API, estão disponíveis amostras de solicitações e uma lista dos endpoints disponíveis (para as versões Alfa e Beta).
Depois de ativar a API, é recomendável enviar algumas solicitações manualmente para ter uma noção da operação e dos recursos da API antes de implementar soluções mais complexas. Isso também pode ajudar a determinar tempos de consulta, que podem variar de acordo com o volume de dados em processamento. A execução de consultas em longos intervalos de tempo, em muitas dimensões e/ou em apps muito grandes, pode demorar muito.
A maioria dos nossos conjuntos de métricas é atualizada uma vez por dia. Para evitar o desperdício de recursos e cotas de solicitação, recomendamos a utilização dos métodos fornecidos para verificar o nível de atualização dos dados e se novos dados estão disponíveis antes de emitir uma consulta.
Agradecemos a todos os desenvolvedores que solicitaram esse recurso. Esperamos que isso ajude vocês a continuar melhorando os apps e jogos. Para saber mais sobre o Android Vitals e a API Play Developer Reporting, assista à nossa sessão no Google for Games Developer Summit.
Esta postagem do blog foi útil para você?
★ ★ ★ ★ ★
Postado por Krish Vitaldevara, diretor de gerenciamento de produtos
O Google Play ajuda nossa comunidade de desenvolvedores a distribuir os apps mais inovadores e confiáveis do mundo para bilhões de pessoas. Esse é um processo contínuo, e nós estamos sempre trabalhando para encontrar formas de aumentar a segurança dos apps em todo o ecossistema.
Além dos recursos e das políticas do Google Play que são fundamentais para o fornecimento de uma experiência segura para os usuários, todas as atualizações do SO Android trazem melhorias de privacidade, segurança e experiência do usuário. Para garantir que os usuários se beneficiem totalmente desses avanços e para manter a experiência confiável que as pessoas esperam do Google Play, colaboramos com os desenvolvedores para assegurar que os apps funcionem perfeitamente nas versões mais recentes do Android.
No momento, exigimos que os novos apps e as atualizações de apps sejam segmentados para um determinado nível de API do Android no máximo um ano depois do mais recente lançamento de uma versão principal do SO Android. Os novos apps e as atualizações de apps que não atendem a esse requisito não podem ser publicados no Google Play. Para ver os cronogramas exatos, consulte este artigo da Central de Ajuda.
Requisitos atuais de nível de API de destino para novos apps e atualizações de apps
Hoje, como parte das mais recentes atualizações de políticas do Google Play, estamos tomando medidas adicionais, por meio da expansão dos requisitos de nível de API de destino, para proteger os usuários contra a instalação de apps que podem não ter os recursos mais recentes de privacidade e segurança.
A partir de 1º de novembro de 2022, os apps existentes que não segmentarem um nível de API dentro de dois anos da mais recente versão principal do Android não serão disponibilizados para descoberta ou instalação por novos usuários com dispositivos que executem versões do SO Android superiores ao nível de API de destino do app. Quando novas versões do SO Android forem lançadas no futuro, a janela do requisito será ajustada adequadamente.
Requisitos de nível de API de destino para apps existentes a partir de 1º de novembro
A lógica por trás dessa decisão é simples. Os usuários com os dispositivos mais recentes ou que fazem todas as atualizações do Android esperam aproveitar todo o potencial de todas as proteções de privacidade e segurança oferecidas pelo Android. A expansão dos requisitos de nível de API de destino protegerá os usuários contra a instalação de apps mais antigos que podem não ter essas proteções implementadas.
A boa notícia é que a enorme maioria dos apps no Google Play já segue esses padrões. No caso de outros apps, sabemos que isso exigirá atenção adicional, e é por isso que estamos notificando os desenvolvedores com bastante antecedência e fornecendo recursos para aqueles que necessitam.
Encorajamos você a:
Os usuários atuais de apps mais antigos que tiverem feito a instalação pelo Google Play continuarão tendo a capacidade de descobrir, reinstalar e usar o app em qualquer dispositivo com qualquer versão do SO Android à qual o app dê suporte.
Essa política reforçada de nível de API de destino é apenas uma das atualizações de políticas que anunciamos hoje para expandir as proteções e melhorar as experiências dos usuários no Google Play. Continuaremos compartilhando atualizações sobre esse importante trabalho, que ajudará a elevar o nível de privacidade e segurança de apps em todos os aspectos, fazendo do Google Play e do Android locais mais seguros para todos.
Postado por Max Bires, engenheiro de software
Como recurso, o atestado é obrigatório desde o Android 8.0. Ao longo das várias versões, ele foi se tornando cada vez mais fundamental para a confiabilidade de diversos recursos e serviços, como SafetyNet, Identity Credential, Digital Car Key, e de muitas bibliotecas de terceiros. Em vista disso, chegou a hora de revisar nossa infraestrutura de atestados para reforçar a segurança da cadeia de confiança e aumentar a capacidade de recuperação da confiabilidade dos dispositivos em caso de vulnerabilidades conhecidas.
A partir do Android 12.0, forneceremos uma opção de substituição do provisionamento de chaves privadas de fábrica por uma combinação de extração de chaves privadas de fábrica e provisionamento OTA de certificados de curta duração. Esse esquema será obrigatório no Android 13.0. Ele é conhecido como provisionamento remoto de chaves.
Os fabricantes de dispositivos deixarão de provisionar chaves privadas de atestado diretamente para os dispositivos na fábrica, o que elimina a sobrecarga de gerenciamento de chaves secretas na fábrica para fins de atestado.
O formato, os algoritmos e o comprimento da cadeia de certificados de um atestado, descritos mais adiante, passarão por mudanças. Se uma parte confiável tiver configurado o código de validação de certificados com correspondência muito rígida à estrutura da cadeia de certificados legada, esse código precisará ser atualizado.
Os dois fatores principais que motivaram a mudança da forma como provisionamos certificados de atestado para os dispositivos são permitir a recuperação de dispositivos após um comprometimento e reforçar a cadeia de suprimentos de atestados. No atual esquema de atestado, se um modelo de dispositivo for comprometido de uma forma que afete o sinal de confiabilidade de um atestado ou se ocorrer o vazamento de uma chave por meio de qualquer mecanismo, a chave deverá ser revogada. Devido ao número cada vez maior de serviços que dependem do sinal de chave de atestado, isso pode ter um grande impacto sobre os consumidores cujos dispositivos forem afetados.
Essa mudança nos permite interromper o provisionamento para dispositivos com software comprovadamente comprometido e eliminar o potencial de vazamento não intencional de chaves. Isso ajudará a reduzir muito a possibilidade de interrupção de serviços para os usuários.
Cada dispositivo gera um par de chaves estáticas exclusivas, e a parte pública desse par de chaves é extraída pelo OEM na fábrica. Em seguida, é feito o upload dessas chaves públicas para os servidores do Google, onde elas servem como base de confiança para o provisionamento posterior. A chave privada nunca deixa o ambiente seguro na qual é gerada.
Quando um novo dispositivo é conectado pela primeira vez à Internet, ele gera uma solicitação de assinatura de certificado para as chaves geradas por ele, assinando-a com a chave privada correspondente à chave pública coletada na fábrica. Os servidores de back-end verificam a autenticidade da solicitação e assinam as chaves públicas, retornando as cadeias de certificados. O armazenamento de chaves, então, armazena essas cadeias de certificados, atribuindo-as aos apps sempre que um atestado é solicitado.
Esse fluxo ocorre regularmente com a expiração dos certificados ou a exaustão do suprimento de chaves atual. O esquema preserva a privacidade, porque cada aplicativo recebe uma chave de atestado diferente, e as próprias chaves passam periodicamente por um rodízio. Além disso, os servidores de back-end do Google são segmentados de tal forma que o servidor que verifica a chave pública do dispositivo não vê as chaves de atestado anexadas. Isso significa que não é possível para o Google correlacionar as chaves de atestado com o dispositivo em particular que as solicitou.
Os usuários finais não notarão nenhuma mudança. Os desenvolvedores que usam atestados deverão ficar atentos às seguintes mudanças:
Postado pela equipe do Android
O Twitter, uma das plataformas de mídia social mais utilizadas do mundo, está sempre em busca de formas de conectar melhor os usuários. Ao mesmo tempo, a fim de criar novos recursos com eficiência e ainda manter os existentes, os desenvolvedores precisam de uma infraestrutura de suporte. A equipe de engenharia do Twitter escolheu o Jetpack Compose para iniciar uma reformulação muito necessária da base da IU do app. Com o Compose, os desenvolvedores podem facilmente localizar e usar as APIs certas, estilizar e modularizar componentes e criar mais com menos código.
Algumas equipes, como as de IU de cliente Android, aquisição de clientes, Twitter Blue e comunidades, reformularam seus processos de desenvolvimento, gerando grande agitação entre os engenheiros do Twitter. "Várias equipes do Twitter adotaram o Compose em seus fluxos de trabalho diários", disse Sneha Patil, engenheira de software sênior e líder técnica da equipe de comunidades do Twitter para Android. Ao eliminar o trabalho de criação e configuração de temas e atributos personalizados, o Compose tornou a escrita de funções e a implementação de requisitos de design muito mais rápida e simples do que com Views. O Jetpack Compose permitiu que essas equipes trabalhassem com mais rapidez e eficiência, assegurassem a capacidade de reutilização do código e integrassem novos engenheiros com facilidade.
A criação de conteúdo dinâmico é mais direta com o Compose. A equipe do Twitter usou a função que pode ser composta LazyColumn para criar a IU sem a necessidade de um Adapter ou ViewHolder, simplificando o processo de escrita de um código que dá vida, facilmente, a layouts, temas e estilos. Com menos linhas a serem escritas, as equipes de desenvolvimento do Twitter reduziram o código boilerplate, tiveram menos bugs durante o desenvolvimento e os lançamentos, ativaram os testes experimentais da IU e aceleraram o processo de testes. Essas melhorias elevaram a produtividade para que os desenvolvedores pudessem passar mais tempo criando aquilo que torna o Twitter único.
Eles também usaram o Compose para criar componentes sem estado que podem ser reutilizados em todo o app. A flexibilidade do Compose facilitou e agilizou o atendimento de requisitos de design, tornando a configuração de temas e estilos mais simples para os engenheiros novos e também para os mais experientes.
Com as melhorias observadas, eles decidiram criar um recurso totalmente novo usando o Compose. Eles criaram o recurso Comunidades, o espaço dedicado do Twitter no qual os usuários podem interagir em discussões sobre assuntos que são importantes para eles. Isso foi feito usando o Compose, do início ao fim. Em comparação com a experiência anterior das equipes com o uso de Views para outros recursos, a criação com o Compose foi muito mais rápida e com menos bugs. "Foi mágico", disse Sneha. "Isso muda tudo na forma como podemos desenvolver em Android usando o Compose.."
O Compose amplificou a velocidade e a eficiência do desenvolvimento de IUs pelos engenheiros do Twitter. Os desenvolvedores incorporaram e criaram com facilidade usando o Compose, o que facilitou a modularização do código, a reutilização de componentes e o detalhamento de dependências. A equipe utiliza regularmente os testes experimentais de IU, e o Compose ajudou a aumentar a confiança quanto ao comportamento em produção dos componentes que reagem as interações de usuários, atualizações de dados e diferentes tamanhos de tela.
O sucesso inicial dessas equipes com o Compose inspirou outras equipes de desenvolvimento do Twitter a seguir o exemplo. Agora, até mesmo os engenheiros que trabalham em componentes legados complexos estão pensando em adotá-lo.
Em geral, o Compose não só removeu muitos dos obstáculos que a equipe experimentava com Views, como também tornou o fluxo de trabalho agradável, e alguns desenvolvedores estão prontos para abandonar de vez os métodos antigos. "Estou louca para escrever mais em Compose e nunca mais ter que tocar em um layout XML novamente", disse Yoali Sotomayor Baqueiro, engenheira de software de IU de cliente Android do Twitter. "Ele torna o desenvolvimento de IUs não só mais simples, mas também muito mais divertido e intuitivo.."
Otimize o desenvolvimento de IUs com o Compose.