Como criar vários APKs com diversas dimensões

Se você publicar seu aplicativo no Google Play, precisará criar e fazer upload de um Android App Bundle. Quando você fizer isso, o Google Play gerará e exibirá automaticamente APKs otimizados para a configuração do dispositivo de cada usuário, para que eles façam o download apenas do código e dos recursos necessários para executar o app. A publicação de vários APKs é útil se você não pretende publicar no Google Play, mas será preciso criar, assinar e gerenciar cada APK por conta própria.

Ao desenvolver seu aplicativo para Android para aproveitar vários APKs no Google Play, é importante seguir algumas recomendações desde o início e evitar dores de cabeça desnecessárias no processo de desenvolvimento. Esta lição mostra como criar vários APKs do seu app, cada um com uma classe diferente de tamanho de tela. Você também terá algumas ferramentas necessárias para simplificar o máximo possível a manutenção de um codebase de vários APKs.

Confirmar que você precisa de vários APKs

Ao tentar criar um aplicativo que funcione em uma ampla gama de dispositivos Android disponíveis, é natural que você queira que seu app tenha a melhor aparência em cada dispositivo. Você quer aproveitar o espaço de telas grandes, mas ainda trabalhar em telas pequenas, usar novos recursos da API do Android ou texturas visuais disponíveis em dispositivos modernos, mas sem esquecer dos mais antigos. No início, pode parecer que a compatibilidade com vários APKs é a melhor solução, mas esse geralmente não é o caso. A seção Como usar um único APK do guia de vários APKs traz algumas informações úteis sobre como fazer tudo isso com um único APK, incluindo o uso da nossa Biblioteca de Suporte (link em inglês) e links para recursos em todo o guia do desenvolvedor Android.

Se possível, a limitação do seu aplicativo a um único APK tem várias vantagens, incluindo o seguinte:

  • É mais fácil fazer publicações e testes.
  • Há apenas um codebase para manter.
  • Seu aplicativo pode se adaptar às mudanças de configuração do dispositivo.
  • A restauração de apps é funcional em vários dispositivos.
  • Você não precisa se preocupar com a preferência de mercado, o comportamento de "upgrades" de um APK para o próximo ou qual APK combina com cada classe de dispositivos.

O restante da lição considera que você já pesquisou o assunto, estudou o material nos recursos indicados e determinou que usar vários APKs é o caminho certo para seu aplicativo.

Organizar seus requisitos

Comece criando um gráfico simples para determinar rapidamente de quantos APKs você precisa e os tamanhos de tela que cada APK abrange. Felizmente, não é difícil mapear seus requisitos de maneira rápida, fácil e ter uma referência simples para uso posterior. Digamos que você queira dividir seus APKs em duas dimensões: API e tamanho da tela. Crie uma tabela com uma linha e uma coluna para cada par de valores possíveis e pinte alguns "blobs", sendo que cada cor representa um APK.

3 4 5 6 7 8 9 10 11 12 +
pequeno
normal
grande
extra grande

Acima, há um exemplo com quatro APKs. A cor azul corresponde a todos os dispositivos de tela pequena/normal, verde corresponde a dispositivos de tela grande e vermelho dispositivos de tela extra grande, todos com nível de API de 3 a 10. O roxo é um caso especial, já que corresponde a todos os tamanhos de tela, mas apenas para a API de nível 11 ou superior. Mais importante, basta olhar para esse gráfico e você saberá imediatamente qual APK abrange qualquer combinação de tamanho de tela/API. Além disso, você também tem codinomes elegantes para cada um, já que é muito mais fácil perguntar ao seu colega "Testamos o vermelho no…?" em vez de "Testamos o APK extra grande nível 3 a 10 com relação ao Xoom?". Imprima esse gráfico e dê uma cópia a todas as pessoas que trabalham no seu codebase. Isso facilitará muito sua vida.

Colocar todos os códigos e recursos comuns em um projeto de biblioteca

