Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Descripción general de la entrega de funciones en Play

El modelo de entrega de apps de Google Play usa paquetes Android App Bundle a fin de generar y publicar APK optimizados para la configuración del dispositivo de cada usuario, de manera que los usuarios descarguen solo el código y los recursos necesarios para ejecutar la app.

La publicación de funciones en Play usa capacidades avanzadas de los paquetes de aplicaciones, lo que permite que ciertas funciones se entreguen a tu app de manera condicional o se descarguen a pedido.

Cómo usar los módulos de funciones para la entrega personalizada

Un beneficio único de los módulos de funciones es la habilidad de personalizar cómo y cuándo se descargan las diferentes funciones de la app en dispositivos con Android 5.0 (nivel de API 21) o versiones posteriores. Por ejemplo, a fin de reducir el tamaño de la descarga inicial de tu app, puedes configurar ciertas funciones para que se descarguen a pedido según sea necesario o solo en dispositivos que admitan ciertas capacidades, como la posibilidad de tomar fotografías o admitir funciones de realidad aumentada.

Si bien cuando subes tu app como un paquete de aplicación obtienes una descarga altamente optimizada de manera predeterminada, las opciones de entrega de funciones más avanzadas y personalizables requieren una configuración adicional y la modularización de las funciones de la app mediante módulos de funciones. Es decir, los módulos de funciones proporcionan los componentes básicos para crear funciones modulares que puedes configurar a fin de que se descarguen según sea necesario.

Piensa en una app que permite a los usuarios comprar y vender bienes en un mercado en línea. Puedes modularizar razonablemente cada una de las siguientes funciones de la app en módulos de funciones independientes:

  • Acceso y creación de cuentas
  • Navegación por el mercado
  • Colocación de un artículo a la venta
  • Procesamiento de pagos

En la tabla que sigue, se describen las diferentes opciones de entrega que admiten los módulos de funciones y cómo se pueden usar para optimizar el tamaño de descarga inicial en el ejemplo de la aplicación de Marketplace.

Opción de entrega Comportamiento Caso práctico de muestra Cómo comenzar
Entrega durante la instalación Los módulos de funciones que no configuran ninguna de las opciones de entrega descritas con anterioridad se descargan de forma predeterminada cuando se instala la app. Este es un comportamiento importante porque permite adoptar de manera gradual opciones de entrega avanzadas. Por ejemplo, puedes aprovechar la modularización de funciones de la app y habilitar la entrega on demand solo después de haber implementado por completo las descargas on demand usando la biblioteca de Play Core.

Además, la app puede solicitar la desinstalación de funciones más adelante. Por lo tanto, si necesitas ciertas funciones al instalar la app, pero no después de ese momento, puedes reducir el tamaño de la instalación solicitando que se quiten esas funciones del dispositivo.

Si la app tiene ciertas actividades de capacitación, como una guía interactiva sobre cómo comprar y vender artículos en el mercado, puedes incluir esa función en la instalación de la app de manera predeterminada.

Sin embargo, para reducir el tamaño instalado de la app, esta puede solicitar eliminar la función después de que el usuario haya completado la capacitación.

Modulariza tu app con módulos de funciones que no configuren opciones de entrega avanzadas.

Para aprender a reducir el tamaño instalado de tu app gracias a la extracción de ciertos módulos de funciones que el usuario ya no necesita, consulta Cómo administrar módulos instalados.

Entrega a pedido Permite que la app solicite y descargue módulos de funciones según sea necesario. Si solo el 20% de los usuarios de la aplicación de Marketplace publican artículos para la venta, una buena estrategia de reducción del tamaño de descarga inicial para la mayoría de los usuarios es ofrecer la funcionalidad de tomar fotos, incluir una descripción del artículo y colocar un artículo a la venta como descarga a pedido. Es decir, puedes configurar el módulo de funciones para que la funcionalidad de venta de la app se descargue solo cuando un usuario muestre interés en colocar artículos para la venta en el mercado.

