Utilizando Módulos Dinâmicos no seu app Android

Angélica Oliveira
Android Dev BR
Published in
7 min readApr 1, 2020

--

Melhorando a arquitetura do seu aplicativo e a vida de seus usuários

Photo by chuttersnap on Unsplash

Com o passar do tempo é natural que os aplicativos cresçam, uma feature após a outra, até chegarmos ao ponto de termos um código fonte muito grande, gerando um aplicativo enorme, que na maioria das vezes é subutilizado pelos usuários.

Vou explicar nesse artigo, como podemos liberar features dinâmicas em um aplicativo Android, essas features não são entregues com o app original, apenas quando o usuário tem a necessidade de utilizar a funcionalidade.

Regra do 80/20

A regra do 80/20, diz que 80% dos seus usuários usam apenas 20% do seu aplicativo.

Aí fica a pergunta…

O que podemos/devemos fazer então com os 80% restante das features que ainda temos em nossos singelos aplicativos?

imagem de um cachorrinho com cara de dúvida

Vamos descobrir em breve…

Imaginando um caso real

Vamos supor um aplicativo de visualização de GIFs:

Imagem com exemplo de layout de aplicativo de visualização e compartilhamento de GIFs

Vamos supor que entre as features deste aplicativo, além de ver os GIFs mais populares, poderia ser possível favoritar as imagens que mais gostarmos para uma consulta posterior.

Esta feature não seria a principal do aplicativo (lembrem-se, é uma aplicativo para consulta de GIFs). Logo, poderíamos deixar esta feature dinâmica, sendo baixada e instalada apenas pelos usuários que a utilizem! 😻(gatinho com olhos de coração)

Mas qual seria o benefício real?

Todos os usuários baixariam somente o aplicativo com o código referente a feature de consulta de GIFs, que é um aplicativo menor em tamanho do que o conjunto da consulta de GIFs + lista de favoritos. Apenas os usuários que desejem utilizar a funcionalidade de favoritar a baixariam. Com isso, iríamos poupar:

  • Tempo de download do app.
  • Internet dos usuários para download do aplicativo.
  • Espaço de armazenamento do device dos usuários.

No mínimo interessante não é mesmo?

Gif de uma pessoa fazendo sinal afirmativo

Lembrando apenas que este é um caso hipotético, apenas como exemplo, pois certamente a economia de apenas uma Activity como feature dinâmica não justifica o trabalho de refatorar um aplicativo para tal fim. O ideal segundo a documentação oficial do Google é que funcionalidades que não são parte do core do app possam ser transformadas em features dinâmicas.

Agora vamos ao que interessa: Show me the code!

Para começar, crie um projeto novo no Android Studio, ou no projeto que você já tenha aberto e deseja implementar dynamic features, abra o arquivo build.gradle do seu módulo app e adicione a dependência da biblioteca Play Core:

Depois, no arquivo AndroidManifest.xml do módulo app, você deve adicionar a SplitCompatApplication como application de seu aplicativo:

Caso você já possua uma classe Application customizada, apenas faça a mesma herdar de SplitCompatApplication:

Agora, no módulo que você deseja deixar como dinâmico (instalado quando o usuário acessar a feature), adicione as seguintes linhas ao arquivo AndroidManifest.xml (no caso do exemplo, estou colocando o módulo favorite, responsável pela feature de visualizar as imagens favoritas do usuário como funcionalidade dinâmica):

Nesse trecho de código, podemos ver a utilização da string module_favorite, esta string, idealmente deve estar localizada no módulo app, devido a uma alteração estrutural que veremos logo a seguir. 👇(emoji com dedo apontando para baixo).

Então, neste momento não se preocupe com a criação da string, mas caso queira olhar uma opção de como criar, só olhar no código utilizado como exemplo para este artigo, no Github.

Agora vamos alterar a estrutura do aplicativo como um todo, pois vamos adicionar o módulo app, como dependência do módulo de feature favorite. 🤔(carinha pensando)

Muita calma, sei que isso parece ser confuso, mas vou tentar explicar aqui com um desenho bem simples, como era e como ficou a estrutura do aplicativo:

Imagem da alteração necessária na arquitetura do aplicativo, onde o módulo dinâmico deve depender do módulo app

Resumindo, nos aplicativos modularizados, com a arquitetura comumente utilizada o módulo app é o principal do aplicativo, e ele depende dos outros módulos, de features, ferramentas etc. Mas, quando a arquitetura é modificada para conter um módulo dinâmico, este módulo deve depender do módulo app, como podemos ver na documentação.

Para realizar esta alteração, precisamos fazer algumas modificações nos arquivos gradle do projeto, e outras nas classes de acesso à funcionalidade dinâmica, vou colocar tudo passo-a-passo por aqui.

Alterações nos arquivos gradle

Primeiro adicione o módulo app como dependência do módulo de feature, adicionando a linha no conjunto dependencies, do arquivo build.gradle do módulo de feature. Também neste arquivo, devemos sinalizar que esta feature é dinâmica, removendo o plugin de biblioteca aplicado que era com.android.library, e adicionando o plugin de feature dinâmica com.android.dynamic-feature.
Recapitulando, as alterações do arquivo build.gradle do módulo de feature dinâmica, são as seguintes:

