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

Play Feature Delivery

Con Play Feature Delivery, tu app puede descargar módulos de funciones a pedido en los dispositivos con Android 5.0 (nivel de API 21) y versiones posteriores. 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.

A fin de obtener más información sobre cómo agregar módulos de funciones a tu proyecto y configurarlos para que estén disponibles a pedido, lee Crea 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 obtén información sobre 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

Cuando 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.

Este código de error se expone como una actualización a tu SplitInstallStateUpdatedListener con el estado FAILED y el ID de sesión -1.

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_DIES) {
       // 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. Lo más probable es que se deba al tamaño de la descarga, que supera los 10 MB. Pídele al usuario que acepte la solicitud de descarga. Si deseas obtener más información, 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 splitInstallHelper a fin de actualizar los componentes de la app con el módulo nuevo.

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 una solicitud requiere una descarga de gran tamaño y el dispositivo usa datos móviles. 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 dialog for the user to either “Download”
        // or “Cancel” 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 dialog for the user to either “Download”
        // or “Cancel” 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 selecciona "Download", el estado de la solicitud cambia a PENDING y la descarga continúa.
  • Si el usuario selecciona "Cancel", 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 sobre cómo usar la biblioteca de Play Core, prueba los siguientes recursos.

Ejemplos

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

Videos