Cómo crear varios APK para diferentes texturas de GL

Para publicar tu app en Google Play, debes compilar y subir un Android App Bundle. Cuando lo haces, Google Play genera y publica automáticamente APK optimizados para la configuración del dispositivo de cada usuario, por lo que este solo debe descargar el código y los recursos que necesita para ejecutar tu app. Publicar varios APK es útil si no publicas en Google Play, pero debes compilar, firmar y administrar cada APK por tu cuenta.

Cuando desarrolles tu aplicación para Android con el objetivo de aprovechar múltiples APK en Google Play, es importante que adoptes algunas prácticas recomendadas desde el principio y evites dolores de cabeza innecesarios en el proceso de desarrollo. En esta lección, se muestra cómo crear varios APK de tu app, en la que cada uno admite un subconjunto diferente de formatos de texturas OpenGL. También obtendrás algunas herramientas necesarias para que el mantenimiento de una base de código APK múltiple sea lo más sencillo posible.

Cómo confirmar que necesitas varios APK

Cuando intentas crear una aplicación que funcione en todos los dispositivos con Android disponibles, es natural que busques que la aplicación tenga el mejor aspecto en cada dispositivo, aunque no todos sean compatibles con el mismo conjunto de texturas de GL. Al principio, puede parecer que la compatibilidad con varios APK es la mejor solución, pero a menudo este no es el caso. La sección Cómo usar un solo APK de la guía para desarrolladores de varios APK contiene información útil sobre cómo lograrlo con un solo APK, incluso sobre cómo detectar formatos de textura compatibles durante el tiempo de ejecución. Según tu situación, tal vez sea más fácil agrupar todos los formatos con tu app y solo elegir el que se va a usar durante el tiempo de ejecución.

Si puedes administrarla, limitar tu aplicación a un solo APK tiene varias ventajas, entre las que se incluyen las siguientes:

  • Es más fácil realizar publicaciones y pruebas.
  • Solo hay que mantener una base de código.
  • Tu app se puede adaptar a los cambios de configuración del dispositivo.
  • Funciona el restablecimiento de apps en dispositivos.
  • No tienes que preocuparte por la preferencia del mercado, por el comportamiento de las "actualizaciones" de un APK al siguiente, o por el APK adecuado para cada clase de dispositivos.

En el resto de esta lección, se supone que investigaste el tema, absorbiste detenidamente el material de los recursos vinculados y determinaste que varios APK son la ruta correcta para tu aplicación.

Cómo organizar tus requisitos

En la página supports-gl-texture de la guía para desarrolladores de Android, se proporciona una referencia práctica sobre algunas de las texturas compatibles más comunes. En esta página, también se incluyen algunas sugerencias sobre qué teléfonos (o familias de teléfonos) admiten formatos de textura específicos. Ten en cuenta que, en general, es útil que uno de los APK admita ETC1, ya que ese formato de textura es compatible con todos los dispositivos que ejecutan Android y admiten la especificación OpenGL ES 2.0.

Como la mayoría de los dispositivos con Android admiten más de un formato de textura, debes establecer un orden de preferencia. Crea un gráfico que incluya todos los formatos que admitirá tu aplicación. La celda ubicada en el extremo izquierdo será la prioridad más baja (probablemente será ETC1, un valor predeterminado muy sólido en términos de rendimiento y compatibilidad). Luego, colorea el gráfico de manera que cada celda represente un APK.

ETC1 ATI PowerVR

Los colores del gráfico no solo hacen que esta guía sea menos monocromática, sino que también permiten facilitar la comunicación dentro del equipo. Ahora puedes referirte a cada APK como "azul", "verde" o "rojo", en lugar de "el que admite formatos de textura ETC1", etcétera.

Cómo colocar todos los recursos y el código común en un proyecto de biblioteca

Si vas a modificar una app para Android existente o comenzar una desde cero, esto es lo primero, y lo más importante, que deberías hacer con la base de código base. Solo se necesita actualizar una vez todo lo que entra en el proyecto de biblioteca (como cadenas localizadas para diferentes idiomas, temas de color, corrección de errores en el código compartido). De esa forma, mejorará el tiempo de desarrollo y habrá menos errores que podrían haberse evitado fácilmente.

