Visão geral do Play Feature Delivery

O modelo de exibição de apps do Google Play usa Android App Bundles para gerar e disponibilizar APKs otimizados para a configuração do dispositivo de cada usuário. Assim, os usuários fazem o download apenas do código e dos recursos necessários para executar o app.

O Play Feature Delivery usa recursos avançados de pacotes de apps, permitindo que determinados recursos sejam enviados condicionalmente ou transferidos por download sob demanda. Para fazer isso, é necessário primeiro separar esses recursos do app base em módulos de recursos.

Configuração do build do módulo de recurso

Quando você cria um novo módulo de recurso usando o Android Studio, o ambiente de desenvolvimento integrado aplica o seguinte plug-in do Gradle ao arquivo build.gradle do módulo.

// The following applies the dynamic-feature plugin to your feature module.
// The plugin includes the Gradle tasks and properties required to configure and build
// an app bundle that includes your feature module.

plugins {
  id 'com.android.dynamic-feature'
}

Muitas das propriedades disponíveis para o plug-in de aplicativo padrão também estão disponíveis para seu módulo de recurso. As seções a seguir descrevem as propriedades que você precisa ou não incluir na configuração da compilação do módulo de recurso.

O que não incluir na configuração da compilação do módulo de recurso

Como cada módulo de recurso depende do módulo base, ele também herda certas configurações. Portanto, você precisa omitir o seguinte no arquivo build.gradle do módulo de recurso:

  • Configurações de assinatura: os pacotes de apps são assinados usando configurações de assinatura que você especifica no módulo base.
  • A propriedade minifyEnabled: você pode ativar a redução de código para todo o projeto do app apenas na configuração da compilação do módulo base. Portanto, você precisa omitir essa propriedade dos módulos de recursos. No entanto, você pode especificar outras regras do ProGuard para cada módulo de recurso.
  • versionCode e versionName: ao criar seu pacote de apps, o Gradle usa as informações da versão do app fornecidas pelo módulo base. Você precisa omitir essas propriedades do arquivo build.gradle do módulo de recurso.

Estabelecer uma relação com o módulo base

Quando o Android Studio cria seu módulo de recurso, ele fica visível para o módulo base adicionando a propriedade android.dynamicFeatures ao arquivo build.gradle do módulo base, como mostrado abaixo:

// In the base module’s build.gradle file.
android {
    ...
    // Specifies feature modules that have a dependency on
    // this base module.
    dynamicFeatures = [":dynamic_feature", ":dynamic_feature2"]
}

Além disso, o Android Studio inclui o módulo base como uma dependência do módulo de recurso, conforme mostrado abaixo:

// In the feature module’s build.gradle file:
...
dependencies {
    ...
    // Declares a dependency on the base module, ':app'.
    implementation project(':app')
}

Especificar outras regras do ProGuard

Embora somente a configuração do build do módulo base possa ativar a redução de código no projeto do app, você pode fornecer regras personalizadas do ProGuard com cada módulo de recurso usando a propriedade proguardFiles, como mostrado abaixo.

android.buildTypes {
     release {
         // You must use the following property to specify additional ProGuard
         // rules for feature modules.
         proguardFiles 'proguard-rules-dynamic-features.pro'
     }
}

Essas regras do ProGuard são mescladas com as regras de outros módulos (incluindo o módulo base) no momento da compilação. Assim, embora cada módulo de recurso possa especificar um novo conjunto de regras, essas regras se aplicam a todos os módulos no projeto do app.

Implantar o app

Durante o desenvolvimento do app com compatibilidade com módulos de recursos, você pode implantar o app em um dispositivo conectado, como faria normalmente, selecionando Run > Run na barra de menus ou clicando em Run na barra de ferramentas.

