Compilação de APKs específicos para ABI

Este documento discute como compilar um APK que será direcionado a uma única ABI usando o Xamarin.Android.

Visão geral

Em algumas situações, pode ser vantajoso para um aplicativo ter vários APKs – cada APK é assinado com o mesmo armazenamento de chaves e compartilha o mesmo nome de pacote, mas é compilado para uma configuração do Android ou dispositivo específico. Essa não é a abordagem recomendada, pois é muito mais simples ter um APK que pode dar suporte a vários dispositivos e configurações. Há algumas situações em que criar vários APKs pode ser útil, tais como:

  • Reduzir o tamanho do APK – o Google Play impõe um limite de tamanho de 100 MB para arquivos APK. A criação de APKs específicos de um dispositivo pode reduzir o tamanho do APK, pois você só precisa fornecer um subconjunto de ativos e recursos para o aplicativo.

  • Compatível com diferentes arquiteturas de CPU – Se o aplicativo tem bibliotecas compartilhadas para CPUs específicas, você pode distribuir apenas as bibliotecas compartilhadas para essa CPU.

Vários APKs podem complicar a distribuição – um problema que é abordado pelo Google Play. O Google Play garantirá que o APK correto seja entregue a um dispositivo com base no código da versão do aplicativo e outros metadados contidos em AndroidManifest.XML. Para obter detalhes específicos e restrições no modo como o Google Play é compatível com vários APKs para um aplicativo, consulte a Documentação do Google sobre o suporte a vários APKs.

Este guia abordará como criar o script o build de múltiplos APKs para um aplicativo Xamarin.Android, cada APK direcionado a um ABI específico. Ele aborda os seguintes tópicos:

  1. Criar um código de versão exclusivo para o APK.
  2. Criar uma versão temporária de AndroidManifest.XML, que será usada para este APK.
  3. Compile o aplicativo usando o AndroidManifest.XML da etapa anterior.
  4. Prepare o APK para lançamento, assinando-o e submetendo-o a zipalign.

No final deste guia há um passo a passo que demonstra como criar o script dessas etapas usando o Rake.

Criar um código de versão para o APK

O Google recomenda um algoritmo específico para o código de versão, que usa um código de versão de sete dígitos (consulte a seção Usando um esquema de código de versão no Documento de suporte a vários APKs). Expandindo esse esquema de código da versão de oito dígitos, será possível incluir, no código de versão, algumas informações de ABI que garantirão que o Google Play distribuirá o APK correto para um dispositivo. A lista a seguir explica este formato de código de versão de oito dígitos (indexado da esquerda para a direita):

  • Índice 0 (vermelho no diagrama abaixo) – Um inteiro para o ABI:

    • 1 – armeabi
    • 2 – armeabi-v7a
    • 6 – x86
  • Índice 1-2 (laranja no diagrama abaixo) – O nível mínimo de API suportado pelo aplicativo.

  • Índice 3-4 (azul no diagrama abaixo) – Os tamanhos de tela suportados:

    • 1 – pequeno
    • 2 – Normal
    • 3 – grande
    • 4 – xlarge
  • Índice 5-7 (verde no diagrama abaixo) – Um número exclusivo para o código da versão. Ele é definido pelo desenvolvedor. Ele deve aumentar a cada versão pública do aplicativo.

O diagrama a seguir ilustra a posição de cada código descrito na lista acima:

Diagram of eight-digit version code format, coded by color

O Google Play garantirá que o APK correto seja entregue ao dispositivo com base no versionCode e na configuração de APK. O APK com o código da versão mais alto será entregue ao dispositivo. Como um exemplo, um aplicativo pode ter três APKs com os seguintes códigos de versão:

  • 11413456 - O ABI é armeabi direcionado ao nível 14 da API, telas pequenas a grandes, com um número de versão de 456.
  • 21423456 - O ABI é armeabi-v7a alvo de API nível 14, telas grandes normais e com número de versão 456.
  • 61423456 - O ABI é x86 de API nível 14, tela grande normal e com número de versão 456.

Para continuar com este exemplo, imagine que foi corrigido um bug que era específico para armeabi-v7a. A versão do aplicativo aumenta para 457, e um novo APK é criado com o android:versionCode definido para 21423457. Os versionCodes para as versões armeabi e x86 permanecerão os mesmos.

Agora, imagine que a versão x86 recebe algumas atualizações ou correções de bug que se destinam a uma API mais recente (nível da API 19), tornando esta a versão 500 do aplicativo. O novo versionCode seria alterado para 61923500, enquanto o armeabi/armeabi-v7a permaneceriam inalterados. Nesse momento, os códigos de versão seriam:

  • 11413456 - O ABI é armeabi de API nível 14, telas pequenas a grandes, com nome de versão 456.
  • 21423457 - O ABI é armeabi-v7a o nível 14 da API, as telas grandes normais e com o nome da versão 457.
  • 61923500 - O ABI é x86 alvo de API nível 19, telas grandes normais e com nome de versão 500.

Manter esses códigos de versão manualmente pode ser um fardo significativo para o desenvolvedor. O processo de calcular o android:versionCode correto e posteriormente compilar os APKs deve ser automatizado. Um exemplo de como fazer isso será abordado no passo a passo no final deste documento.

Criar um AndroidManifest.XML temporário