Además, si el usuario ya no vende artículos después de un cierto tiempo, la app puede solicitar la desinstalación de la función para reducir su tamaño instalado.

Crea un módulo de funciones y configura la entrega a pedido. La app puede usar la biblioteca de Play Core para solicitar la descarga del módulo a pedido.
Entrega condicional Permite especificar ciertos requisitos del dispositivo del usuario, como funciones de hardware, configuración regional y un nivel mínimo de API, para determinar si una función modularizada se descarga cuando se instala la app. Si la aplicación de Marketplace tiene alcance global, puede ser necesario admitir formas de pago que se usan solo en ciertas regiones o países. A fin de reducir el tamaño de descarga inicial de la app, puedes crear módulos de funciones individuales para procesar ciertos tipos de formas de pago y, luego, instalarlos de forma condicional en el dispositivo de un usuario según su configuración regional registrada. Crea un módulo de funciones y configura la entrega condicional.
Entrega instantánea Google Play Instant permite a los usuarios interactuar con tu app sin necesidad de instalar APK en sus dispositivos. En cambio, pueden experimentar la app a través del botón "Probar ahora" en Google Play Store o una URL que crees. Esta forma de entregar contenido hace que sea más fácil aumentar la interacción con tu app.

Con la entrega instantánea, puedes usar Google Play Instant para permitir que los usuarios experimenten al instante ciertas funciones de la app sin instalación.

Por ejemplo, un juego que incluya los primeros niveles en un módulo de funciones liviano. Puedes habilitar instantáneamente ese módulo para que los usuarios puedan experimentar el juego de inmediato a través de un vínculo a una URL o del botón "Probar ahora", sin necesidad de instalar la app. Crea un módulo de funciones y configura la entrega instantánea. La app puede usar la biblioteca de Play Core para solicitar la descarga del módulo a pedido.

Ten en cuenta que modularizar las funciones de tu app mediante módulos de funciones es solo el primer paso. Para admitir Google Play Instant, el tamaño de descarga del módulo base de la app y una cierta función habilitada instantáneamente deben cumplir con estrictas restricciones de tamaño. Para obtener más información, lee Cómo habilitar experiencias instantáneas reduciendo el tamaño de la app o el juego.

Cómo modularizar tu app

La modularización de una app es el proceso de separar componentes lógicos del proyecto de app en módulos independientes.

La reorganización de la funcionalidad de tu app en estos componentes independientes requiere una evaluación cuidadosa y tiempo. Sin embargo, la modularización proporciona a tu proyecto los siguientes beneficios:

  • Desarrollo en paralelo: Como se separan los componentes lógicos de la app en módulos, diferentes equipos o personas de tu organización pueden ocuparse de cada módulo y trabajar en ellos con menos conflictos de fusión o interrupciones para otros equipos. Además, si usas lógica que se implementa en varias partes de la app, puedes usar módulos de biblioteca para facilitar la reutilización y encapsulación de código.
  • Mejores tiempos de compilación: Los sistemas de compilación, como Android Studio con Gradle, están optimizados para proyectos organizados en módulos. Por ejemplo, si habilitas la optimización de ejecución de proyectos en paralelo de Gradle en una estación de trabajo que incluye un procesador multinúcleo, el sistema de compilación puede compilar varios módulos en paralelo y reducir significativamente los tiempos de compilación. Cuanto más modular sea tu proyecto, más significativa será la mejora del rendimiento de la compilación.
  • Entrega de funciones personalizada: Modularizar las funciones de la app como módulos de funciones es un requisito para aprovechar las opciones de entrega personalizada de la entrega de funciones de Play, como a pedido, condicional y entrega instantánea. Crear funciones a pedido requiere más esfuerzo y, posiblemente, la refactorización de la app. Por lo tanto, evalúa cuidadosamente cuáles de las funciones de la app convendría modularizar en módulos de funciones a fin de aprovechar las opciones de entrega personalizada.