Independentemente de estar modificando um aplicativo para Android existente ou começando do zero, essa é a primeira coisa que você precisará fazer no codebase e, de longe, a mais importante. Tudo que entra no projeto da biblioteca só precisa ser atualizado uma única vez (strings localizadas por idioma, temas de cor, bugs corrigidos no código compartilhado), o que melhora o tempo de desenvolvimento e reduz a probabilidade de erros que poderiam ser facilmente evitados.

Observação: embora os detalhes de implementação de como criar e incluir projetos de biblioteca estejam fora do escopo desta lição, você pode se orientar lendo Criar uma biblioteca Android.

Se estiver convertendo um aplicativo existente para ter compatibilidade com vários APKs, vasculhe seu codebase para cada arquivo de string localizada, lista de valores, cores de tema, ícones de menu e layout que não serão modificados em APKs e coloque tudo no projeto da biblioteca. O código que não muda muito também precisa ser incluído no projeto da biblioteca. Você provavelmente acabará estendendo essas classes para adicionar um método ou dois de APK para APK.

Se, por outro lado, você estiver criando o aplicativo do zero, é importante tentar tanto quanto possível escrever o código no projeto da biblioteca primeiro e, em seguida, movê-lo apenas para um APK individual se necessário. Isso é muito mais fácil de gerenciar a longo prazo do que adicioná-lo a um, depois a outro, depois outro e meses depois tentar descobrir se esse blob pode ser movido para a seção da biblioteca sem estragar tudo.

Criar novos projetos de APK

Haverá um projeto Android diferente para cada APK que você gerará. Para facilitar a organização, coloque o projeto da biblioteca e todos os projetos de APK relacionados na mesma pasta mãe. Lembre-se também de que cada APK precisa ter o mesmo nome de pacote, embora não precise necessariamente ter o mesmo nome do pacote que a biblioteca. Se você tivesse três APKs seguindo o esquema descrito anteriormente, seu diretório raiz seria algo assim:

    alexlucas:~/code/multi-apks-root$ ls
    foo-blue
    foo-green
    foo-lib
    foo-purple
    foo-red
    

Depois que os projetos forem criados, adicione o projeto da biblioteca como referência para cada projeto de APK. Se possível, defina a atividade inicial no projeto da biblioteca e estenda essa atividade no projeto do APK. Ter uma atividade inicial definida no projeto da biblioteca permite que você coloque toda a inicialização do aplicativo em um só lugar. Assim, cada APK não precisará reimplementar tarefas "universais", como inicializar o Analytics, executar verificações de licenciamento e qualquer outro procedimento de inicialização que não mude muito de APK para APK.

Ajustar os manifestos

Quando um usuário faz o download de um aplicativo que usa vários APKs por meio do Google Play, o APK correto a ser usado é escolhido usando duas regras simples:

  • O manifesto precisa mostrar que determinado APK é qualificado.
  • Dos APKs qualificados, o número de versão mais alto ganha.

Por exemplo, vamos usar o conjunto de vários APKs descritos anteriormente e presumir que cada APK foi configurado para ser compatível com todos os tamanhos de tela maiores que o tamanho de tela "desejado". Vejamos o gráfico de amostra exibido anteriormente:

3 4 5 6 7 8 9 10 11 12 +
pequeno
normal
grande
extra grande

Como a cobertura pode ser sobreposta, podemos descrever a área coberta por cada APK desta forma:

  • Azul: abrange todas as telas, minSDK 3.
  • Verde: telas grandes e maiores, minSDK 3.
  • Vermelho: telas extra grandes (geralmente tablets), minSDK 9.
  • Roxo: abrange todas as telas, minSDK 11.

Observe que há muita sobreposição nessas regras. Por exemplo, um dispositivo extra grande com API de nível 11 pode executar qualquer um dos quatro APKs especificados. No entanto, ao usar a regra "o número de versão mais alto ganha", podemos definir uma ordem de preferência da seguinte maneira:

Roxo ≥ Vermelho ≥ Verde ≥ Azul

