The Android Developer Challenge is back! Submit your idea before December 2.

Cómo crear varios APK

Para publicar tu app en Google Play, debes compilar y subir un Android App Bundle. Cuando lo hagas, Google Play generará y publicará automáticamente los APK optimizados de la configuración del dispositivo de cada usuario, de manera que solo tengan que descargar el código y los recursos que necesiten para ejecutar tu app. La publicación de varios APK resulta útil cuando no publicas tu app en Google Play, pero deberás compilar, firmar y administrar cada APK tú mismo.

Si bien deberías crear un solo APK que admita todos los dispositivos de destino siempre que sea posible, quizás se genere uno muy grande debido a la cantidad de archivos necesarios para admitir varias densidades de pantalla o interfaces binarias de aplicación (ABI). Una forma de reducir el tamaño de tu APK es crear varios APK que contengan archivos para ABI o densidades de pantalla específicas.

Gradle puede crear APK separados que solo contengan el código y los recursos específicos de cada densidad o ABI. En esta página, se describe cómo configurar tu compilación a fin de generar varios APK. Si necesitas crear diferentes versiones de tu app que no se basen en la densidad de pantalla ni ABI, en su lugar, puedes usar variantes de compilación.

Cómo configurar tu compilación para varios APK

A fin de configurar tu compilación para varios APK, agrega un bloque splits a tu archivo build.gradle en el nivel del módulo. Dentro del bloque splits, incluye un bloque density que especifique la manera en que Gradle debe generar los APK por densidad, o bien un bloque abi que especifique la manera en que Gradle debería generar los APK por ABI. También puedes proporcionar bloques de ABI y densidad, y el sistema de compilación creará un APK para cada combinación de ABI y densidad.

Cómo configurar varios APK para densidades de pantalla

Si quieres crear APK individuales para las diferentes densidades de pantalla, agrega un bloque density en tu bloque splits. En tu bloque density, proporciona la lista de densidades de pantalla deseadas y tamaños de pantalla compatibles. La lista de tamaños de pantalla compatibles solo debe usarse si necesitas elementos <compatible-screens> específicos en el manifiesto de cada APK.

Las siguientes opciones de Gradle DSL se usan a fin de configurar varios APK para densidades de pantalla:

enable
Si configuras este elemento en true, Gradle generará varios APK basados en las densidades de pantalla que definas. El valor predeterminado es false.
exclude
Especifica la lista de densidades, separadas por comas, para las que Gradle no debería generar APK separados. Usa exclude si deseas generar APK para la mayoría de las densidades, pero necesitas excluir aquellas que tu app no admite.
reset()
Borra la lista predeterminada de densidades de pantalla. Solo debe usarse junto con el elemento include a fin de especificar las densidades que quieras agregar. En el siguiente fragmento, se configura la lista de densidades únicamente en ldpi y xxhdpi llamando a reset() para borrar la lista y, luego, usando include.
    reset()  // Clears the default list from all densities to no densities.
    include "ldpi", "xxhdpi" // Specifies the two densities we want to generate APKs for.
    
include
Especifica la lista de densidades, separadas por comas, para las que Gradle debería generar los APK. Solo se usa junto con reset() para especificar la lista exacta de densidades.
compatibleScreens
Especifica la lista de tamaños de pantalla compatibles separados por comas. De esta manera, se insertará un nodo <compatible-screens> que coincida en el manifiesto de cada APK. Esta opción permite administrar de manera conveniente las densidades y los tamaños de pantalla en la misma sección de build.gradle. Sin embargo, el uso de <compatible-screens> puede limitar los tipos de dispositivos en los que funcionará tu app. Para ver maneras alternativas de admitir diferentes tamaños de pantalla, consulta Cómo admitir varias pantallas.