La correcta modularización de tu proyecto según las funciones de la app requiere tiempo y consideración. Cuando decidas comenzar a modularizar tu app, primero deberás configurar el módulo base con las propiedades necesarias para admitir funciones modulares. Luego, puedes modularizar gradualmente las funciones de la app sin modificar el comportamiento actual de la app mediante la configuración de los módulos de funciones para la entrega durante la instalación.

Manifiesto del módulo de funciones

Cuando creas un módulo de funciones nuevo con Android Studio, el IDE incluye la mayoría de los atributos de manifiesto que el módulo requiere para comportarse como un módulo de funciones. Además, el sistema de compilación inserta algunos atributos en el tiempo de compilación, por lo que no necesitas especificarlos ni modificarlos. En la tabla siguiente, se describen los atributos de manifiesto que son importantes para los módulos de funciones.

Atributo Descripción
<manifest
...
Este es un bloque <manifest> típico.
xmlns:dist="http://schemas.android.com/apk/distribution" Especifica un nuevo espacio de nombres XML dist: que se describe más adelante.
split="split_name" Cuando Android Studio compila el paquete de aplicación, incluye este atributo automáticamente. Por lo tanto, no debes incluir ni modificar este atributo.

Define el nombre del módulo, que la app especifica cuando solicita un módulo on demand desde la biblioteca de Play Core.

Cómo hace Gradle para determinar el valor de este atributo:

De forma predeterminada, cuando creas un módulo de funciones con Android Studio, el IDE usa lo que especificas como su nombre del módulo para identificar el módulo como un subproyecto de Gradle en tu Archivo de configuración de Gradle.

Cuando compilas tu paquete de aplicación, Gradle usa el último elemento de la ruta de acceso del subproyecto para insertar este atributo del manifiesto en el manifiesto del módulo. Por ejemplo, si creas un módulo de función nuevo en el directorio MyAppProject/features/ y especificas el valor "dynamic_feature1" como nombre del módulo, el IDE agrega ':features:dynamic_feature1' como un subproyecto en tu archivo settings.gradle. Cuando compilas tu paquete de aplicación, Gradle inserta <manifest split="dynamic_feature1"> en el manifiesto del módulo.

android:isFeatureSplit="true | false"> Cuando Android Studio compila el paquete de aplicación, incluye este atributo automáticamente. Por lo tanto, no debes incluir ni modificar este atributo de forma manual.

Especifica que este módulo es un módulo de función. Los manifiestos en el módulo base y los APK de configuración omiten este atributo o lo configuran como false.

<dist:module Este nuevo elemento XML define atributos que determinan cómo se empaqueta y distribuye el módulo como APK.
dist:instant="true | false" Especifica si el módulo debe estar disponible a través de Google Play Instant como una experiencia instantánea.

Si tu app incluye uno o más módulos de funciones habilitadas instantáneamente, también debes habilitar al instante el módulo base. Cuando usas Android Studio 3.5 o versiones posteriores, el IDE lo hace automáticamente cuando creas un módulo de funciones habilitadas instantáneamente.

No es posible configurar este elemento XML en true y, al mismo tiempo, establecer <dist:on-demand/>. Sin embargo, todavía puedes solicitar descargas a pedido de los módulos de funciones habilitadas instantáneamente como experiencias instantáneasmediante la biblioteca de Play Core. Cuando un usuario descarga la app y la instala, el dispositivo descarga y luego instala los módulos de funciones habilitadas instantáneamente de la app, junto con el APK base, de forma predeterminada.

dist:title="@string/feature_name" Especifica un título para el módulo que se mostrará al usuario. Por ejemplo, el dispositivo puede mostrar este título cuando solicita confirmación de descarga.