Por que permitir essa sobreposição? Vamos fazer de conta que o APK roxo tem alguns requisitos que os outros dois não têm. A página Filtros no Google Play do guia do desenvolvedor Android tem uma lista de possíveis culpados. Por exemplo, vamos supor que a cor roxa exija uma câmera frontal. Na verdade, o objetivo da cor roxa é usar entretenimento com a câmera frontal. Entretanto, nem todos os dispositivos com API de nível 11 ou superior têm câmeras frontais. Ah, não!

Felizmente, se um usuário estiver navegando no Google Play em um desses dispositivos, o Google Play analisará o manifesto, verá que o roxo lista a câmera frontal como requisito e o ignorará silenciosamente após determinar que o roxo e esse dispositivo não nasceram para ficar juntos. Então, ele verá que o vermelho não é apenas compatível com dispositivos extra grandes, mas também não se importa se há ou não uma câmera frontal. O usuário ainda poderá fazer o download do app no Google Play porque, apesar de todo o contratempo com a câmera frontal, havia um APK compatível com esse nível específico de API.

Para manter todos os seus APKs em "faixas" separadas, é importante ter um bom esquema de código de versão. O recomendado pode ser encontrado na área de Códigos de versão do nosso guia do desenvolvedor. Vale a pena ler a seção inteira, mas a ideia principal desse conjunto de APKs é usar dois dígitos para representar o minSDK, dois para representar o tamanho mínimo e máximo da tela e três para representar o número da versão. Dessa forma, quando o dispositivo for atualizado para uma nova versão do Android (por exemplo, da 10 para a 11), os APKs agora qualificados e preferidos em relação ao APK instalado serão considerados pelo dispositivo como um "upgrade". O esquema de número de versão, quando aplicado ao conjunto de exemplos de APKs, será algo assim:

Azul: 0304001, 0304002, 0304003…
Verde: 0334001, 0334002, 0334003
Vermelho: 0344001, 0344002, 0344003…
Roxo: 1104001, 1104002, 1104003…

Juntando tudo isso, os manifestos do Android provavelmente teriam esta aparência:

Azul:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        android:versionCode="0304001" android:versionName="1.0" package="com.example.foo">
        <uses-sdk android:minSdkVersion="3" />
        <supports-screens android:smallScreens="true"
            android:normalScreens="true"
            android:largeScreens="true"
            android:xlargeScreens="true" />
        ...
    

Verde:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        android:versionCode="0334001" android:versionName="1.0" package="com.example.foo">
        <uses-sdk android:minSdkVersion="3" />
        <supports-screens android:smallScreens="false"
            android:normalScreens="false"
            android:largeScreens="true"
            android:xlargeScreens="true" />
        ...
    

Vermelho:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        android:versionCode="0344001" android:versionName="1.0" package="com.example.foo">
        <uses-sdk android:minSdkVersion="3" />
        <supports-screens android:smallScreens="false"
            android:normalScreens="false"
            android:largeScreens="false"
            android:xlargeScreens="true" />
        ...
    

Roxo:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        android:versionCode="1104001" android:versionName="1.0" package="com.example.foo">
        <uses-sdk android:minSdkVersion="11" />
        <supports-screens android:smallScreens="true"
            android:normalScreens="true"
            android:largeScreens="true"
            android:xlargeScreens="true" />
        ...
    

Tecnicamente, vários APKs funcionarão com a tag "supports-screens" ou com a tag "compatible-screens". As supports-screens costumam ser as preferidas, e geralmente é uma péssima ideia usar as duas. Isso torna as coisas desnecessariamente complicadas e aumenta a possibilidade de erros. Observe também que, em vez de aproveitar os valores padrão (pequeno e normal são sempre verdadeiros por padrão), os manifestos definem explicitamente o valor para cada tamanho de tela. Isso pode evitar dores de cabeça: por exemplo, um manifesto com um SDK de destino < 9 terá o extra grande automaticamente definido como falso, porque esse tamanho ainda não existia. Por isso, seja explícito.

