Mantener tu app actualizada en los dispositivos de los usuarios permite que prueben nuevas funciones y aprovechen las mejoras de rendimiento y las correcciones de errores. Aunque algunos usuarios habilitan las actualizaciones en segundo plano para cuando su dispositivo tiene una conexión no medida, es posible que otros necesiten recibir recordatorios de las actualizaciones disponibles. Las actualizaciones dentro de la app son una función de la biblioteca de Play Core que presenta un nuevo flujo de solicitudes para pedir a los usuarios activos que actualicen tu app.
Las actualizaciones dentro de la app solo funcionan con dispositivos que ejecutan Android 5.0 (nivel de API 21) o versiones posteriores y requieren que uses la biblioteca de Play Core 1.5.0 o versiones posteriores. Además, esas actualizaciones admiten apps que se ejecutan solo en dispositivos móviles y tablets Android, así como en dispositivos con el Sistema operativo Chrome.
Si se cumplen esos requisitos, tu app puede admitir la siguiente UX para actualizaciones dentro de la app:
Flexible: una experiencia del usuario que proporciona descargas e instalaciones en segundo plano con supervisión fluida del estado. Esta UX resulta apropiada cuando es aceptable que el usuario utilice la app mientras descarga la actualización. Por ejemplo, deseas instar a los usuarios a que prueben una nueva función que no es imprescindible para la funcionalidad principal de tu app.
Figura 1: Ejemplo de un flujo de actualización flexible
Inmediata: una experiencia del usuario en pantalla completa que requiere que el usuario actualice y reinicie la app para poder seguir usándola. Esta UX es ideal en los casos en que la actualización es crítica para continuar utilizando la app. Después de que el usuario acepta la actualización inmediata, Google Play se encarga de instalar la actualización y reiniciar la app.
Figura 2: Ejemplo de un flujo de actualización inmediata
En esta página, se muestra cómo usar la biblioteca de Play Core para solicitar y realizar una actualización flexible o inmediata dentro de la app.
Cómo comprobar la disponibilidad de actualizaciones
Antes de solicitar una actualización, primero debes comprobar si hay una disponible para tu app usando AppUpdateManager
, como se muestra a continuación:
Kotlin
// Creates instance of the manager. val appUpdateManager = AppUpdateManagerFactory.create(context) // Returns an intent object that you use to check for an update. val appUpdateInfoTask = appUpdateManager.appUpdateInfo // Checks that the platform will allow the specified type of update. appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE // For a flexible update, use AppUpdateType.FLEXIBLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) ) { // Request the update. } }
Java
// Creates instance of the manager. AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context); // Returns an intent object that you use to check for an update. Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo(); // Checks that the platform will allow the specified type of update. appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> { if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE // For a flexible update, use AppUpdateType.FLEXIBLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) { // Request the update. } });
El resultado contiene el estado de disponibilidad de la actualización. Si hay una actualización disponible y está permitida, la AppUpdateInfo
que se muestra también contiene un intent para iniciar la actualización. Consulta la siguiente sección para saber cómo iniciar la actualización.
Si ya hay una actualización en curso dentro de la app, el resultado también informará el estado de esa actualización.
Cómo verificar la obsolescencia de las actualizaciones
Además de comprobar si hay actualizaciones disponibles, te recomendamos que verifiques cuánto tiempo pasó desde que el usuario recibió una notificación sobre una actualización a través de Google Play Store. Esto, por ejemplo, puede ayudarte a decidir si tu app debe iniciar una actualización flexible o inmediata. Es decir, podrías esperar unos días antes de notificar al usuario sobre una actualización flexible y algunos días más para requerir que realice una actualización inmediata.
Para verificar la cantidad de días que transcurrieron desde que Google Play Store tuvo conocimiento de una actualización, usa clientVersionStalenessDays()
, como se muestra a continuación:
Kotlin
// Creates instance of the manager. val appUpdateManager = AppUpdateManagerFactory.create(context) // Returns an intent object that you use to check for an update. val appUpdateInfoTask = appUpdateManager.appUpdateInfo // Checks whether the platform allows the specified type of update, // and current version staleness. appUpdateInfoTask.addOnSuccessListener { if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.clientVersionStalenessDays() != null && appUpdateInfo.clientVersionStalenessDays() >= DAYS_FOR_FLEXIBLE_UPDATE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) { // Request the update. }
Java
// Creates instance of the manager. AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context); // Returns an intent object that you use to check for an update. Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo(); // Checks whether the platform allows the specified type of update, // and current version staleness. appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> { if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.clientVersionStalenessDays() != null && appUpdateInfo.clientVersionStalenessDays() >= DAYS_FOR_FLEXIBLE_UPDATE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) { // Request the update. } });
Cómo verificar la prioridad de las actualizaciones
La API de Google Play Developer te permite establecer la prioridad de cada actualización. De esta manera, tu app puede determinar la insistencia con la que recomendará una actualización al usuario. Por ejemplo, considera la siguiente estrategia para establecer la prioridad de las actualizaciones:
- Mejoras menores en la IU: actualización de baja prioridad. No solicites una actualización flexible ni una inmediata.
- Mejoras en el rendimiento: actualización de prioridad media. Solicita una actualización flexible.
- Actualización crítica de seguridad: actualización de prioridad alta. Requiere una actualización inmediata.
Para determinar la prioridad, Google Play usa un valor entero entre 0 y 5, en el que 0 es la prioridad predeterminada y 5 es la más alta. A fin de establecer la prioridad para una actualización, usa el campo inAppUpdatePriority
en Edits.tracks.releases
en la API de Google Play Developer. Se considerará que todas las versiones agregadas recientemente en el lanzamiento tendrán la prioridad establecida en este último. Solo se puede establecer la prioridad al momento de lanzar una versión nueva; no se puede cambiar más tarde.
Para establecer la prioridad con la API de Google Play Developer, puedes crear un flujo de trabajo de Edits, subir los APK o paquetes nuevos, asignarlos a una pista y confirmar la edición como se describe en la documentación de la API de Play Developer.
La prioridad de la actualización integrada en la app debe especificarse en el Edits.tracks resource
que se pasa en el método Edits.tracks: update
. Por ejemplo, para lanzar un APK con código de versión 88, con inAppUpdatePriority
5:
{ "releases": [{ "versionCodes": ["88"], "inAppUpdatePriority": 5, "status": "completed" }] }
En el código de tu app, puedes verificar el nivel de prioridad de una actualización determinada usando updatePriority()
, como se muestra a continuación:
Kotlin
// Creates instance of the manager. val appUpdateManager = AppUpdateManagerFactory.create(context) // Returns an intent object that you use to check for an update. val appUpdateInfoTask = appUpdateManager.appUpdateInfo // Checks whether the platform allows the specified type of update, // and checks the update priority. appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.updatePriority() >= HIGH_PRIORITY_UPDATE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) { // Request an immediate update. }
Java
// Creates instance of the manager. AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context); // Returns an intent object that you use to check for an update. Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo(); // Checks whether the platform allows the specified type of update, // and checks the update priority. appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> { if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.updatePriority() >= HIGH_PRIORITY_UPDATE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) { // Request an immediate update. } });
Cómo iniciar una actualización
Después de verificar que es posible actualizar la app, puedes solicitar la actualización usando AppUpdateManager.startUpdateFlowForResult()
, como se muestra. Sin embargo, para evitar que los usuarios se cansen o se molesten, debes tener en cuenta la frecuencia con la que solicitas actualizaciones. Es decir, debes limitar la solicitud de actualizaciones dentro de la app solo a los cambios que son importantes para la funcionalidad de la app.
Kotlin
appUpdateManager.startUpdateFlowForResult( // Pass the intent that is returned by 'getAppUpdateInfo()'. appUpdateInfo, // Or 'AppUpdateType.FLEXIBLE' for flexible updates. AppUpdateType.IMMEDIATE, // The current activity making the update request. this, // Include a request code to later monitor this update request. MY_REQUEST_CODE)
Java
appUpdateManager.startUpdateFlowForResult( // Pass the intent that is returned by 'getAppUpdateInfo()'. appUpdateInfo, // Or 'AppUpdateType.FLEXIBLE' for flexible updates. AppUpdateType.IMMEDIATE, // The current activity making the update request. this, // Include a request code to later monitor this update request. MY_REQUEST_CODE);
Cada instancia de AppUpdateInfo
se puede usar para iniciar una actualización solo una vez.
Para volver a intentar realizar la actualización en caso de error, debes solicitar otra AppUpdateInfo
y verificar nuevamente que la actualización esté disponible y se permita.
El tipo de actualización que solicitas determina los próximos pasos que deberás realizar. Para obtener más información, consulta las secciones Cómo manejar una actualización inmediata o Cómo manejar una actualización flexible.
Cómo obtener una devolución de llamada sobre el estado de la actualización
Después de iniciar una actualización, puedes usar una devolución de llamada onActivityResult()
a fin de manejar un error o una cancelación de la actualización, como se muestra.
Kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { if (requestCode == MY_REQUEST_CODE) { if (resultCode != RESULT_OK) { log("Update flow failed! Result code: $resultCode") // If the update is cancelled or fails, // you can request to start the update again. } } }
Java
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == MY_REQUEST_CODE) { if (resultCode != RESULT_OK) { log("Update flow failed! Result code: " + resultCode); // If the update is cancelled or fails, // you can request to start the update again. } } }
A continuación, se describen los diferentes valores que puedes recibir de la devolución de llamada onActivityResult()
:
RESULT_OK
: el usuario aceptó la actualización. En el caso de las actualizaciones inmediatas, es posible que no recibas esta devolución de llamada porque probablemente Google Play ya habrá completado la actualización para cuando tu app recupere el control.RESULT_CANCELED
: el usuario rechazó o canceló la actualización.ActivityResult.RESULT_IN_APP_UPDATE_FAILED
: otro error impidió que el usuario proporcionara el consentimiento o que la actualización procediera.
Cómo manejar una actualización flexible
Cuando inicias una actualización flexible, el usuario primero ve un diálogo en el que se solicita su consentimiento. Si el usuario otorga consentimiento, la descarga comienza en segundo plano, y el usuario puede seguir interactuando con la app. En esta sección, se describe cómo supervisar y completar una actualización flexible dentro de la app.
Cómo supervisar el estado de una actualización flexible
Cuando un usuario acepta una actualización flexible, Google Play comienza a descargar la actualización en segundo plano. Una vez que empieza la descarga, tu app necesita supervisar el estado de la actualización para saber cuándo se puede instalar la actualización y mostrar el progreso en la IU de tu app.
Puedes supervisar el estado de una actualización en curso registrando un objeto de escucha para instalar actualizaciones de estado. También puedes proporcionar una barra de progreso en la IU de la app a los efectos de informar a los usuarios qué tan avanzada se encuentra la descarga.
Kotlin
// Create a listener to track request state updates. val listener = { state -> // (Optional) Provide a download progress bar. if (state.installStatus() == InstallStatus.DOWNLOADING) { val bytesDownloaded = state.bytesDownloaded() val totalBytesToDownload = state.totalBytesToDownload() // Show update progress bar. } // Log state or install the update. } // Before starting an update, register a listener for updates. appUpdateManager.registerListener(listener) // Start an update. // When status updates are no longer needed, unregister the listener. appUpdateManager.unregisterListener(listener)
Java
// Create a listener to track request state updates. InstallStateUpdatedListener listener = state -> { // (Optional) Provide a download progress bar. if (state.installStatus() == InstallStatus.DOWNLOADING) { long bytesDownloaded = state.bytesDownloaded(); long totalBytesToDownload = state.totalBytesToDownload(); // Implement progress bar. } // Log state or install the update. }; // Before starting an update, register a listener for updates. appUpdateManager.registerListener(listener); // Start an update. // When status updates are no longer needed, unregister the listener. appUpdateManager.unregisterListener(listener);
Cómo instalar una actualización flexible
Si supervisas el estado de la actualización flexible y detectas el estado InstallStatus.DOWNLOADED
, debes reiniciar la app para instalar la actualización.
A diferencia de lo que ocurre con las actualizaciones inmediatas, en este caso Google Play no activa el reinicio de una app. Eso se debe a que, durante una actualización flexible, el usuario tiene la expectativa de seguir usando la aplicación hasta que decida que desea instalar la actualización.
Por lo tanto, te recomendamos que proporciones una notificación (o alguna otra indicación de la IU) para informar al usuario que finalizó la instalación y solicitar su confirmación antes de reiniciar la app.
Por ejemplo, puedes implementar una barra de notificaciones con Material Design a fin de solicitar la confirmación del usuario antes de reiniciar la app, como se muestra en la figura 1.
En el siguiente ejemplo de código, se muestra una notificación de la barra de notificaciones que ve el usuario tras la descarga de una actualización flexible.
Kotlin
override fun onStateUpdate(state: InstallState) { if (state.installStatus() == InstallStatus.DOWNLOADED) { // After the update is downloaded, show a notification // and request user confirmation to restart the app. popupSnackbarForCompleteUpdate() } ... } /* Displays the snackbar notification and call to action. */ fun popupSnackbarForCompleteUpdate() { Snackbar.make( findViewById(R.id.activity_main_layout), "An update has just been downloaded.", Snackbar.LENGTH_INDEFINITE ).apply { setAction("RESTART") { appUpdateManager.completeUpdate() } setActionTextColor(resources.getColor(R.color.snackbar_action_text_color)) show() } }
Java
@Override public void onStateUpdate(InstallState state) { if (state.installStatus() == InstallStatus.DOWNLOADED) { // After the update is downloaded, show a notification // and request user confirmation to restart the app. popupSnackbarForCompleteUpdate(); } ... } /* Displays the snackbar notification and call to action. */ private void popupSnackbarForCompleteUpdate() { Snackbar snackbar = Snackbar.make( findViewById(R.id.activity_main_layout), "An update has just been downloaded.", Snackbar.LENGTH_INDEFINITE); snackbar.setAction("RESTART", view -> appUpdateManager.completeUpdate()); snackbar.setActionTextColor( getResources().getColor(R.color.snackbar_action_text_color)); snackbar.show(); }
Cuando llamas a appUpdateManager.completeUpdate()
en primer plano, la plataforma muestra una IU en pantalla completa que reinicia la app en segundo plano. Una vez que la plataforma instala la actualización, la app se reinicia en su actividad principal.
Si, en cambio, llamas a appUpdateManager.completeUpdate()
cuando la app está en segundo plano, la actualización se instala de manera silenciosa sin ocultar la IU del dispositivo.
Cuando el usuario lleva tu app al primer plano, es recomendable que verifiques que la aplicación no tenga una actualización pendiente. Si tu app tiene una actualización en el estado DOWNLOADED
, muestra la notificación para solicitar que el usuario la instale, como se muestra. De lo contrario, los datos de la actualización seguirán ocupando el almacenamiento del dispositivo del usuario.
Kotlin
// Checks that the update is not stalled during 'onResume()'. // However, you should execute this check at all app entry points. override fun onResume() { super.onResume() appUpdateManager .appUpdateInfo .addOnSuccessListener { appUpdateInfo -> ... // If the update is downloaded but not installed, // notify the user to complete the update. if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) { popupSnackbarForCompleteUpdate() } } }
Java
// Checks that the update is not stalled during 'onResume()'. // However, you should execute this check at all app entry points. @Override protected void onResume() { super.onResume(); appUpdateManager .getAppUpdateInfo() .addOnSuccessListener(appUpdateInfo -> { ... // If the update is downloaded but not installed, // notify the user to complete the update. if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) { popupSnackbarForCompleteUpdate(); } }); }
Cómo manejar una actualización inmediata
Si realizas una actualización inmediata y el usuario da su consentimiento para instalarla, Google Play mostrará el progreso durante toda la actualización en la parte superior de la IU de tu app. Durante este proceso, si el usuario cierra la app, la actualización debería continuar descargándose e instalándose en segundo plano sin que se requiera una nueva confirmación del usuario.
Sin embargo, cuando tu app regrese al primer plano, deberás confirmar que la actualización no está detenida en el estado UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
. Si la actualización se detiene en ese estado, reanúdala, como se muestra a continuación:
Kotlin
// Checks that the update is not stalled during 'onResume()'. // However, you should execute this check at all entry points into the app. override fun onResume() { super.onResume() appUpdateManager .appUpdateInfo .addOnSuccessListener { appUpdateInfo -> ... if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS ) { // If an in-app update is already running, resume the update. appUpdateManager.startUpdateFlowForResult( appUpdateInfo, IMMEDIATE, this, MY_REQUEST_CODE ); } } }
Java
// Checks that the update is not stalled during 'onResume()'. // However, you should execute this check at all entry points into the app. @Override protected void onResume() { super.onResume(); appUpdateManager .getAppUpdateInfo() .addOnSuccessListener( appUpdateInfo -> { ... if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) { // If an in-app update is already running, resume the update. appUpdateManager.startUpdateFlowForResult( appUpdateInfo, IMMEDIATE, this, MY_REQUEST_CODE); } }); }
Tu app debería poder procesar casos en los que un usuario rechaza la actualización o cancela la descarga. Cuando el usuario realiza cualquiera de estas acciones, se cierra la IU de Google Play, y tu app debería determinar la mejor manera de proceder.
Si es posible, procura permitir que el usuario continúe sin la actualización y, más tarde, pídele que la realice para que se vuelva a iniciar el flujo de actualización. Si tu app no funciona sin la actualización, procura mostrar un mensaje informativo antes de reiniciar el flujo de actualización, de pedirle al usuario que cierre la app o de que la app se cierre por sí sola. De esta manera, el usuario entiende que puede reiniciar tu app cuando esté listo para descargar la actualización.
Cómo realizar pruebas con el uso compartido interno de apps
Con el uso compartido interno de apps, puedes compartir rápidamente un paquete de aplicación o APK con tu equipo interno y tus verificadores subiendo el paquete de aplicación que deseas probar a Play Console.
También puedes utilizar el uso compartido interno de apps para probar las actualizaciones dentro de la app de la siguiente manera:
- En tu dispositivo de prueba, asegúrate de haber instalado una versión de tu app que cumpla con los siguientes requisitos:
- La app se instaló mediante una URL de uso compartido interno de apps.
- Admite actualizaciones dentro de la app.
- Utiliza un código de versión inferior al de la versión actualizada de tu app.
- Sigue las instrucciones de Play Console para compartir tu app internamente. Asegúrate de subir una versión de tu app que use un código de versión superior al que ya instalaste en el dispositivo de prueba.
- En el dispositivo de prueba, solo haz clic en el vínculo de uso compartido interno de apps para la versión actualizada de tu app. No instales la app de la página de Google Play Store que ves después de hacer clic en el vínculo.
- Abre la app desde la pantalla principal del dispositivo o desde su panel de apps. La actualización debería estar disponible para tu app, y deberías poder probar tu implementación de actualizaciones dentro de la app.
Cómo solucionar problemas
En esta sección, se describen algunas posibles soluciones para casos en que las actualizaciones dentro de la app pueden no funcionar como se espera durante las pruebas.
- Las actualizaciones dentro de la app están disponibles solo para las cuentas de usuario propietarias de la app. Por lo tanto, asegúrate de que la cuenta que estás usando haya descargado tu app desde Google Play al menos una vez antes de usarla para probar las actualizaciones dentro de la app.
- Asegúrate de que la aplicación con la que estés probando las actualizaciones dentro de la app tenga el mismo ID de aplicación y esté firmada con la misma clave de firma que la que está disponible en Google Play.
- Debido a que Google Play solo puede actualizar una app a un código de versión posterior, asegúrate de que la que estés probando tenga un código de versión anterior al código de la actualización.
- Asegúrate de que la cuenta sea apta y de que la caché de Google Play esté actualizada. Para hacerlo, accede a la cuenta de Google Play Store en el dispositivo de prueba y sigue estos pasos:
- Asegúrate de cerrar la app de Google Play Store por completo.
- Abre la app de Google Play Store y ve a la pestaña Mis apps y juegos.
- Si la app que estás probando no aparece con una actualización disponible, verifica que hayas configurado correctamente los segmentos de prueba.