Se o projeto do app incluir um ou mais módulos de recursos, você poderá escolher quais recursos incluir ao implantar o app modificando a configuração de execução/depuração existente da seguinte maneira:

  1. Selecione Run > Edit Configurations na barra de menus.
  2. No painel à esquerda da caixa de diálogo Run/Debug Configurations, selecione a configuração de Android App que você quer usar.
  3. Em Dynamic features to deploy, na guia General, marque a caixa ao lado de cada módulo de recursos que você quer incluir durante a implantação do app.
  4. Clique em OK.

Por padrão, o Android Studio não implementa seu app usando pacotes de apps. Em vez disso, o ambiente de desenvolvimento integrado cria e instala no dispositivo APKs que são otimizados para a velocidade de implantação, não para o tamanho do APK. Para configurar o Android Studio para criar e implantar APKs e experiências instantâneas a partir de um pacote de apps, modifique sua configuração de execução/depuração.

Usar módulos de recursos para entrega personalizada

Um benefício exclusivo dos módulos de recursos é a capacidade de personalizar como e quando diferentes recursos do app são transferidos por download para dispositivos com o Android 5.0 (nível 21 da API) ou mais recente. Por exemplo, para reduzir o tamanho inicial do download do app, configure determinados recursos para serem transferidos conforme necessário sob demanda ou apenas por dispositivos compatíveis com determinadas capacidades, como a de tirar fotos ou com funcionalidades de realidade aumentada.

Embora você receba downloads altamente otimizados por padrão quando faz upload do app como um pacote de apps, as opções de entrega de recursos mais avançadas e personalizáveis exigem outras configurações e a modularização dos recursos do app com módulos de recursos. Ou seja, os módulos de recursos oferecem os elementos básicos para a criação de recursos modulares que você pode configurar para cada download, conforme necessário.

Imagine um app que permite ao usuário comprar e vender mercadorias em um mercado on-line. Você pode modularizar cada uma das seguintes funcionalidades do app em módulos de recursos separados:

  • Login e criação da conta
  • Navegação no mercado
  • Disponibilização de itens para venda
  • Processamento de pagamentos

A tabela abaixo descreve as diferentes opções de entrega compatíveis com módulos de recursos e como elas podem ser usadas para otimizar o tamanho inicial do download do app de mercado de exemplo.

Opção de entrega Comportamento Exemplo de caso de uso Primeiros passos
Entrega na instalação Por padrão, os módulos de recursos que não configuram nenhuma das opções de entrega descritas acima são transferidos por download na instalação do app. Esse é um comportamento importante, porque significa que você pode adotar opções de entrega avançadas gradativamente. Por exemplo, você só pode usufruir da modularização dos recursos do seu app e ativar a entrega sob demanda depois de ter implementado totalmente os downloads sob demanda usando a biblioteca Play Core.

Além disso, o app pode solicitar a desinstalação de recursos posteriormente. Portanto, se você precisar de determinados recursos na instalação do app, mas não depois disso, poderá reduzir o tamanho da instalação, solicitando que o recurso seja removido do dispositivo.

Se o app tiver determinadas atividades de treinamento, como um guia interativo sobre como comprar e vender itens no mercado, você poderá incluir esse recurso na instalação do app, por padrão.

No entanto, para reduzir o tamanho de instalação, o app poderá solicitar a exclusão do recurso depois que o usuário concluir o treinamento.

Modularize seu app usando módulos de recursos que não configuram opções avançadas de entrega.

Para saber como reduzir o tamanho de instalação do app removendo determinados módulos de recursos que o usuário não precisa mais, consulte Gerenciar módulos instalados.

Entrega sob demanda Permite que o app solicite módulos de recursos e faça o download deles, conforme necessário. Se apenas 20% das pessoas que usam o app do mercado publicarem itens para venda, uma boa estratégia para reduzir o tamanho inicial do download para a maioria dos usuários é usar a funcionalidade para tirar fotos, incluir a descrição de um item e disponibilizar itens para venda na forma de um download sob demanda. Ou seja, você pode configurar o módulo de recurso para que a funcionalidade de venda do app seja transferida por download somente quando o usuário mostrar interesse em colocar itens à venda no mercado.