Analisar a lista de verificação de pré-lançamento

Antes de fazer upload para o Google Play, verifique os itens a seguir. Lembre-se de que esses itens são especificamente relevantes para vários APKs e não representam uma lista de verificação completa para todos os aplicativos enviados ao Google Play.

  • Todos os APKs precisam ter o mesmo nome de pacote.
  • Todos os APKs precisam ser assinados com o mesmo certificado.
  • Se houver sobreposição de APKs na versão da plataforma, o que tiver a minSdkVersion mais recente precisa ter um código de versão posterior.
  • No manifesto, defina como verdadeiro cada tamanho de tela que você quer que seja compatível com o APK. Defina como falso cada tamanho de tela que você queira evitar.
  • Verifique seus filtros de manifesto em busca de informações conflitantes. Um APK que só aceita o Android Cupcake em telas extra grandes, por exemplo, não será visto por ninguém.
  • Cada manifesto do APK precisa ser exclusivo em pelo menos um dos tipos de tela, textura OpenGL ou versão da plataforma compatível.
  • Tente testar cada APK em pelo menos um dispositivo. Fazendo isso, você terá um dos emuladores de dispositivos mais personalizáveis do mercado na sua máquina de desenvolvimento. O céu é o limite!

Também vale a pena inspecionar o APK compilado antes de enviar para o mercado para garantir que não haja surpresas que possam ocultar seu aplicativo no Google Play. É bem simples fazer isso usando a ferramenta "AAPT2". O AAPT (Android Asset Packaging Tool) é parte do processo de compilação para criar e empacotar seus apps para Android, além de ser uma ferramenta muito útil para inspecioná-los.

    >aapt dump badging
    package: name='com.example.hello' versionCode='1' versionName='1.0'
    sdkVersion:'11'
    uses-permission:'android.permission.SEND_SMS'
    application-label:'Hello'
    application-icon-120:'res/drawable-ldpi/icon.png'
    application-icon-160:'res/drawable-mdpi/icon.png'
    application-icon-240:'res/drawable-hdpi/icon.png'
    application: label='Hello' icon='res/drawable-mdpi/icon.png'
    launchable-activity: name='com.example.hello.HelloActivity'  label='Hello' icon=''
    uses-feature:'android.hardware.telephony'
    uses-feature:'android.hardware.touchscreen'
    main
    supports-screens: 'xlarge'
    supports-any-density: 'true'
    locales: '--_--'
    densities: '120' '160' '240'
    

Ao examinar a saída AAPT2, verifique se você não tem valores conflitantes para supports-screens e compatible-screens e se não tem valores "uses-feature" não intencionais que foram adicionados como resultado de permissões definidas no manifesto. No exemplo acima, o APK ficará invisível para a maioria ou até todos os dispositivos.

Por quê? Ao adicionar a permissão SEND_SMS necessária, o requisito de recurso de android.hardware.telephony é adicionado implicitamente. Como a maioria dos dispositivos extra grandes (se não todos) são tablets sem hardware de telefonia, o Google Play filtrará esse APK nesses casos até que apareçam novos dispositivos grandes o suficiente para informar um tamanho de tela extra grande e que tenham hardware de telefonia.

Felizmente, isso é facilmente corrigido adicionando o seguinte ao seu manifesto:

    <uses-feature android:name="android.hardware.telephony" android:required="false" />
    

O requisito android.hardware.touchscreen também é adicionado implicitamente. Se você quiser que seu APK esteja visível em TVs que não têm tela touchscreen, adicione o seguinte ao manifesto:

    <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
    

Depois de concluir a lista de verificação de pré-lançamento, faça upload dos seus APKs para o Google Play. Pode demorar um pouco para o aplicativo aparecer ao navegar pelo Google Play, mas, quando isso acontecer, faça uma última verificação. Faça o download do aplicativo em qualquer dispositivo de teste para verificar se os APKs estão segmentando os dispositivos pretendidos. Parabéns, você terminou!