Con Play Feature Delivery, tu app puede descargar módulos de funciones a pedido en los siguientes dispositivos:
- Smartphones y tablets que ejecuten Android 5.0 (nivel de API 21) y versiones posteriores
- Dispositivos con Chrome OS
Tu app solo necesita llamar a las API en la biblioteca de Play Core para descargar e instalar esos módulos según sea necesario, y Google Play Store solo instala el código y los recursos necesarios para ese módulo en el dispositivo. También puedes usar esta API a fin de descargar módulos a pedido para tus Apps instantáneas Android.
Si quieres obtener más información para agregar módulos de funciones a tu proyecto y configurarlos a fin de que estén disponibles a pedido, lee Cómo crear un módulo de funciones.
Además, después de leer esta guía, consulta la API en acción. Para ello, prueba la app de muestra de la API de Play Core y descubre cómo admitir las actualizaciones en la app.
Por último, antes de publicar tu app, prueba tu paquete de aplicación para verificar que la funcionalidad a pedido se ejecute correctamente.
Cómo incluir la biblioteca de Play Core en tu proyecto
Antes de comenzar, debes importar la biblioteca de Play Core a tu proyecto.
Cómo solicitar un módulo a pedido
Si tu app necesita usar un módulo de funciones, puede solicitar uno mientras está en primer plano mediante la clase SplitInstallManager
. Cuando tu app envía una solicitud, debe especificar el nombre del módulo como lo define el elemento split
en el manifiesto del módulo objetivo. Cuando creas un módulo de funciones con Android Studio, el sistema de compilación usa el nombre del módulo que proporcionas para incorporar esta propiedad en el manifiesto del módulo durante el tiempo de compilación.
Para obtener más información, lee sobre los manifiestos del módulo de funciones.
Por ejemplo, imagina una app que tiene un módulo a pedido para capturar y enviar mensajes con imágenes mediante la cámara del dispositivo y este módulo a pedido tiene split="pictureMessages"
especificado en su manifiesto. En el siguiente ejemplo, se usa SplitInstallManager
a fin de solicitar el módulo de pictureMessages
(además del módulo adicional para algunos filtros promocionales):
Kotlin
// Creates an instance of SplitInstallManager. val splitInstallManager = SplitInstallManagerFactory.create(context) // Creates a request to install a module. val request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build() splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener { sessionId -> ... } .addOnFailureListener { exception -> ... }
Java
// Creates an instance of SplitInstallManager. SplitInstallManager splitInstallManager = SplitInstallManagerFactory.create(context); // Creates a request to install a module. SplitInstallRequest request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build(); splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener(sessionId -> { ... }) .addOnFailureListener(exception -> { ... });
Cuando tu app solicita un módulo a pedido, la biblioteca de Play Core utiliza una estrategia de "activar y olvidar". Es decir, envía la solicitud para descargar el módulo a la plataforma, pero no supervisa si la instalación se realizó correctamente. Para avanzar en el recorrido del usuario después de la instalación o administrar errores correctamente, asegúrate de supervisar el estado de la solicitud.
Nota: Es posible solicitar un módulo de funciones que ya está instalado en el dispositivo. La API considera inmediatamente que se completó la solicitud si detecta que el módulo ya está instalado. Además, después de instalar un módulo, Google Play lo actualiza automáticamente. Es decir, cuando subes una versión nueva de tu paquete de aplicación, la plataforma actualiza todos los APK instalados que pertenecen a tu app. Si deseas obtener más información, consulta Cómo administrar actualizaciones de apps.
A fin de obtener acceso al código y a los recursos del módulo, debes habilitar SplitCompat para tu app. Ten en cuenta que SplitCompat no es necesario para las Apps instantáneas Android.
Cómo posponer la instalación de módulos a pedido
Si no necesitas que tu app descargue e instale inmediatamente un módulo a pedido, puedes postergar la instalación para cuando la app esté en segundo plano. Por ejemplo, si quieres precargar material promocional para un lanzamiento posterior de tu app.
Puedes especificar que un módulo se descargue más adelante mediante el método deferredInstall()
, como se muestra a continuación. Además, a diferencia de SplitInstallManager.startInstall()
, tu app no necesita estar en primer plano para iniciar la solicitud de una instalación postergada.
Kotlin
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(listOf("promotionalFilters"))
Java
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(Arrays.asList("promotionalFilters"));
Las solicitudes de instalaciones postergadas se incluyen en la categoría de mejor esfuerzo y no puedes realizar un seguimiento de su progreso. Por lo tanto, antes de intentar acceder a un módulo que especificaste para la instalación diferida, debes verificar que el módulo se haya instalado. Si necesitas que el módulo esté disponible inmediatamente, usa SplitInstallManager.startInstall()
en su lugar para solicitarlo, como se muestra en la sección anterior.
Cómo supervisar el estado de la solicitud
Para poder actualizar una barra de progreso, activar un intent después de la instalación o manejar correctamente un error de solicitud, debes detectar actualizaciones de estado desde la tarea SplitInstallManager.startInstall()
asíncrona.
Antes de comenzar a recibir actualizaciones para tu solicitud de instalación, registra un objeto de escucha y obtén el ID de sesión de la solicitud, como se muestra a continuación.
Kotlin
// Initializes a variable to later track the session ID for a given request. var mySessionId = 0 // Creates a listener for request status updates. val listener = SplitInstallStateUpdatedListener { state -> if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } } // Registers the listener. splitInstallManager.registerListener(listener) ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener { sessionId -> mySessionId = sessionId } // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener { exception -> // Handle request errors. } // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener)
Java
// Initializes a variable to later track the session ID for a given request. int mySessionId = 0; // Creates a listener for request status updates. SplitInstallStateUpdatedListener listener = state -> { if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } }; // Registers the listener. splitInstallManager.registerListener(listener); ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener(sessionId -> { mySessionId = sessionId; }) // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener(exception -> { // Handle request errors. }); // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener);
Cómo manejar los errores de solicitud
Para manejar correctamente las fallas, descarga o instala un módulo a través de addOnFailureListener()
, como se indica a continuación:
Kotlin
splitInstallManager .startInstall(request) .addOnFailureListener { exception -> when ((exception as SplitInstallException).errorCode) { SplitInstallErrorCode.NETWORK_ERROR -> { // Display a message that requests the user to establish a // network connection. } SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED -> checkForActiveDownloads() ... } } fun checkForActiveDownloads() { splitInstallManager // Returns a SplitInstallSessionState object for each active session as a List. .sessionStates .addOnCompleteListener { task -> if (task.isSuccessful) { // Check for active sessions. for (state in task.result) { if (state.status() == SplitInstallSessionStatus.DOWNLOADING) { // Cancel the request, or request a deferred installation. } } } } }
Java
splitInstallManager .startInstall(request) .addOnFailureListener(exception -> { switch (((SplitInstallException) exception).getErrorCode()) { case SplitInstallErrorCode.NETWORK_ERROR: // Display a message that requests the user to establish a // network connection. break; case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED: checkForActiveDownloads(); ... }); void checkForActiveDownloads() { splitInstallManager // Returns a SplitInstallSessionState object for each active session as a List. .getSessionStates() .addOnCompleteListener( task -> { if (task.isSuccessful()) { // Check for active sessions. for (SplitInstallSessionState state : task.getResult()) { if (state.status() == SplitInstallSessionStatus.DOWNLOADING) { // Cancel the request, or request a deferred installation. } } } }); }
En la siguiente tabla, se describen los estados de error que es posible que tu app deba manejar:
Código de error | Descripción | Acción sugerida |
---|---|---|
ACTIVE_SESSIONS_LIMIT_EXCEEDED | Se rechaza la solicitud porque, actualmente, se está descargando, al menos, una solicitud existente. | Verifica si todavía se están descargando solicitudes, como se muestra en el ejemplo anterior. |
MODULE_UNAVAILABLE | Google Play no encuentra el módulo que se solicitó en función de la versión instalada actualmente de la app, el dispositivo y la cuenta de Google Play del usuario. | Si el usuario no tiene acceso al módulo, debes notificarlo al respecto. |
INVALID_REQUEST | Google Play recibió la solicitud, pero esta no es válida. | Verifica que la información incluida en la solicitud esté completa y sea precisa. |
SESSION_NOT_FOUND | No se encontró ninguna sesión para un ID de sesión determinado. | Si intentas supervisar el estado de una solicitud a partir de su ID de sesión, asegúrate de que este sea correcto. |
API_NOT_AVAILABLE | El dispositivo actual no admite la biblioteca de Play Core. Es decir, el dispositivo no puede descargar ni instalar funciones a pedido. | Para los dispositivos con Android 4.4 (nivel de API 20) o versiones anteriores, debes incluir módulos de funciones en el tiempo de instalación. Para ello, usa la propiedad de manifiesto dist:fusing . Si deseas obtener más información, lee sobre el manifiesto del módulo de funciones.
|
ACCESS_DENIED | La app no puede registrar la solicitud debido a que los permisos no son suficientes. | Por lo general, esto sucede cuando la app está en segundo plano. Intenta ejecutar la solicitud cuando la app vuelva al primer plano. |
NETWORK_ERROR | Falló la solicitud debido a un error de red. | Pídele al usuario que establezca una conexión de red o que se conecte a una diferente. |
INCOMPATIBLE_WITH_EXISTING_SESSION | La solicitud contiene uno o más módulos que ya se solicitaron, pero que todavía no se instalaron. | Crea una solicitud nueva que no incluya módulos que tu app ya solicitó o espera a que todos los módulos solicitados actualmente terminen de instalarse antes de reintentarlo. Ten en cuenta que solicitar un módulo que ya se instaló no soluciona un error. |
SERVICE_DIED | El servicio responsable de manejar la solicitud no está disponible. | Vuelve a intentar ejecutar la solicitud.
Tu |
INSUFFICIENT_STORAGE | El dispositivo no tiene suficiente almacenamiento gratuito para instalar el módulo de funciones. | Notifica al usuario que no tiene almacenamiento suficiente para instalar esta función. |
APP_NOT_OWNED | Google Play no instaló la app y no se puede descargar la función. En la versión 1.9 de Play Core o posterior, este error solo se puede producir para las instalaciones diferidas. | Si quieres que el usuario adquiera la app en Google Play, usa startInstall() , que puede obtener la confirmación de usuario necesaria (versión de Play Core 1.9 o posterior). |
Si un usuario solicita descargar un módulo a pedido y se produce un error, puedes mostrar un diálogo en el que se brinden dos opciones para el usuario: Try again (para volver a realizar la solicitud) y Cancel (para abandonar la solicitud). Para obtener asistencia adicional, también debes proporcionar un vínculo de ayuda que dirija a los usuarios al Centro de ayuda de Google Play.
Cómo manejar las actualizaciones de estado
Después de registrar un objeto de escucha y grabar el ID de sesión de tu solicitud, usa StateUpdatedListener.onStateUpdate()
a fin de manejar los cambios de estado, como se muestra a continuación.
Kotlin
override fun onStateUpdate(state : SplitInstallSessionState) { if (state.status() == SplitInstallSessionStatus.FAILED && state.errorCode() == SplitInstallErrorCode.SERVICE_DIED) { // Retry the request. return } if (state.sessionId() == mySessionId) { when (state.status()) { SplitInstallSessionStatus.DOWNLOADING -> { val totalBytes = state.totalBytesToDownload() val progress = state.bytesDownloaded() // Update progress bar. } SplitInstallSessionStatus.INSTALLED -> { // After a module is installed, you can start accessing its content or // fire an intent to start an activity in the installed module. // For other use cases, see access code and resources from installed modules. // If the request is an on demand module for an Android Instant App // running on Android 8.0 (API level 26) or higher, you need to // update the app context using the SplitInstallHelper API. } } } }
Java
@Override public void onStateUpdate(SplitInstallSessionState state) { if (state.status() == SplitInstallSessionStatus.FAILED && state.errorCode() == SplitInstallErrorCode.SERVICE_DIES) { // Retry the request. return; } if (state.sessionId() == mySessionId) { switch (state.status()) { case SplitInstallSessionStatus.DOWNLOADING: int totalBytes = state.totalBytesToDownload(); int progress = state.bytesDownloaded(); // Update progress bar. break; case SplitInstallSessionStatus.INSTALLED: // After a module is installed, you can start accessing its content or // fire an intent to start an activity in the installed module. // For other use cases, see access code and resources from installed modules. // If the request is an on demand module for an Android Instant App // running on Android 8.0 (API level 26) or higher, you need to // update the app context using the SplitInstallHelper API. } } }
Los posibles estados de tu solicitud de instalación se describen en la siguiente tabla.
Estado de solicitud | Descripción | Acción sugerida |
---|---|---|
PENDIENTE | Se aceptó la solicitud y la descarga debería comenzar pronto. | Inicializa los componentes de IU, como una barra de progreso, para brindar los comentarios del usuario sobre la descarga. |
REQUIRES_USER_CONFIRMATION | La descarga requiere la confirmación del usuario. Generalmente, este estado ocurre si la app no se instaló a través de Google Play. | Pídele al usuario que confirme la descarga de la función mediante GooglebPlay. Si deseas conocer más detalles, ve a la sección sobre cómo obtener información del usuario. |
DOWNLOADING | La descarga está en curso. | Si agregas una barra de progreso para la descarga, usa los métodos SplitInstallSessionState.bytesDownloaded() y SplitInstallSessionState.totalBytesToDownload() a fin de actualizar la IU (consulta la muestra de código ubicada arriba de esta tabla). |
DOWNLOADED | El dispositivo descargó el módulo, pero la instalación todavía no comenzó. | Las apps deberían habilitar SplitCompat para tener acceso a los módulos descargados y evitar ver este estado. Esto es necesario para acceder al código y a los recursos del módulo de funciones. |
INSTALANDO | El dispositivo está instalando el módulo. | Actualiza la barra de progreso. Por lo general, este estado es corto. |
INSTALLED | Se instaló el módulo en el dispositivo. | Accede al código y a los recursos en el módulo para continuar el recorrido del usuario. Si el módulo es para una App instantánea Android que ejecuta Android 8.0 (nivel de API 26) o versiones posteriores, usa |
ERROR | Falló la solicitud antes de que se pudiera instalar el módulo en el dispositivo. | Pídele al usuario que vuelva a enviar la solicitud o que la cancele. |
CANCELING | El dispositivo está en proceso de cancelar la solicitud. | Para obtener más información, ve a la sección sobre cómo cancelar una solicitud de instalación. |
CANCELED | Se canceló la solicitud. |
Cómo obtener la confirmación del usuario
En algunos casos, es posible que Google Play requiera la confirmación del usuario antes de completar una solicitud de descarga. Por ejemplo, si Google Play no instaló tu app. En estos casos, el estado de la solicitud informa REQUIRES_USER_CONFIRMATION
y tu app necesita obtener la confirmación del usuario para que el dispositivo pueda descargar y también instalar los módulos en la solicitud. Para obtener la confirmación, tu app debe pedirle al usuario lo siguiente:
Kotlin
override fun onSessionStateUpdate(state: SplitInstallSessionState) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, /* activity = */ this, // You use this request code to later retrieve the user's decision. /* requestCode = */ MY_REQUEST_CODE) } ... }
Java
@Override void onSessionStateUpdate(SplitInstallSessionState state) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, /* activity = */ this, // You use this request code to later retrieve the user's decision. /* requestCode = */ MY_REQUEST_CODE); } ... }
El estado de la solicitud se actualiza según la respuesta del usuario:
- Si el usuario acepta la confirmación, el estado de la solicitud cambia a
PENDING
y la descarga continúa. - Si el usuario rechaza la confirmación, el estado de la solicitud cambia a
CANCELED
. - Si el usuario no hace una selección antes de que se destruya el diálogo, el estado de la solicitud permanece como
REQUIRES_USER_CONFIRMATION
. Tu app puede volver a pedirle al usuario que complete la solicitud.
Para recibir una devolución de llamada con la respuesta del usuario, utiliza onActivityResult()
, como se muestra a continuación.
Kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == MY_REQUEST_CODE) { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } }
Java
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == MY_REQUEST_CODE) { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } }
Cómo cancelar una solicitud de instalación
Si tu app necesita cancelar una solicitud antes de que se instale, puede invocar el método cancelInstall()
mediante el ID de sesión de la solicitud, como se muestra a continuación.
Kotlin
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId)
Java
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId);
Cómo acceder a los módulos
Para acceder al código y los recursos de un módulo descargado después de la descarga, tu app debe habilitar la biblioteca de SplitCompat para tu app y cada actividad en los módulos de funciones que descarga tu app.
Sin embargo, ten en cuenta que la plataforma cuenta con las siguientes restricciones para acceder al contenido de un módulo durante un tiempo (días, en algunos casos) después de descargar el módulo:
- La plataforma no puede aplicar ninguna entrada nueva del manifiesto que ingrese el módulo.
- La plataforma no puede acceder a los recursos del módulo para los componentes de la IU del sistema, como las notificaciones. Si necesitas usar esos recursos inmediatamente, puedes incluirlos en el módulo de base de tu app.
Habilita SplitCompat
Si quieres que tu app acceda al código y los recursos de un módulo descargado, debes habilitar SplitCompat mediante solo uno de los métodos que se describen en las siguientes secciones.
Después de habilitar SplitCompat en tu app, también debes habilitar SplitCompat para cada actividad en los módulos de funciones a los que quieres que tu app tenga acceso.
Cómo declarar SplitCompatApplication en el manifiesto
La manera más simple de habilitar SplitCompat consiste en declarar SplitCompatApplication
como la subclase de Application
en el manifiesto de tu app, como se muestra a continuación:
<application
...
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>
Después de instalar la app en un dispositivo, puedes acceder automáticamente al código y los recursos de los módulos de funciones descargados.
Cómo invocar SplitCompat durante el tiempo de ejecución
También puedes habilitar SplitCompat en actividades o servicios específicos durante el tiempo de ejecución.
Es necesario habilitar SplitCompat de esta manera para iniciar las actividades incluidas en los módulos de funciones. Para ello, anula attachBaseContext
como se muestra a continuación.
Si tienes una clase Application personalizada, haz que extienda SplitCompatApplication
a fin de habilitar SplitCompat para tu app, como se muestra a continuación:
Kotlin
class MyApplication : SplitCompatApplication() { ... }
Java
public class MyApplication extends SplitCompatApplication { ... }
SplitCompatApplication
simplemente anula ContextWrapper.attachBaseContext()
para incluir SplitCompat.install(Context applicationContext)
. Si no deseas que tu clase Application
extienda SplitCompatApplication
, puedes anular el método attachBaseContext()
de forma manual, como se muestra a continuación:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this); }
Si tu módulo a pedido es compatible con las apps instantáneas y las apps instaladas, puedes invocar SplitCompat de manera condicional, como se muestra a continuación:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this) } }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this); } }
Cómo habilitar SplitCompat para las actividades del módulo
Después de habilitar SplitCompat para tu app de base, debes habilitar SplitCompat en cada actividad que tu app descargue en un módulo de funciones. Para ello, usa el método SplitCompat.installActivity()
de la siguiente manera:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this); }
Cómo acceder al código y a los recursos desde los módulos instalados
Siempre que habilites SplitCompat para el contexto de tu aplicación de base y las actividades en tu módulo de funciones, después de que una solicitud de un módulo a pedido informe INSTALLED
, puedes comenzar a usar su código y sus recursos como si fuesen parte del APK de base.
Si deseas acceder a elementos o recursos que existen en el módulo recién instalado desde un módulo instalado diferente de tu app, debes hacerlo mediante el contexto de la aplicación. El contexto del componente que intenta acceder a los recursos todavía no estará actualizado. Como alternativa, puedes volver a crear ese componente o instalar SplitCompat por encima después de la instalación del módulo de funciones.
Además, no almacenes en caché los objetos ApplicationInfo
de Android, su contenido o sus objetos que los incluyan dentro de tu app. Siempre debes obtener estos objetos desde el contexto de una app, según sea necesario. Si almacenas esos objetos en caché, podrías provocar que la app falle cuando instale una versión dividida o versiones más recientes de Android.
Cómo acceder a Apps instantáneas Android instaladas
Después de que se informe un módulo de App instantánea Android como INSTALLED
, puedes acceder a su código y sus recursos mediante el contexto actualizado de una app. Un contexto que tu app crea antes de instalar un módulo (por ejemplo, uno que ya está instalado en una variable) no incluye el contenido del módulo nuevo. Sin embargo, un contexto actualizado sí lo incluye y lo puedes obtener, por ejemplo, mediante createPackageContext
.
Kotlin
// Generate a new context as soon as a request for a new module // reports as INSTALLED. override fun onStateUpdate(state: SplitInstallSessionState ) { if (state.sessionId() == mySessionId) { when (state.status()) { ... SplitInstallSessionStatus.INSTALLED -> { val newContext = context.createPackageContext(context.packageName, 0) // If you use AssetManager to access your app’s raw asset files, you’ll need // to generate a new AssetManager instance from the updated context. val am = newContext.assets } } } }
Java
// Generate a new context as soon as a request for a new module // reports as INSTALLED. @Override public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { ... case SplitInstallSessionStatus.INSTALLED: Context newContext = context.createPackageContext(context.getPackageName(), 0); // If you use AssetManager to access your app’s raw asset files, you’ll need // to generate a new AssetManager instance from the updated context. AssetManager am = newContext.getAssets(); } } }
Apps instantáneas Android en Android 8.0 y versiones posteriores
Cuando solicitas un módulo a pedido para una App instantánea Android en Android 8.0 (nivel de API 26) y versiones posteriores, después de que una solicitud de instalación se informa como INSTALLED
, debes actualizar la app con el contexto de módulo nuevo a través de una llamada a SplitInstallHelper.updateAppInfo(Context context)
.
De lo contrario, la app no está al tanto del código y los recursos del módulo. Después de actualizar los metadatos de la app, debes cargar el contenido del módulo durante el próximo evento de subproceso principal. Para ello, invoca un Handler
nuevo, como se indica a continuación:
Kotlin
override fun onStateUpdate(state: SplitInstallSessionState ) { if (state.sessionId() == mySessionId) { when (state.status()) { ... SplitInstallSessionStatus.INSTALLED -> { // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context) Handler().post { // Loads contents from the module using AssetManager val am = context.assets ... } } } } } }
Java
@Override public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { ... case SplitInstallSessionStatus.INSTALLED: // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context); new Handler().post(new Runnable() { @Override public void run() { // Loads contents from the module using AssetManager AssetManager am = context.getAssets(); ... } }); } } } }
Cómo cargar bibliotecas C/C++
Si quieres cargar bibliotecas C/C++ desde un módulo que el dispositivo ya descargó en una app instantánea, usa SplitInstallHelper.loadLibrary(Context context, String libName)
, como se muestra a continuación:
Kotlin
override fun onStateUpdate(state: SplitInstallSessionState) { if (state.sessionId() == mySessionId) { when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Updates the app’s context as soon as a module is installed. val newContext = context.createPackageContext(context.packageName, 0) // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”) ... } } } }
Java
public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Updates the app’s context as soon as a module is installed. Context newContext = context.createPackageContext(context.getPackageName(), 0); // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”); ... } } }
Cómo administrar módulos instalados
Para verificar qué módulos de funciones están instalados actualmente en el dispositivo, puedes llamar a SplitInstallManager.getInstalledModules()
, que muestra un Set<String>
de los nombres de los módulos instalados, como se muestra a continuación.
Kotlin
val installedModules: Set<String> = splitInstallManager.installedModules
Java
Set<String> installedModules = splitInstallManager.getInstalledModules();
Cómo desinstalar módulos
Puedes pedirle al dispositivo que desinstale módulos. Para ello, invoca SplitInstallManager.deferredUninstall(List<String> moduleNames)
, como se muestra a continuación.
Kotlin
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(listOf("pictureMessages", "promotionalFilters"))
Java
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));
Las desinstalaciones del módulo no se realizan inmediatamente. Es decir, el dispositivo los desinstala en el segundo plano según sea necesario para ahorrar espacio de almacenamiento.
Para confirmar que el dispositivo haya quitado un módulo, invoca SplitInstallManager.getInstalledModules()
y también inspecciona el resultado, como se describe en la sección anterior.
Cómo descargar recursos de idiomas adicionales
Con los paquetes de aplicaciones, los dispositivos solo descargan el código y los recursos necesarios a fin de ejecutar tu app. Por lo tanto, para los recursos de idioma, el dispositivo de un usuario solo descarga los recursos de idioma de tu app que coinciden con uno o más idiomas seleccionados actualmente en la configuración del dispositivo.
Si quieres que tu app tenga acceso a recursos de idiomas adicionales, por ejemplo, para implementar un selector de idiomas en la app, puedes usar la biblioteca de Play Core a fin de descargarlos a pedido. El proceso es similar al de descargar un módulo de funciones, como se muestra a continuación.
Kotlin
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply() ... // Creates a request to download and install additional language resources. val request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build() // Submits the request to install the additional language resources. splitInstallManager.startInstall(request)
Java
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply(); ... // Creates a request to download and install additional language resources. SplitInstallRequest request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build(); // Submits the request to install the additional language resources. splitInstallManager.startInstall(request);
La solicitud se maneja como si fuese una solicitud de un módulo de funciones. Es decir, puedes supervisar el estado de la solicitud como lo harías normalmente.
Si tu app no requiere los recursos de idiomas adicionales inmediatamente, puedes postergar la instalación de la app para cuando esté en el segundo plano, como se muestra a continuación.
Kotlin
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
Cómo acceder a los recursos de idiomas descargados
Para obtener acceso a los recursos de idiomas descargados, tu app necesita ejecutar el método SplitCompat.installActivity()
dentro del método attachBaseContext()
de cada actividad que requiera acceso a esos recursos, como se muestra a continuación.
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); SplitCompat.installActivity(this); }
Para cada actividad en la que quieres usar recursos de idiomas que descargó tu app, actualiza el contexto de la base y define una configuración regional nueva a través de su Configuration
:
Kotlin
override fun attachBaseContext(base: Context) { val configuration = Configuration() configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) val context = base.createConfigurationContext(configuration) super.attachBaseContext(context) SplitCompat.install(this) }
Java
@Override protected void attachBaseContext(Context base) { Configuration configuration = new Configuration(); configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))); Context context = base.createConfigurationContext(configuration); super.attachBaseContext(context); SplitCompat.install(this); }
Para que estos cambios surtan efecto, tienes que volver a crear tu actividad después de que un idioma nuevo se instale y esté listo para usar. Puedes usar el método Activity#recreate()
.
Kotlin
when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Recreates the activity to load resources for the new language // preference. activity.recreate() } ... }
Java
switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Recreates the activity to load resources for the new language // preference. activity.recreate(); ... }
Cómo desinstalar recursos de idiomas adicionales
Del mismo modo que los módulos de funciones, puedes desinstalar recursos adicionales en cualquier momento. Antes de solicitar una desinstalación, determina qué idiomas están instalados actualmente, de la siguiente manera.
Kotlin
val installedLanguages: Set<String> = splitInstallManager.installedLanguages
Java
Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();
Luego, puedes decidir qué idiomas desinstalar con el método deferredLanguageUninstall()
, como se muestra a continuación.
Kotlin
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
Recursos adicionales
Si deseas obtener más información para usar la biblioteca de Play Core, prueba los siguientes recursos.
Ejemplos
- Ejemplo de la API de PlayCore, que demuestra el uso de la API de PlayCore para solicitar y descargar funciones a pedido
- Ejemplo de carga de código dinámico, que muestra tres enfoques diferentes para acceder de forma segura al código desde un módulo de funciones instalado
Codelabs
- Módulos a pedido, que sirven de ayuda para crear una app que descarga y también instala funciones a pedido
Entradas de blog
- Nuevas funciones que ayudan a desarrollar, lanzar y expandir tu empresa en Google Play
- Últimas actualizaciones de Android App Bundle, incluida la API de idiomas adicionales