Debes incluir el recurso de strings para este título en el archivo module_root/src/source_set/res/values/strings.xml del módulo base.

<dist:fusing dist:include="true | false" />
</dist:module>
Especifica si se debe incluir el módulo en APK múltiples orientados a dispositivos con Android 4.4 (API nivel 20) y versiones anteriores.

Además, cuando usas bundletool para generar APK a partir de un paquete de aplicación, solo los módulos de funciones que establecen esta propiedad en true se incluyen en el APK universal, que es un APK monolítico que incluye código y recursos para todas las configuraciones del dispositivo que admite tu app.

<dist:delivery> Encapsula opciones que personalizan la entrega de los módulos, como se muestra a continuación. Ten en cuenta que en cada módulo de funciones se debe configurar solo un tipo de estas opciones de entrega personalizadas.
<dist:install-time> Especifica que el módulo debe estar disponible en el momento de la instalación. Este es el comportamiento predeterminado de los módulos de funciones que no especifican otro tipo de opción de entrega personalizada.

Para obtener más información sobre las descargas en el momento de la instalación, consulta Cómo configurar la entrega durante la instalación.

Este nodo también puede especificar condiciones que limitan el módulo a dispositivos que cumplen con ciertos requisitos, como las funciones del dispositivo, el país del usuario o el nivel mínimo de API. Para obtener más información, consulta Cómo configurar la entrega condicional.

<dist:removable value="true | false" />

Si bundletool no se configura o se establece en false, se fusionarán los módulos de tiempo de instalación con el módulo base cuando generes APK divididos desde el paquete. Como quedarán menos APK divididos después de la fusión, esta configuración puede mejorar el rendimiento de tu app.

Cuando se establece removable en true, los módulos de tiempo de instalación no se fusionarán con el módulo base. Configúralo en true si deseas desinstalar módulos en el futuro. Sin embargo, configurar demasiados módulos removibles puede aumentar el tiempo de instalación de tu app.

La configuración predeterminada es false. Solo es necesario establecer este valor en el manifiesto si deseas inhabilitar la fusión de un módulo de funciones.

Nota: Esta función solo está disponible cuando usas el complemento de Gradle para Android 4.2 o cuando usas bundletool v1.0 desde la línea de comandos.

</dist:install-time>  
<dist:on-demand/> Especifica que el módulo debe estar disponible como descarga a pedido. Es decir, el módulo no está disponible en el momento de la instalación, pero es posible que la app solicite descargarlo más tarde.

Si deseas obtener más información sobre las descargas a pedido, consulta Cómo configurar la entrega a pedido.

</dist:delivery>
<application
android:hasCode="true | false">
...
</application>
Si el módulo de funciones no genera archivos DEX, es decir, no contiene ningún código que luego se compile en el formato de archivo DEX, debes hacer lo siguiente (de lo contrario, puedes encontrar errores en el tiempo de ejecución):
  1. Configura android:hasCode como "false" en el manifiesto del módulo de funciones.
  2. Agrega lo siguiente al manifiesto de tu módulo base:
    
    <application
      android:hasCode="true"
      tools:replace="android:hasCode">
      ...
    </application>
    

Cómo probar la entrega de funciones en Play

La mejor manera de probar la entrega de funciones en Play es mediante Google Play Store. Esto se debe a que muchos de los beneficios de la entrega de funciones de Play se basan en aplazar la generación, firma y publicación de APK en Play Store. Por lo tanto, si solo subes un paquete de aplicación o configuras opciones de entrega más avanzadas, debes usar los siguientes métodos para probar la app.

  • Comparte tu app mediante una URL. Esta es la manera más rápida de subir tu paquete de aplicación y compartir la app como un vínculo de Google Play Store con verificadores de confianza. Además, es el método más rápido para probar opciones de publicación personalizadas, como la descarga de funciones a pedido.
  • Configura una prueba abierta, cerrada o interna Este método proporciona canales de prueba estructurados y es una buena manera de probar la versión de final de la app antes de lanzarla para usuarios externos.

