Únete a ⁠ #Android11: The Beta Launch Show el 3 de junio.

Compatibilidad con arquitecturas de 64 bits

A partir del 1 de agosto de 2019, las apps que publiques en Google Play tendrán que ser compatibles con arquitecturas de 64 bits. Las CPU de 64 bits brindan a los usuarios experiencias más enriquecidas y rápidas. Si agregas una versión de 64 bits a tu app, mejorarás su rendimiento, favorecerás la innovación y podrás ofrecerla para dispositivos que cuenten con hardware de 64 bits únicamente.

En esta guía, se explican los pasos que puedes realizar para asegurarte de que tu app de 32 bits sea compatible con dispositivos de 64 bits.

Cómo evaluar tu app

Si tu app solo usa código escrito en el lenguaje de programación Java o Kotlin, incluidas todas las bibliotecas y los SDK, es compatible con dispositivos de 64 bits. Sin embargo, si usa algún código nativo o no sabes con seguridad si lo hace, tendrás que evaluarla y tomar medidas.

Comprobación rápida de estado

Una manera rápida de comprobar si tu app está lista para el requisito de 64 bits consiste en ir a Play Console y consultar las versiones existentes para ver si cumplen los requisitos:

Si hay problemas relacionados con el requisito de 64 bits, Play Console también mostrará advertencias aplicables a tus versiones en borrador. Por ejemplo:

Si ves una alerta, sigue los pasos que se indican a continuación para preparar tu app.

¿Tu app usa código nativo?

Lo primero que debes hacer es verificar si tu app usa algún código nativo. Los siguientes casos indican que sí lo hace:

  • Usa cualquier código (nativo) C/C++.
  • Se vincula con alguna biblioteca nativa de terceros.
  • Fue compilada por terceros que usan bibliotecas nativas.

¿Tu app incluye bibliotecas de 64 bits?

La manera más sencilla de encontrar bibliotecas de 64 bits es analizar la estructura del archivo APK. Las bibliotecas nativas que necesita la app se incluyen durante la etapa de diseño del APK. Estas bibliotecas se almacenan en varias carpetas según la ABI. No es necesario ofrecer compatibilidad con todas las arquitecturas de 64 bits, pero por cada arquitectura de 32 bits nativa que admitas debes incluir la arquitectura de 64 bits correspondiente.

En el caso de la arquitectura ARM, las bibliotecas de 32 bits se encuentran en armeabi-v7a. El equivalente para la arquitectura de 64 bits es arm64-v8a.

En el caso de la arquitectura x86, busca x86 para 32 bits y x86_64 para 64 bits.

Lo primero que debes hacer es asegurarte de que se hayan incluido bibliotecas nativas en estas dos carpetas. En resumen:

Plataforma Carpeta de bibliotecas de 32 bits Carpeta de bibliotecas de 64 bits
ARM lib/armeabi-v7a lib/arm64-v8a
x86 lib/x86 lib/x86_64

Ten en cuenta que tal vez no se incluya exactamente el mismo conjunto de bibliotecas en cada carpeta, lo cual depende de tu app. El objetivo es asegurarse de que tu app se ejecute de manera correcta en un entorno solo de 64 bits.

En un caso típico, un APK o paquete diseñado para arquitecturas de 32 y 64 bits tiene carpetas para las dos ABI, y cada una incluye el conjunto de bibliotecas nativas correspondiente. Si no es compatible con la arquitectura de 64 bits, es posible que solo veas una carpeta para la ABI de 32 bits.

Cómo buscar bibliotecas nativas que usen el Analizador de APK

El Analizador de APK es una herramienta que permite evaluar varios aspectos de un APK compilado. En este caso, lo usaremos para buscar bibliotecas nativas y asegurarnos de que haya bibliotecas de 64 bits.

  1. Abre Android Studio y, luego, ingresa a cualquier proyecto.
  2. En el menú, selecciona Build > Analyze APK…

    Inicia el Analizador de APK

  3. Selecciona el APK que quieras evaluar.

  4. Busca los archivos ".so" en la carpeta lib. Si no encuentras ningún archivo ".so" en tu app, significa que está lista y no es necesario que realices ninguna acción. Si encuentras armeabi-v7a o x86, es porque tienes bibliotecas de 32 bits.

  5. Verifica si tienes archivos ".so" similares en las carpetas arm64-v8a o x86_64.

    Inicia el Analizador de APK

  6. Si no tienes ninguna biblioteca arm64-v8a ni x86_64, deberás actualizar el proceso de compilación para comenzar a compilar y empaquetar los artefactos en tu APK.

  7. Si ves las dos bibliotecas empaquetadas, puedes avanzar al paso Prueba tu app en un dispositivo de 64 bits.

Descomprime los archivos APK para buscar bibliotecas nativas