Agora, devemos alterar o arquivo build.gradle do módulo app, neste arquivo devemos remover a dependência do módulo de feature e adicionar a dependência novamente, mas agora como uma dependência dinâmica, utilizando o comando dynamicFeatures.
Assim, as alterações do arquivo build.gradle do módulo app, ficam desta forma:

Neste momento já conseguimos realizar o build do nosso projeto com feature dinâmica com sucesso! 🙌 (emoji de mãos para cima, em comemoração)

Mas, ainda precisamos realizar algumas alterações para de fato concluir a implementação.

Inicialização do SplitInstallManager

Para utilizar alguns métodos de controle da instalação dos módulos dinâmicos, precisamos de uma propriedade do tipo SplitInstallManager, sua inicialização se dá através do método SplitInstallManagerFactory.create(this), e no exemplo, a inicialização se encontra no método onCreate da Activity:

O SplitInstallManager controla quando o listener (SplitInstallStateUpdatedListener), responsável por tratar os diferentes estados de download e instalação do módulo dinâmico, deve registrar os eventos deste módulo.

Para tanto, é necessário colocar duas chamadas na Activity do módulo app, uma no método onResume e outra no onPause. Assegurando que os eventos de download não serão disparados enquanto a aplicação está em background:

Implementação da SplitInstallStateUpdatedListener

Para obter o status do download dos módulos dinâmicos, é possível implementar a interface SplitInstallStateUpdatedListener.

Em sua implementação o atual estado de download do módulo pode ser verificado e, a partir do estado, realizar alguma ação. Como por exemplo, exibir uma mensagem de loading, de erro ou executar a funcionalidade requerida.

No exemplo, o listener está sendo implementado na Activity e apenas alguns estados sendo tratados:

  • DOWNLOADING -> chamado quando o módulo está sendo baixado, neste estado é possível exibir o progresso do download.
  • INSTALLED -> neste estado o módulo dinâmico já está instalado, então podemos iniciar a exibição da feature requerida para instalação, caso seja necessário.
  • INSTALLING -> estado para o momento de instalação do módulo.
  • FAILED -> chamado quando houve falha na instalação ou download de um módulo dinâmico.

Existem outros estados que podem ser tratados no listener conforme a documentação, a implementação do tratamento dos estados feita no aplicativo de exemplo ficou da seguinte forma:

Iniciando a Feature Dinâmica

Quando o usuário desejar acessar a funcionalidade dinâmica é necessário seguir alguns passos:

  1. Checar se o módulo está instalado
  2. Mostrar ao usuário a mensagem de carregamento e instalação do módulo
  3. Construir o SplitInstallRequest caso o módulo não esteja instalado
  4. Instalar o módulo

Ufa! 😰 (emoji suando frio) Então, vamos lá:

Para checar se a funcionalidade está instalada no aplicativo, devemos utilizar a seguinte chamada:

manager.installedModules.contains(name)

Onde name é a string mencionada no arquivo AndroidManifest do módulo dinâmico como título da funcionalidade, no caso do exemplo a string module_favorite foi utilizada.

Caso a funcionalidade já esteja instalada o usuário pode ser notificado e SUCESSO!! 💃 (emoji de uma mulher dançando) O usuário já pode utilizar a feature!

Caso contrário, é necessário iniciar a instalação através, primeiramente da construção de um SplitInstallRequest, e depois a chamada para a instalação pela variável SplitInstallManager:

// Create request to install a feature module by name.        
val request = SplitInstallRequest.newBuilder()
.addModule(name)
.build()

// Load and install the requested feature module. manager.startInstall(request)

De forma resumida, a função responsável por carregar e iniciar a funcionalidade dinâmica ficaria da seguinte forma:

Neste momento terminamos as modificações na classe responsável por chamar a funcionalidade dinâmica! 👏 (emoji batendo palmas)

Agora falta apenas uma pequena modificação na Activity da funcionalidade dinâmica…

Modificando Activity da Feature Dinâmica

Para poder acessar a funcionalidade dinâmica logo após a requisição de sua instalação, é imprescindível a utilização do método installActivity, dentro da Activity do módulo dinâmico. Esta chamada faz a emulação da instalação, possibilitando o acesso imediato a feature.

No exemplo essa chamada foi colocada no método attachBaseContext da Activity da funcionalidade dinâmica.

Desta forma, é possível concluir as modificações necessárias para se ter uma funcionalidade dinâmica em um aplicativo.

Qualquer dúvida podem comentar aqui ou acessar o exemplo completo no Github.
Espero, ter contribuído de alguma forma para o conhecimento da comunidade em geral, e também para os usuários dessa nossa plataforma tão amada Android. 👋 (emoji de mão acenando)

Imagem com a frase That's all Folks!

Fontes

UX best practices for on demand delivery

Build a Modular Android App Architecture (Google I/O’19)

Android Developers Reference

About Dynamic Delivery

On Demand Modules Codelab

--

--

Angélica Oliveira
Android Dev BR

Android Engineer @Spotify | Google Developer Expert for Android. Learning and sharing knowledge.