Além disso, se o usuário deixar de realizar vendas depois de um determinado período, o app poderá reduzir o tamanho da instalação solicitando a desinstalação do recurso.

Crie um módulo de recurso e configure a entrega sob demanda. Assim, o app poderá usar a biblioteca Play Core para solicitar o download do módulo sob demanda.
Entrega condicional Permite que você especifique determinados requisitos de dispositivos do usuário, como recursos de hardware, localidade e nível mínimo da API, para determinar se um recurso modularizado é transferido por download na instalação do app. Se o app do mercado tem alcance global, talvez seja necessário oferecer compatibilidade com formas de pagamento conhecidas apenas em regiões ou locais específicos. Para reduzir o tamanho inicial do download do app, você pode criar módulos de recursos separados para processar determinados tipos de forma de pagamento e instalá-los condicionalmente no dispositivo do usuário com base na localidade registrada dele. Crie um módulo de recurso e configure a entrega condicional.
Entrega instantânea O Google Play Instant permite que os usuários interajam com seu app sem instalá-lo no dispositivo. Eles podem conhecer seu app usando o botão "Testar agora" da Google Play Store ou um URL criado por você. Essa forma de entregar conteúdo facilita o aumento do engajamento com seu app.

Com a entrega instantânea, você pode usar o Google Play Instant para permitir que o usuário acesse determinados recursos do app instantaneamente, sem fazer a instalação.

Imagine um jogo que inclua as primeiras fases em um módulo leve de recurso. Ative esse módulo instantaneamente para que o usuário possa conhecer o jogo de imediato por um link de URL ou do botão "Testar agora", sem instalar o app. Crie um módulo de recurso e configure a entrega instantânea. Assim, o app poderá usar a biblioteca Play Core para solicitar o download do módulo sob demanda.

A modularização dos recursos do app por módulos de recursos é apenas o primeiro passo. Para oferecer compatibilidade com o Google Play Instant, o tamanho de download do módulo base do app e de um determinado recurso instantâneo precisa atender a restrições rígidas de tamanho. Para saber mais, leia Ativar experiências instantâneas reduzindo o tamanho do app ou jogo.

Criar um URI para um recurso

Se você quiser acessar um recurso armazenado em um módulo usando um URI, veja como gerar um URI de módulo de recurso usando Uri.Builder():

Kotlin

val uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build()

Java

String uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build().toString();

Cada parte do caminho para o recurso é construída no momento da execução, garantindo que o namespace correto seja gerado após o carregamento dos APKs divididos.

Como exemplo de como o URI é gerado, suponha que você tenha um app e módulos de recursos com esses nomes:

  • Nome do pacote do app: com.example.my_app_package
  • Nome do pacote de recursos do elemento: com.example.my_app_package.my_dynamic_feature

Se o resId no snippet de código acima se referir a um recurso de arquivo bruto com o nome "my_video" no módulo de recurso, o código Uri.Builder() acima produzirá o seguinte:

android.resource://com.example.my_app_package/raw/com.example.my_app_package.my_dynamic_feature:my_video

Esse URI pode ser usado pelo seu app para acessar o recurso deste módulo.

Para validar os caminhos no URI, use o APK Analyzer para inspecionar o APK do módulo de recurso e determinar o nome do pacote:

Uma captura de tela do APK Analyzer inspecionando o conteúdo de um arquivo de recurso compilado.

Figura 2. Use o APK Analyzer para inspecionar o nome do pacote em um arquivo de recurso compilado.

Considerações sobre módulos de recursos