Nota: Si bien los detalles de la implementación sobre cómo crear e incluir proyectos de biblioteca están fuera del alcance de esta lección, puedes consultar Cómo crear una biblioteca de Android para obtener más información.

Si estás convirtiendo una aplicación existente para usar la compatibilidad con varios APK, examina tu base de código en busca de todos los archivos de cadenas localizadas, listas de valores, colores de tema, íconos de menú y diseños que no vas a cambiar entre los APK, y pon todo en el proyecto de la biblioteca. También debes incluir en este proyecto el código que no sufrirá demasiados cambios. Es probable que estés extendiendo estas clases para agregar uno o dos métodos de un APK a otro.

Si, en cambio, estás creando la app desde cero, primero intenta escribir el código en el proyecto de la biblioteca y, luego, transfiérelo a un APK individual, si es necesario. Esto es mucho más fácil de administrar a largo plazo que agregar código a uno, luego a otro y a otro, y meses más tarde intentas averiguar si se puede transferir este BLOB a la biblioteca sin arruinar nada.

Cómo crear nuevos proyectos de APK

Debe haber un proyecto de Android por separado para cada APK que vas a publicar. Para organizarte de manera sencilla, coloca el proyecto de la biblioteca y todos los proyectos de APK relacionados en la misma carpeta principal. Además, recuerda que cada APK debe tener el mismo nombre de paquete, aunque no necesariamente deben compartir el nombre del paquete con la biblioteca. Si tuvieras 3 APK que siguen el esquema descrito anteriormente, tu directorio raíz podría verse de la siguiente manera:

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

Una vez que se creen los proyectos, agrega el proyecto de la biblioteca como referencia para cada proyecto de APK. Si es posible, define tu actividad inicial en el proyecto de la biblioteca y extiende esa actividad en tu proyecto de APK. Tener una actividad inicial definida en el proyecto de la biblioteca te permite poner toda la inicialización de tu aplicación en un solo lugar, de modo que cada APK individual no tenga que volver a implementar tareas "universales", como inicializar Analytics, ejecutar verificaciones de licencias y cualquier otro procedimiento de inicialización que no cambie mucho de un APK a otro.

Cómo ajustar los manifiestos

Cuando un usuario descarga una aplicación que usa varios APKs a través de Google Play, el APK correcto que se usará se elige según algunas reglas simples:

  • El manifiesto tiene que mostrar que un APK en particular es apto.
  • De los APK aptos, se da prioridad al que tiene el número de versión más alto.
  • Si alguno de los formatos de texturas enumerados en tu APK es compatible con un dispositivo que se encuentra en el mercado, ese dispositivo se considera apto.

Con respecto a las texturas GL, esta última regla es importante. Esto significa que, por ejemplo, debes tener mucho cuidado cuando usas diferentes formatos GL en la misma app. Si usaras PowerVR el 99% del tiempo, pero usas ETC1 para, digamos, la pantalla de presentación, el manifiesto indicaría necesariamente que es compatible con ambos formatos. Un dispositivo que solo admita ETC1 se considera compatible; tu app podría descargarse, y el usuario vería algunos mensajes de fallas. Lo más habitual es que, si usas varios APK para orientar específicamente los anuncios a diferentes dispositivos según la compatibilidad con la textura GL, haya un formato de textura por APK.

Esto hace que la compatibilidad con texturas sea un poco diferente a las otras dos dimensiones de APK múltiples: el nivel de API y el tamaño de la pantalla. Cualquier dispositivo solo tiene un nivel de API y un tamaño de pantalla, y depende del APK admitir una variedad de ellos. En el caso de las texturas, el APK admitirá, por lo general, una sola, y el dispositivo admitirá muchas. A menudo, habrá superposiciones en cuanto que un dispositivo admita varios APK, pero la solución es la misma: códigos de versión.

A modo de ejemplo, toma algunos dispositivos y observa cuántos de los APK que se definieron anteriormente se ajustan a cada dispositivo.

FooPhone Nexus S Evo
ETC1 ETC1 ETC1
PowerVR ATI TC