Como cada APK que se basa en una densidad de pantalla incluye una etiqueta <compatible-screens> con restricciones específicas sobre qué tipos de APK admite (incluso si publicas varios APK), algunos dispositivos nuevos no coincidirán con tus filtros de varios APK. Por este motivo, Gradle siempre genera un APK universal adicional que contiene recursos para todas las densidades de pantalla y no incluye una etiqueta <compatible-screens>. Deberías publicar este APK universal junto con los APK por densidad a fin de proporcionar una solución alternativa para los dispositivos que no coincidan con los APK que incluyen una etiqueta <compatible-screens>.

En el siguiente ejemplo, se genera un APK separado para cada densidad de pantalla incluida en la lista de Pantallas admitidas, excepto por ldpi, xxhdpi y xxxhdpi. Para ello, se usa exclude a fin de quitar tres densidades de la lista predeterminada de todas las densidades.

    android {
      ...
      splits {

        // Configures multiple APKs based on screen density.
        density {

          // Configures multiple APKs based on screen density.
          enable true

          // Specifies a list of screen densities Gradle should not create multiple APKs for.
          exclude "ldpi", "xxhdpi", "xxxhdpi"

          // Specifies a list of compatible screen size settings for the manifest.
          compatibleScreens 'small', 'normal', 'large', 'xlarge'
        }
      }
    }
    

Para ver la lista de los nombres de densidades y tamaños de pantalla, consulta Cómo admitir varias pantallas. Para obtener más detalles sobre cómo distribuir una app a dispositivos y tipos de pantalla específicos, consulta Cómo distribuir a pantallas específicas.

Cómo configurar varios APK para las ABI

A fin de crear APK separados para diferentes ABI, agrega un bloque abi dentro de tu bloque splits. En el bloque abi, proporciona la lista de las ABI deseadas.

Para configurar varios APK por ABI, se usan las siguientes opciones de Gradle DSL:

enable
Si configuras este elemento en true, Gradle generará varios APK basados en las ABI que definas. El valor predeterminado es false.
exclude
Especifica la lista de las ABI, separadas por comas, para las que Gradle no debería generar APK separados. Usa exclude si deseas generar APK para la mayoría de las ABI, pero necesitas excluir aquellas que tu app no admite.
reset()
Borra la lista predeterminada de las ABI. Solo se usa junto con el elemento include a fin de especificar las ABI que quisieras agregar. En el siguiente fragmento, se configura la lista de ABI únicamente en x86 y x86_64 llamando a reset() para borrar la lista y, luego, usando include:
    reset()  // Clears the default list from all ABIs to no ABIs.
    include "x86", "x86_64" // Specifies the two ABIs we want to generate APKs for.
    
include
Especifica la lista de ABI, separadas por comas, para las que Gradle debería generar APK. Solo se usa junto con reset() a fin de especificar la lista exacta de ABI.
universalApk
Si se configura en true, Gradle generará un APK universal además de los APK por ABI. Un APK universal contiene el código y los recursos para todas las ABI en un único APK. El valor predeterminado es false. Ten en cuenta que esta opción solo está disponible en el bloque splits.abi. Al compilar varios APK basados en densidades de pantalla, Gradle siempre generará un APK universal con el código y los recursos para todas las densidades de pantalla.

En el siguiente ejemplo, se genera un APK separado para cada ABI: x86 y x86_64. Para ello, se usa reset() a fin de comenzar con la lista vacía de ABI, seguida de include con la lista de las ABI que para las que se generará un APK.

    android {
      ...
      splits {

        // Configures multiple APKs based on ABI.
        abi {

          // Enables building multiple APKs per ABI.
          enable true

          // By default all ABIs are included, so use reset() and include to specify that we only
          // want APKs for x86 and x86_64.

          // Resets the list of ABIs that Gradle should create APKs for to none.
          reset()

          // Specifies a list of ABIs that Gradle should create APKs for.
          include "x86", "x86_64"

          // Specifies that we do not want to also generate a universal APK that includes all ABIs.
          universalApk false
        }
      }
    }
    

Consulta la lista de las ABI admitidas aquí.

mips, mips64 y armeabi