Cómo compilar un URI para un recurso

Si deseas acceder a un recurso almacenado en un módulo de funciones mediante un URI, consulta la siguiente información para aprender a generar un URI de recurso de módulo de funciones con Uri.Builder():

Kotlin

val uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build()

Java

String uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build().toString();

Cada parte de la ruta de acceso al recurso se construye en el tiempo de ejecución, lo que garantiza que se genere el espacio de nombres correcto después de cargar los APK divididos.

Si deseas un ejemplo de cómo se genera el URI, supongamos que tienes una app y módulos de funciones con estos nombres:

  • Nombre del paquete de apps: com.example.my_app_package
  • Nombre del paquete de recursos de la función: com.example.my_app_package.my_dynamic_feature

Si el resId del fragmento de código anterior hace referencia a un recurso de archivos sin procesar con el nombre "my_video" en tu módulo de funciones, entonces el código de Uri.Builder() debería generar el siguiente resultado:

android.resource://com.example.my_app_package/raw/com.example.my_app_package.my_dynamic_feature:my_video

Tu app puede usar este URI para acceder al recurso del módulo de funciones.

Para validar las rutas de acceso de tu URI, puedes usar el Analizador de APK a fin de inspeccionar el APK del módulo de funciones y determinar el nombre del paquete:

Captura de pantalla del Analizador de APK que inspecciona el contenido de un archivo de recursos compilado.

Figura 2: Usa el Analizador de APK para inspeccionar el nombre del paquete en un archivo de recursos compilado.

Consideraciones para los módulos de funciones

Si deseas publicar una app que incluya módulos de funciones en una pista de producción, ten en cuenta las siguientes consideraciones:

  • Instalar 50 módulos de funciones o más en un solo dispositivo puede generar problemas de rendimiento. Para evitar que esto suceda, considera usar la biblioteca de Play Core a fin de desinstalar los módulos que el usuario ya no necesite.
  • Limita la cantidad de módulos que configures como extraíbles para la entrega en el momento de la instalación a 10 o menos. De lo contrario, podría aumentar el tiempo de descarga y de instalación de tu app.
  • Solo los dispositivos con Android 5.0 (nivel de API 21) y versiones posteriores admiten la descarga y la instalación de funciones a pedido. Para que la función esté disponible en versiones anteriores de Android, asegúrate de habilitar la opción Fusing cuando crees un módulo de función.
  • Asegúrate de habilitar SplitCompat a fin de que la app tenga acceso a los módulos de funciones descargados.
  • Si el tamaño de descarga de la función es grande, la app necesitará obtener la confirmación del usuario antes de poder descargar el módulo de función en un dispositivo.
  • Los módulos de funciones no deben especificar actividades en su manifiesto con android:exported establecido en true. Esto se debe a que no hay garantía de que el dispositivo haya descargado el módulo de funciones cuando otra app intente iniciar la actividad. Además, tu app debe confirmar que se descarga una función antes de intentar acceder a su código y a sus recursos. Para obtener más información, consulta Cómo administrar módulos instalados.
  • Dado que la entrega de funciones de Play requiere que publiques tu app con un paquete de aplicación, asegúrate de tener en cuenta los problemas conocidos del paquete de aplicación.

Recursos adicionales

Si deseas obtener más información para admitir la entrega de funciones en Play, prueba el siguiente recurso.

Ejemplos

Codelabs

  • Tu primer paquete Android App Bundle, un codelab que explora los principios básicos de los archivos Android App Bundle y te muestra cómo comenzar rápidamente a compilar el tuyo con Android Studio. En este codelab, también se analiza cómo probar los paquetes de aplicaciones usando bundletool.
  • Módulos a pedido, que te ayudan a crear una app que descargue y, luego, instale módulos de funciones a pedido.

Entradas de blog

Videos