Suponiendo que los formatos PowerVR y ATI sean preferidos sobre ETC1 cuando estén disponibles, según la regla por la que se da prioridad al que tiene el número de versión más alto, si establecemos el atributo versionCode en cada APK de modo que rojo ≥ verde ≥ azul, entonces el rojo y el verde siempre se elegirán en lugar del azul en los dispositivos que los admitan. Si alguna vez aparece un dispositivo que admita el rojo y el verde, se elegirá el rojo.

Para mantener todos tus APKs en "segmentos" separados, es importante tener un buen esquema de código de versión. Se recomienda usar el que se encuentra en el área Códigos de versión de nuestra guía para desarrolladores. Como el conjunto de ejemplos de APK solo abarca una de 3 dimensiones posibles, basta con separar cada APK por 1,000 y comenzar a sumar desde allí. El aspecto podría ser el siguiente:

Azul: 1,001, 1,002, 1,003, 1,004…
Verde: 2,001, 2,002, 2,003, 2,004…
Rojo:3,001, 3,002, 3,003, 3,004…

Si se junta todo, es probable que los manifiestos de Android se vean así:

Azul:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
    ...

Verde:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="2001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_AMD_compressed_ATC_texture" />
    ...

Rojo:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="3001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_IMG_texture_compression_pvrtc" />
    ...

Cómo revisar tu lista de tareas previa al lanzamiento

Antes de subir tu proyecto a Google Play, verifica los siguientes elementos. Recuerda que estos son solo pertinentes para varios APK, y de ninguna manera representan una lista de tareas completa para todas las apps que se suben a Google Play.

  • Todos los APK deben tener el mismo nombre de paquete.
  • Todos los APK deben estar firmados con el mismo certificado.
  • Comprueba que los filtros de manifiesto no tengan información contradictoria (a un APK que solo admita Cupcake en las pantallas extragrandes no lo verá nadie).
  • El manifiesto de cada APK debe ser único en al menos una de las pantallas, texturas de OpenGL o versiones de plataforma compatibles.
  • Intenta probar cada APK en al menos un dispositivo. Salvo eso, tienes uno de los emuladores de dispositivos más personalizables de la industria en tu máquina de desarrollo. ¡Disfruta a lo grande!

También vale la pena inspeccionar el APK compilado antes de lanzarlo al mercado, para asegurarte de que no haya sorpresas que puedan ocultar tu app en Google Play. Esto es bastante simple con la herramienta "aapt". Aapt (Android Asset Packaging Tool) es parte del proceso de compilación para crear y empaquetar tus aplicaciones para Android, y también es una herramienta muy útil para inspeccionarlas.

>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'

Cuando examines el resultado de aapt, asegúrate de verificar que no tengas valores en conflicto para supports-screens y compatible-screens, y que no tengas valores "uses-feature" no deseados que se hayan agregado como resultado de los permisos que estableciste en el manifiesto. En el ejemplo anterior, el APK será invisible para la mayoría de los dispositivos, si no para todos.

¿Por qué? Cuando agregas el permiso necesario SEND_SMS, se agregó de manera implícita el requisito de función de android.hardware.telephony. Como la mayoría de los dispositivos extragrandes (si no todos) son tabletas sin hardware de telefonía, Google Play filtrará este APK en estos casos, hasta que aparezcan dispositivos futuros que tengan el tamaño suficiente para ser tratado como tamaño de pantalla extragrande y cuenten con hardware de telefonía.

Por suerte, esto se soluciona fácilmente si agregas lo siguiente en el manifiesto:

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

También se agrega de forma implícita el requisito android.hardware.touchscreen. Si quieres que el APK sea visible en TVs sin pantalla táctil, debes agregar lo siguiente en el manifiesto:

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

Cuando completes la lista de tareas previa al lanzamiento, sube los APK a Google Play. Es posible que la app demore un poco en aparecer cuando navegas por Google Play. Cuando aparezca, realiza una última comprobación. Descarga la app en cualquier dispositivo de prueba para asegurarte de que los APK estén orientados a los dispositivos previstos. ¡Felicitaciones! Eso es todo.