La estructura de los archivos APK y ZIP es similar, y estos se pueden extraer de la misma manera. Si lo prefieres, puedes usar la línea de comandos o cualquier otra herramienta de extracción para descomprimir los APK.

Descomprime el archivo APK (es posible que debas renombrarlo como .zip en función de la herramienta de extracción que utilices) y sigue las instrucciones que se indican más arriba para buscar los archivos correspondientes y verificar si tu app es compatible con dispositivos de 64 bits.

Por ejemplo, puedes ejecutar las siguientes acciones desde la línea de comandos:

:: Command Line
    > zipinfo -1 YOUR_APK_FILE.apk | grep \.so$
    lib/armeabi-v7a/libmain.so
    lib/armeabi-v7a/libmono.so
    lib/armeabi-v7a/libunity.so
    lib/arm64-v8a/libmain.so
    lib/arm64-v8a/libmono.so
    lib/arm64-v8a/libunity.so
    

Observa la presencia de las bibliotecas armeabi-v7a y arm64-v8a en este ejemplo, lo cual significa que la app es compatible con arquitecturas de 64 bits.

Compila tu app con bibliotecas de 64 bits

A continuación se incluyen instrucciones para compilar bibliotecas de 64 bits. Sin embargo, debes saber que estas indicaciones solo abarcan la compilación de códigos y bibliotecas que puedes procesar desde el código fuente.

Si usas bibliotecas o SDK externos, sigue los pasos que se indican más arriba para asegurarte de que correspondan a versiones de 64 bits. Si no hay versiones de 64 bits disponibles, comunícate con el propietario del SDK o la biblioteca y ten esto en cuenta cuando planifiques la compatibilidad con dispositivos de 64 bits.

Cómo compilar con Android Studio o Gradle

La mayoría de los proyectos de Android Studio usan Gradle como sistema de compilación subyacente; por lo tanto, esta sección se aplica a ambos casos. Si deseas habilitar las compilaciones para tu código nativo, solo tienes que agregar las carpetas arm64-v8a o x86_64 a la configuración de ndk.abiFilters del archivo "build.gradle" de tu app, según las arquitecturas con las que quieres que sea compatible:

// Your app's build.gradle
    apply plugin: 'com.android.app'

    android {
       compileSdkVersion 27
       defaultConfig {
           appId "com.google.example.64bit"
           minSdkVersion 15
           targetSdkVersion 28
           versionCode 1
           versionName "1.0"
           ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
    // ...
    

Cómo compilar con CMake

Si compilaste tu app con CMake, puedes adaptarla a las ABI de 64 bits. Para ello, debes pasar la carpeta arm64-v8a al parámetro "-DANDROID_ABI":

:: Command Line
    > cmake -DANDROID_ABI=arm64-v8a … or
    > cmake -DANDROID_ABI=x86_64 …
    

Esta opción no tiene ningún efecto cuando se usa externalNativeBuild. Consulta la sección Cómo compilar con Gradle.

Cómo compilar con ndk-build

Si compilaste tu app con ndk-build, puedes adaptarla a las ABI de 64 bits. Para ello, debes modificar el archivo Application.mk con la variable APP_ABI:

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
    

Esta opción no tiene ningún efecto cuando se usa externalNativeBuild. Consulta la sección Cómo compilar con Gradle.

Cómo migrar del código de 32 bits al de 64 bits

Si ya se ejecuta tu código en computadoras de escritorio o en iOS, no es necesario realizar ningún trabajo adicional para Android. Si es la primera vez que se compila tu código para un sistema de 64 bits, el problema principal que debes abordar es que los punteros ya no se ajustan a los tipos enteros de 32 bits como int. Deberás actualizar el código que almacena punteros en tipos como int, unsigned o uint32_t. En los sistemas Unix, long coincide con el tamaño del puntero, pero no sucede lo mismo en Windows, por lo que deberías usar tipos que demuestren la intención, como uintptr_t o intptr_t. Usa el tipo ptrdiff_t para almacenar la diferencia entre dos punteros.

Siempre deberías optar por los tipos de número entero de ancho fijo específicos que se definen en <stdint.h> en lugar de los tradicionales, como int o long, incluso para los elementos que no sean punteros.

Usa las siguientes marcas del compilador para identificar casos en los que tu código convierte punteros a números enteros, y viceversa, de manera incorrecta:

-Werror=pointer-to-int-cast
    -Werror=int-to-pointer-cast
    -Werror=shorten-64-to-32
    

Las clases Java con campos int que incluyen punteros en objetos C/C++ presentan el mismo problema. Busca jint en tu fuente JNI y asegúrate de cambiar a long en el lado de Java y a jlong en el lado de C++.

Las declaraciones de función implícitas son mucho más peligrosas para el código de 64 bits. C/C++ asume que el tipo de devolución de una función declarada de manera implícita (es decir, una función para la que el compilador no vio una declaración) es int. Si el tipo de devolución real de tu función es un puntero, funcionará bien en un sistema de 32 bits en el que tu puntero se adapta a un int. Sin embargo, en un sistema de 64 bits, el compilador cortará la mitad superior del puntero. Por ejemplo:

// This function returns a pointer:
    // extern char* foo();

    // If you don't include a header that declares it,
    // when the compiler sees this:
    char* result = foo();

    // Instead of compiling that to:
    result = foo();

    // It compiles to something equivalent to:
    result = foo() & 0xffffffff;

    // Which will then cause a SIGSEGV if you try to dereference `result`.
    

La siguiente marca del compilador convierte advertencias de declaración de funciones implícitas en errores para que puedas encontrar los problemas y solucionarlos más fácilmente:

-Werror=implicit-function-declaration
    

Si tienes un ensamblador intercalado, deberás volver a escribirlo o usar una implementación C/C++ simple.

Si tienes tamaños hard-coded de tipos (8 o 16 bytes, por ejemplo), reemplázalos con la expresión sizeof(T) equivalente, como sizeof(void*).

Si una de las condiciones es que necesitas compilar códigos diferentes para 32 bits y 64 bits, puedes usar #if defined(__LP64__) para diferencias 32/64 genéricas o __arm__, __aarch64__ (arm64), __i386__ (x86) y __x86_64__ para las arquitecturas específicas compatibles con Android.

Deberás ajustar las strings de formato para funciones similares a printf o scanf, ya que los especificadores de formato tradicionales no te permiten especificar tipos de 64 bits de una manera que sea correcta tanto para dispositivos de 32 bits como de 64 bits. Las macros PRI y SCN en <inttypes.h> solucionan este problema; PRIxPTR y SCNxPTR para punteros hexadecimales de escritura y lectura, mientras que PRId64 y SCNd64 para valores de 64 bits de escritura y lectura portátiles.

Cuando alternes, es posible que debas usar 1ULL para obtener una constante de 64 bits, en lugar de usar 1, que solo tiene 32 bits.

Cómo reducir los efectos del aumento de tamaño con Android App Bundle

Si modificas tu app para que sea compatible con la arquitectura de 64 bits, es posible que aumente el tamaño del APK. Te recomendamos que aproveches la función Android App Bundle para minimizar el impacto si incluyes códigos nativos de 32 y 64 bits en el mismo APK.

Si comienzas a usar los Android App Bundles en tu app, eso puede representar una mejora para el APK, ya que se reducirá el tamaño actual.

Desarrolladores de juegos

Sabemos que el proceso de migración de los motores de juegos de terceros es intenso y puede tomar mucho tiempo. Por suerte, los tres motores más usados son compatibles con la arquitectura de 64 bits:

  • Unreal desde 2015
  • Cocos2d desde 2015
  • Unity desde 2018

Desarrolladores de Unity

Actualiza a las versiones compatibles

Unity comenzó a admitir arquitecturas de 64 bits en las versiones 2018.2 y 2017.4.16.

Si detectas que tienes una versión de Unity que no es compatible con la arquitectura de 64 bits, determina aquella a la que quieras cambiarte y sigue las guías que ofrece Unity para migrar tu entorno. Para esto, debes asegurarte de que tu app pueda compilar bibliotecas de 64 bits. Unity recomienda que actualices tu app a la versión de LTS más reciente del editor para tener acceso a las funciones y actualizaciones más nuevas.

En la siguiente tabla se detallan las distintas versiones de Unity y lo que debes hacer:

Versión de Unity ¿Es compatible con la arquitectura de 64 bits? Acciones recomendadas

2018.4 (LTS)

✔️

Asegúrate de que la configuración de la compilación genere bibliotecas de 64 bits (actualización pendiente).

2018.3

✔️

Asegúrate de que la configuración de la compilación genere bibliotecas de 64 bits.

2018.2

✔️

Asegúrate de que la configuración de la compilación genere bibliotecas de 64 bits.

2018.1

Ofrece compatibilidad experimental con arquitecturas de 64 bits.

2017.4 (LTS)

✔️

Compatible a partir de la versión 2017.4.16. Asegúrate de que la configuración de la compilación genere bibliotecas de 64 bits.

2017.3

✖️

Actualiza a una versión que sea compatible con arquitecturas de 64 bits.

2017.2

✖️

Actualiza a una versión que sea compatible con arquitecturas de 64 bits.

2017.1

✖️

Actualiza a una versión que sea compatible con arquitecturas de 64 bits.

<=5.6

✖️

Actualiza a una versión que sea compatible con arquitecturas de 64 bits.

Cómo cambiar la configuración de la compilación para que genere bibliotecas de 64 bits

Si usas una versión de Unity compatible con bibliotecas de Android de 64 bits, puedes adaptar la configuración de la compilación para generar una versión de 64 bits de tu app. También tendrás que usar el código IL2CPP como backend de programación (puedes obtener más información aquí). Para configurar tu proyecto de Unity de manera que sea compatible con arquitecturas de 64 bits, sigue estos pasos:

  1. Accede a Build Settings y verifica que aparezca el símbolo de Unity junto a Android para asegurarte de que la compilación sea para esa plataforma.**
    1. De no ser así, selecciona Android y haz clic en Switch Platform.
  2. Haz clic en Player settings.

    Configuración del reproductor en Unity

  3. Ve a Player Settings Panel > Settings for Android > Other settings > Configuration.

  4. Establece el valor de Scripting Backend en IL2CPP.

  5. Selecciona la casilla de verificación **Target Architecture > ARM64.

    Configuración de arquitecturas de destino en Unity

  6. Procesa la compilación de forma habitual.

Ten en cuenta que, cuando realices este proceso para ARM64, tendrás que compilar todos los elementos para esa plataforma específica. Sigue las indicaciones de Unity para reducir el tamaño del APK y considera aprovechar la función Android App Bundle para reducir los efectos del aumento de tamaño.

Cumplimiento con el requisito de 64 bits y varios archivos APK

Si usas la compatibilidad con varios archivos APK de Google Play para publicar tu app, ten en cuenta que el cumplimiento del requisito de 64 bits se evalúa a nivel del lanzamiento. Sin embargo, el requisito de 64 bits no se aplica a los APK o paquetes de aplicación que no se distribuyen a dispositivos con Android 9 Pie o versiones posteriores.

Si uno de tus APK no cumple los requisitos, pero es más antiguo y no es posible lograr que lo haga, una estrategia consiste en agregar un atributo maxSdkVersion="27" del elemento uses-sdk en el manifiesto de ese APK. No se entregará este APK a los dispositivos que ejecuten Android 9 Pie o versiones posteriores y ya no impedirá el cumplimiento.

Cumplimiento con el requisito de 64 bits y RenderScript

Si tu app usa RenderScript y se la creó con una versión anterior de las herramientas de Android, es probable que la app presente problemas de cumplimiento del requisito de 64 bits. Con las herramientas de compilación anteriores a 21.0.0, el compilador podría generar código de bits en un archivo .bc externo. Estos archivos .bc heredados ya no son compatibles con las arquitecturas de 64 bits, de manera que el archivo en tu APK provoca el error de cumplimiento.

Para solucionar el problema, quita los archivos .bc de tu proyecto, actualiza el entorno a build-tools-21.0.0 o versiones posteriores y establece la renderscriptTargetApi en Android Studio en 21+ a fin de indicarle al compilador que no genere archivos .bc. A continuación, vuelve a compilar la app, verifica que no haya archivos .bc y súbela a Play Console.

Cómo probar tu app en hardware de 64 bits

La versión de 64 bits de tu app debe ofrecer la misma calidad y el mismo conjunto de funciones que la de 32 bits. Prueba tu app para asegurarte de que los usuarios que tengan los dispositivos de 64 bits más recientes disfruten de la mejor experiencia.

Para comenzar a probar tu app, necesitarás un dispositivo compatible con arquitecturas de 64 bits. Hay muchos dispositivos populares que cuentan con esta característica, como los smartphones de la línea Pixel de Google.

La manera más sencilla de probar tu APK es instalar la app mediante el uso de adb. En la mayoría de los casos, puedes suministrar --abi como parámetro para indicar las bibliotecas que quieres instalar en el dispositivo. De esta forma, se instalará la app solo con bibliotecas de 64 bits.

:: Command Line
    # A successful install:
    > adb install --abi armeabi-v7a YOUR_APK_FILE.apk
    Success

    # If your APK does not have the 64-bit libraries:
    > adb install --abi arm64-v8a YOUR_APK_FILE.apk
    adb: failed to install YOUR_APK_FILE.apk: Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]

    # If your device does not support 64-bit, an emulator, for example:
    > adb install --abi arm64-v8a YOUR_APK_FILE.apk
    ABI arm64-v8a not supported on this device
    

Una vez que la app se haya instalado de manera correcta, realiza la prueba como lo haces habitualmente para asegurarte de que tenga la misma calidad que la versión de 32 bits.

Publica tu app

Cuando consideres que tu app está lista, publícala de la manera habitual. Como siempre, sigue las recomendaciones para la implementación de tu app. Te aconsejamos que aproveches los segmentos de prueba cerrada para lanzar tu app entre una cantidad limitada de usuarios y garantizar el mismo nivel de calidad.

Asegúrate de haber probado tu app de manera exhaustiva en dispositivos compatibles con arquitecturas de 64 bits antes de publicarla para un segmento de usuarios más amplio, como cuando realizas el lanzamiento de una actualización importante.