Com os módulos de recursos, você pode aumentar a velocidade de compilação e de engenharia e personalizar amplamente a entrega dos recursos do app, reduzindo o tamanho dele. No entanto, há algumas restrições e casos extremos que devem ser considerados ao usar os módulos de recursos:

  • A instalação de 50 ou mais módulos de recursos em um único dispositivo, por entrega condicional ou sob demanda, pode causar problemas de desempenho. Os módulos de tempo de instalação, que não são configurados como removíveis, são incluídos automaticamente no módulo base e contam apenas como um módulo de recurso em cada dispositivo.
  • Limite o número de módulos configurados como removíveis para entrega na instalação a 10 ou menos. Caso contrário, o tempo de download e instalação do app poderá aumentar.
  • Apenas dispositivos com o Android 5.0 (nível 21 da API) e versões mais recentes são compatíveis com download e instalação de recursos sob demanda. Para disponibilizar o recurso para versões anteriores do Android, ative a opção Fusing ao criar um módulo de recurso.
  • Para que o app tenha acesso aos módulos de recursos transferidos por download que são enviados sob demanda, ative a SplitCompat.
  • Os módulos de recursos não podem especificar as atividades no manifesto com android:exported definido como true. Isso porque não há garantia de que o dispositivo tenha feito o download do módulo de recurso quando outro app tentar iniciar a atividade. Além disso, seu app precisa confirmar se um recurso foi transferido por download antes de tentar acessar o código e os recursos relacionados. Para saber mais, leia Gerenciar módulos instalados.
  • Como o Play Feature Delivery requer que você publique seu aplicativo usando um pacote de apps, verifique se há problemas conhecidos com o pacote de apps.

Referência ao manifesto do módulo de recurso

Durante a criação de um novo módulo de recurso usando o Android Studio, o ambiente de desenvolvimento integrado inclui a maioria dos atributos de manifesto que o módulo precisa para se comportar como um módulo de recurso. Além disso, alguns atributos são injetados pelo sistema no momento da compilação. Assim, você não precisa especificá-los nem modificá-los. A tabela a seguir descreve os atributos do manifesto que são importantes para os módulos de recursos.

Atributo Descrição
<manifest
...
Este é seu bloco <manifest> típico.
xmlns:dist="http://schemas.android.com/apk/distribution" Especifica um novo namespace XML dist:, que é descrito abaixo.
split="split_name" Quando o Android Studio cria seu pacote de apps, ele inclui esse atributo para você. Portanto, não inclua nem modifique esse atributo por conta própria.

Define o nome do módulo, que seu app especifica ao solicitar um módulo sob demanda usando a biblioteca Play Core.

Como o Gradle determina o valor deste atributo:

Por padrão, quando você cria um módulo de recurso usando o Android Studio, o ambiente de desenvolvimento integrado usa o que você especificou como o Nome do módulo para identificar o módulo como um subprojeto do Gradle no arquivo de configurações do Gradle.

Quando você cria seu pacote de aplicativos, o Gradle usa o último elemento do caminho do subprojeto para inserir esse atributo de manifesto no manifesto do módulo. Por exemplo, se você criar um novo módulo de recurso no diretório MyAppProject/features/ e especificar "dynamic_feature1" como o nome do módulo, o ambiente de desenvolvimento integrado adicionará ':features:dynamic_feature1' como um subprojeto no arquivo settings.gradle. Quando você cria seu pacote de apps, o Gradle injeta <manifest split="dynamic_feature1"> no manifesto do módulo.

android:isFeatureSplit="true | false"> Quando o Android Studio cria seu pacote de apps, ele inclui esse atributo para você. Portanto, não inclua nem modifique esse atributo manualmente.

Especifica que este é um módulo de recurso. Os manifestos no módulo base e nos APKs de configuração omitem esse atributo ou o definem como false.

<dist:module Esse novo elemento XML define os atributos que determinam como o módulo é empacotado e distribuído como APKs.
dist:instant="true | false" Especifica se o módulo deve estar disponível pelo Google Play Instant como uma experiência instantânea.