Embora não seja estritamente necessário, criar um AndroidManifest.XML temporário para cada ABI pode ajudar a evitar problemas que possam surgir com vazamento de informações um APK ao outro. Por exemplo, é crucial que o atributo android:versionCode seja exclusivo para cada APK.

O modo como isso é feito depende do sistema de script envolvido, mas geralmente envolve fazer uma cópia do manifesto do Android usado durante o desenvolvimento, modificá-lo e, em seguida, usar esse manifesto modificado durante o processo de build.

Compilar o APK

Compilar o APK por ABI melhor é realizado usando xbuild ou msbuild, conforme mostrado na seguinte linha de comando de exemplo:

/Library/Frameworks/Mono.framework/Commands/xbuild /t:Package /p:AndroidSupportedAbis=<TARGET_ABI> /p:IntermediateOutputPath=obj.<TARGET_ABI>/ /p:AndroidManifest=<PATH_TO_ANDROIDMANIFEST.XML> /p:OutputPath=bin.<TARGET_ABI> /p:Configuration=Release <CSPROJ FILE>

A lista a seguir explica cada parâmetro de linha de comando:

  • /t:Package – Cria um APK Android que é assinado usando o keystore debug

  • /p:AndroidSupportedAbis=<TARGET_ABI> – Isso a ABI para atingir. Deve ser uma entre armeabi, armeabi-v7a ou x86

  • /p:IntermediateOutputPath=obj.<TARGET_ABI>/ – Este é o diretório que irá conter os arquivos intermediários que são criados como parte da compilação. Se necessário, o Xamarin.Android criará um diretório com o nome da ABI, tal como obj.armeabi-v7a. É recomendável usar uma pasta para cada ABI, pois isso impede problemas resultantes do "vazamento" de arquivos de um build para o outro. Observe que esse valor é encerrado com um separador de diretório (um / no caso de OS X).

  • /p:AndroidManifest – Esta propriedade especifica o caminho para o arquivo AndroidManifest.XML que será usado durante a compilação.

  • /p:OutputPath=bin.<TARGET_ABI> – Este é o diretório que abrigará o APK final. O Xamarin.Android criará um diretório com o nome da ABI, por exemplo, bin.armeabi-v7a.

  • /p:Configuration=Release – Execute uma compilação Release do APK. Os builds de depuração podem não ser carregados no Google Play.

  • <CS_PROJ FILE> – Este é o caminho para o .csproj arquivo para o projeto Xamarin.Android.

Assinar e efetuar o zipalign no APK

É necessário assinar o APK antes que ele possa ser distribuído por meio do Google Play. Isso pode ser feito usando o aplicativo jarsigner, que faz parte do Kit do Desenvolvedor Java. A linha de comando a seguir demonstra como usar jarsigner na linha de comando:

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore <PATH/TO/KEYSTORE> -storepass <PASSWORD> -signedjar <PATH/FOR/SIGNED_JAR> <PATH/FOR/JAR/TO/SIGN> <NAME_OF_KEY_IN_KEYSTORE>

O zipalign deve ser efetuado em todos os aplicativos Xamarin.Android antes que eles sejam executados em um dispositivo. Este é o formato da linha de comando a ser usada:

zipalign -f -v 4 <SIGNED_APK_TO_ZIPALIGN> <PATH/TO/ZIP_ALIGNED.APK>

Automatização da criação de APK com o Rake

O projeto de exemplo OneABIPerAPK é um projeto Android simples, que demonstra como calcular um número de versão específico de uma ABI e compilar três APKs separados para cada uma das seguintes ABIs:

  • armeabi
  • armeabi-v7a
  • x86

O rakefile no projeto de exemplo executa cada uma das etapas descritas nas seções anteriores:

  1. Criar um android: versionCode para o APK.

  2. Gravar o android: versionCode em um AndroidManifest.XML personalizado para esse APK.

  3. Compilar um build de versão do projeto Xamarin.Android que terá como destino exclusivo a ABI, usando o AndroidManifest.XML que foi criado na etapa anterior.

  4. Assine o APK com um repositório de chaves de produção.

  5. Efetuar o zipalign no APK.

Para compilar todos os APKs para o aplicativo, execute a tarefa do Rake build da linha de comando:

$ rake build
==> Building an APK for ABI armeabi with ./Properties/AndroidManifest.xml.armeabi, android:versionCode = 10814120.
==> Building an APK for ABI x86 with ./Properties/AndroidManifest.xml.x86, android:versionCode = 60814120.
==> Building an APK for ABI armeabi-v7a with ./Properties/AndroidManifest.xml.armeabi-v7a, android:versionCode = 20814120.

Após a tarefa rake ser concluída, haverá três pastas bin com o arquivo xamarin.helloworld.apk. A próxima captura de tela mostra cada uma dessas pastas com os respectivos conteúdos:

Locations of platform-specific folders containing xamarin.helloworld.apk

Observação

O processo de build descrito neste guia pode ser implementado em um dos diversos sistemas de build. Embora não tenhamos um exemplo escrito anteriormente, isso também deverá ser possível com Powershell / psake ou Fake.

Resumo

Este guia fornece algumas sugestões de como criar APKs do Android que se destinam a uma ABI específica. Ele também mostrou um esquema possível para a criação de android:versionCodes que identificará a arquitetura de CPU à qual o APK é destinado. O passo a passo inclui um projeto de exemplo que tem o script do seu build escrito usando Rake.