A partir de la versión 3.1.0 del complemento de Android para Gradle, ya no se generan APK para las siguientes ABI de forma predeterminada: mips, mips64 y armeabi, puesto que NDK r17 y sus versiones posteriores ya no incluyen estas ABI como destinos admitidos.

Considera revisar primero Google Play Console a fin de verificar si hay usuarios que descargan los APK de tu app que se orientan a estas ABI. De lo contrario, es posible que quieras omitirlas en tu compilación. Si quieres seguir compilando APK que se orienten a estas ABI, deberás usar NDK r16 o una versión anterior y especificar las ABI en tu archivo build.gradle, como se muestra a continuación:

    splits {
        abi {
            include 'armeabi', 'mips', 'mips64'
            ...
        }
    }
    

Problema conocido: Si usas el complemento de Android para Gradle 3.0.1 o una versión anterior con NDK r17 o una versión posterior, es posible que experimentes el siguiente error: Error:ABIs [mips64, armeabi, mips] are not supported for platform. Este problema se produce porque las versiones anteriores del complemento aún incluyen las ABI no compatibles de forma predeterminada cuando compilas los APK por ABI. Para resolverlo, actualiza a la versión más reciente del complemento o, en el archivo build.gradle de tu app, restablece la lista predeterminada de ABI y, luego, incluye solo las ABI admitidas que desees, como se muestra a continuación:

    ...
    splits {
        abi {
            ...
            reset()
            include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
        }
    }
    

Cómo configurar el control de versiones

De manera predeterminada, cuando Gradle genera varios APK, cada uno de estos tendrá la misma información de versión, de acuerdo con lo que se especificó en el archivo build.gradle en el nivel del módulo. Como Google Play Store no permite varios APK con la misma información de versión para la misma app, deberás asegurarte de que cada APK tenga un versionCode único antes de subirlo a Play Store.

Puedes configurar tu archivo build.gradle en el nivel del módulo para que anule el versionCode de cada APK. Mediante la creación de una asignación que otorgue un único valor numérico a cada ABI y densidad para las que configures varios APK, podrás anular el código de versión de salida con un valor que combine el código de versión definido en el bloque defaultConfig o productFlavors con el valor numérico asignado a la densidad o ABI.

En el siguiente ejemplo, el APK para la ABI x86 obtendría un versionCode de 2004 y la ABI x86_64 obtendría el 3004. La asignación de códigos de versión en grandes incrementos (por ejemplo, de a 1,000) te permitirá asignar códigos de versión únicos más adelante en caso de que necesites actualizar tu app. Por ejemplo, si defaultConfig.versionCode itera a 5 en una actualización posterior, Gradle asignaría un versionCode de 2005 al APK x86 y de 3005 al APK x86_64.

Sugerencia: Si tu compilación incluye un APK universal, deberías asignarlo a un versionCode que sea inferior al de los otros APK. Como Google Play Store instala la versión de tu app que es compatible con el dispositivo de destino y tiene el versionCode más alto, asignar un versionCode inferior al del APK universal garantiza que Google Play Store intente instalar uno de tus APK antes de recurrir al APK universal. En el siguiente código de ejemplo, se realiza esta acción sin anular el versionCode predeterminado del APK universal.

    android {
      ...
      defaultConfig {
        ...
        versionCode 4
      }
      splits {
        ...
      }
    }

    // Map for the version code that gives each ABI a value.
    ext.abiCodes = ['armeabi-v7a':1, x86:2, x86_64:3]

    // For per-density APKs, create a similar map like this:
    // ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3]

    import com.android.build.OutputFile

    // For each APK output variant, override versionCode with a combination of
    // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode
    // is equal to defaultConfig.versionCode. If you configure product flavors that
    // define their own versionCode, variant.versionCode uses that value instead.
    android.applicationVariants.all { variant ->

      // Assigns a different version code for each output APK
      // other than the universal APK.
      variant.outputs.each { output ->

        // Stores the value of ext.abiCodes that is associated with the ABI for this variant.
        def baseAbiVersionCode =
                // Determines the ABI for this variant and returns the mapped value.
                project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))

        // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes,
        // the following code does not override the version code for universal APKs.
        // However, because we want universal APKs to have the lowest version code,
        // this outcome is desirable.
        if (baseAbiVersionCode != null) {

          // Assigns the new version code to versionCodeOverride, which changes the version code
          // for only the output APK, not for the variant itself. Skipping this step simply
          // causes Gradle to use the value of variant.versionCode for the APK.
          output.versionCodeOverride =
                  baseAbiVersionCode * 1000 + variant.versionCode
        }
      }
    }
    