Se o app incluir um ou mais módulos de recursos instantâneos, você também precisará ativar o módulo base como um módulo instantâneo. Com o Android Studio 3.5 ou mais recente, o ambiente de desenvolvimento integrado faz isso quando você cria um módulo de recursos instantâneos.

Não é possível definir esse elemento XML como true ao mesmo tempo em que define <dist:on-demand/>. No entanto, ainda é possível solicitar downloads sob demanda dos seus módulos de recursos instantâneos como experiências instantâneas usando a biblioteca Play Core. Por padrão, quando o usuário faz o download do seu app e o instala, o dispositivo faz o download dos módulos de recursos instantâneos do app e os instala junto do APK básico, por padrão.

dist:title="@string/feature_name" Especifica um título direcionado ao usuário para o módulo. Por exemplo, o dispositivo pode exibir esse título quando solicita uma confirmação de download.

Você precisa incluir o recurso de string para esse título no arquivo module_root/src/source_set/res/values/strings.xml do módulo base.

<dist:fusing dist:include="true | false" />
</dist:module>
Especifica se o módulo deve ser incluído em multi-APKs destinados a dispositivos com o Android 4.4 (API nível 20) ou anterior.

Além disso, quando você usa bundletool para gerar APKs de um pacote de apps, somente os módulos de recursos que definem essa propriedade como true são incluídos na versão universal do APK, que é um APK monolítico que inclui código e recursos para todas as configurações de dispositivo compatíveis com o app.

<dist:delivery> Encapsula opções que personalizam a entrega do módulo, conforme mostrado abaixo. Lembre-se de que cada módulo de recurso precisa configurar apenas um tipo dessas opções de entrega personalizada.
<dist:install-time> Especifica que o módulo precisa estar disponível no momento da instalação. Esse é o comportamento padrão para módulos de recursos que não especificam outro tipo de opção de entrega personalizada.

Para saber mais sobre downloads na instalação, leia Configurar entrega na instalação.

Esse nó também pode especificar condições que limitam o módulo a dispositivos que atendem a determinados requisitos, como recursos do dispositivo, país do usuário ou nível mínimo da API. Para saber mais, leia Configurar entrega condicional.

<dist:removable dist:value="true | false" />

Quando não definido ou definido como false, o bundletool combina os módulos de tempo de instalação no módulo base ao gerar APKs divididos do pacote. Como haverá menos APKs divididos por causa da combinação, essa configuração pode melhorar o desempenho do seu app.

Quando removable é definido como true: os módulos de tempo de instalação não são combinados no módulo base. Defina como true caso queira desinstalar módulos no futuro. No entanto, configurar muitos módulos para serem removíveis pode aumentar o tempo de instalação do aplicativo.

O valor padrão é false. Só é necessário definir esse valor no manifesto se você quiser desativar a fusão de um módulo de recurso.

Observação: esse recurso só está disponível ao usar o Plug-in do Android para Gradle 4.2 ou ao usar o bundletool v1.0 na linha de comando.

</dist:install-time>  
<dist:on-demand/> Especifica que o módulo deve estar disponível como um download sob demanda. Ou seja, o módulo não está disponível no momento da instalação, mas seu app pode solicitar o download mais tarde.

Para saber mais sobre downloads sob demanda, leia Configurar entrega sob demanda.

</dist:delivery>
<application
android:hasCode="true | false">
...
</application>
Se o módulo de recurso não gera arquivos DEX, ou seja, não contém nenhum código que seja compilado posteriormente no formato de arquivo DEX, você precisa fazer o seguinte (caso contrário, poderá receber erros de tempo de execução):
  1. Defina android:hasCode como "false" no manifesto do módulo de recurso.
  2. Adicione o seguinte ao manifesto do seu módulo base:
    
    <application
      android:hasCode="true"
      tools:replace="android:hasCode">
      ...
    </application>
    

Outros recursos

Para saber mais sobre o uso de módulos de recursos, experimente os recursos a seguir.

Postagens do blog (em inglês)

Vídeos (em inglês)