Para obtener más ejemplos de esquemas de códigos de versión alternativos, consulta Cómo asignar códigos de versión.

Cómo crear varios APK

Una vez que configuraste el archivo build.gradle en el nivel del módulo a fin de compilar varios APK, haz clic en Build > Build APK para compilar todos los APK del módulo seleccionado actualmente en el panel Project. Gradle crea los APK para cada densidad o ABI en el directorio build/outputs/apk/ del proyecto.

Gradle compila un APK de cada densidad o ABI para las que configuras varios APK. Si habilitas varios APK tanto para las densidades como para las ABI, Gradle creará un APK para cada combinación de densidad y ABI. Por ejemplo, en el siguiente fragmento de build.gradle, se habilita la compilación de varios APK para las densidades "mdpi" y "hdpi", y también para las ABI "x86" y "x86_64":

    ...
      splits {
        density {
          enable true
          reset()
          include "mdpi", "hdpi"
        }
        abi {
          enable true
          reset()
          include "x86", "x86_64"
        }
      }
    

En el resultado de la configuración de ejemplo, se incluyen los 4 APK siguientes:

  • app-hdpiX86-release.apk: Contiene únicamente el código y los recursos para la densidad "hdpi" y la ABI "x86".
  • app-hdpiX86_64-release.apk: Contiene únicamente el código y los recursos para la densidad "hdpi" y la ABI "x86_64".
  • app-mdpiX86-release.apk: Contiene únicamente el código y los recursos para la densidad "mdpi" y la ABI "x86".
  • app-mdpiX86_64-release.apk: Contiene únicamente el código y los recursos para la densidad "mdpi" y la ABI "x86_64".

Al compilar varios APK basados en densidades de pantalla, Gradle siempre genera un APK universal que incluye el código y los recursos para todas las densidades, además de los APK por densidad. En cambio, al compilar varios APK basados en la ABI, Gradle solo generará un APK que incluya el código y los recursos para todas las ABI si especificas universalApk true en el bloque splits.abi de tu archivo build.gradle.

Formato de nombre de archivo APK

Cuando compilas varios APK, Gradle usa nombres de archivos APK con el siguiente esquema:

modulename-screendensityABI-buildvariant.apk

Los componentes del esquema son los siguientes:

modulename
Especifica el nombre del módulo que se está compilando.
screendensity
Si se habilitan varios APK para densidades de pantalla, especifica la densidad de pantalla del APK, por ejemplo, "mdpi".
ABI
Si se habilitan varios APK para la ABI, especifica la ABI del APK, por ejemplo, "x86". Si se habilitan varios APK tanto para la densidad de pantalla como para la ABI, Gradle concatena el nombre de la densidad con el nombre de la ABI, por ejemplo, "mdpiX86". Si universalApk está habilitado para los APK por ABI, Gradle usa "universal" como la parte de la ABI del nombre de archivo del APK universal.
buildvariant
Especifica la variante de compilación que se está compilando, por ejemplo, de "depuración".

Por ejemplo, al compilar el APK de densidad de pantalla "mdpi" para la versión de depuración de "myApp", el nombre de archivo del APK es myApp-mdpi-debug.apk. La versión de lanzamiento de "myApp" que se configuró en varios APK tanto para la densidad de pantalla "mdpi" como para la ABI "x86" tendrá el nombre de archivo del APK de myApp-mdpiX86-release.apk.