En esta guía, se describe cómo admitir actualizaciones integradas en tu app usando código nativo (C o C++). Existen guías separadas para casos en los que tu implementación usa los lenguajes de programación Kotlin o Java, y casos en los que esta usa Unity.
Descripción general del SDK nativo
El SDK nativo de Play Core forma parte de la familia del SDK de Play Core. El SDK nativo incluye un archivo de encabezado C, app_update.h
, que une AppUpdateManager
de la biblioteca de actualizaciones integradas en la app de Java. Este archivo de encabezado permite que tu app llame a la API para realizar actualizaciones integradas en la app directamente desde tu código nativo.
Cómo configurar tu entorno de desarrollo
Descargar Play Core Native SDK
Antes de la descarga, debes aceptar los Términos y Condiciones.
Términos y Condiciones
Last modified: September 24, 2020- By using the Play Core Software Development Kit, you agree to these terms in addition to the Google APIs Terms of Service ("API ToS"). If these terms are ever in conflict, these terms will take precedence over the API ToS. Please read these terms and the API ToS carefully.
- For purposes of these terms, "APIs" means Google's APIs, other developer services, and associated software, including any Redistributable Code.
- “Redistributable Code” means Google-provided object code or header files that call the APIs.
- Subject to these terms and the terms of the API ToS, you may copy and distribute Redistributable Code solely for inclusion as part of your API Client. Google and its licensors own all right, title and interest, including any and all intellectual property and other proprietary rights, in and to Redistributable Code. You will not modify, translate, or create derivative works of Redistributable Code.
- Google may make changes to these terms at any time with notice and the opportunity to decline further use of the Play Core Software Development Kit. Google will post notice of modifications to the terms at https://developer.android.com/guide/playcore/license. Changes will not be retroactive.
Elige una de las siguientes opciones:
- Instala la versión 4.0 o una posterior de Android Studio. Usa la IU del SDK Manager para instalar la versión 10.0 de la plataforma del SDK de Android (nivel de API 29).
- Instala las herramientas de línea de comandos del SDK de Android y usa
sdkmanager
para instalar la versión 10.0 de la plataforma del SDK de Android (nivel de API 29).
Prepara Android Studio para el desarrollo nativo con SDK Manager para instalar la versión más reciente del kit de desarrollo nativo (NDK) de CMake y Android. Obtén más información para crear o importar proyectos nativos en la sección Cómo comenzar a usar el NDK.
Descarga el archivo ZIP y extráelo junto con tu proyecto.
Vínculo de descarga Tamaño Suma de comprobación SHA-256 37.8 MiB 9db60185185342f28d2c278b60222333608c67bc022e458a25224eaea8c4c4b7 Actualiza el archivo
build.gradle
de tu app como se muestra a continuación:Groovy
// App build.gradle plugins { id 'com.android.application' } // Define a path to the extracted Play Core SDK files. // If using a relative path, wrap it with file() since CMake requires absolute paths. def playcoreDir = file('../path/to/playcore-native-sdk') android { defaultConfig { ... externalNativeBuild { cmake { // Define the PLAYCORE_LOCATION directive. arguments "-DANDROID_STL=c++_static", "-DPLAYCORE_LOCATION=$playcoreDir" } } ndk { // Skip deprecated ABIs. Only required when using NDK 16 or earlier. abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } buildTypes { release { // Include Play Core Library proguard config files to strip unused code while retaining the Java symbols needed for JNI. proguardFile '$playcoreDir/proguard/common.pgcfg' proguardFile '$playcoreDir/proguard/gms_task.pgcfg' proguardFile '$playcoreDir/proguard/per-feature-proguard-files' ... } debug { ... } } externalNativeBuild { cmake { path 'src/main/CMakeLists.txt' } } } dependencies { // Import these feature-specific AARs for each Google Play Core library. implementation 'com.google.android.play:app-update:2.1.0' implementation 'com.google.android.play:asset-delivery:2.2.2' implementation 'com.google.android.play:integrity:1.4.0' implementation 'com.google.android.play:review:2.0.2' // Import these common dependencies. implementation 'com.google.android.gms:play-services-tasks:18.0.2' implementation files("$playcoreDir/playcore-native-metadata.jar") ... }
Kotlin
// App build.gradle plugins { id("com.android.application") } // Define a path to the extracted Play Core SDK files. // If using a relative path, wrap it with file() since CMake requires absolute paths. val playcoreDir = file("../path/to/playcore-native-sdk") android { defaultConfig { ... externalNativeBuild { cmake { // Define the PLAYCORE_LOCATION directive. arguments += listOf("-DANDROID_STL=c++_static", "-DPLAYCORE_LOCATION=$playcoreDir") } } ndk { // Skip deprecated ABIs. Only required when using NDK 16 or earlier. abiFilters.clear() abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") } } buildTypes { release { // Include Play Core Library proguard config files to strip unused code while retaining the Java symbols needed for JNI. proguardFile("$playcoreDir/proguard/common.pgcfg") proguardFile("$playcoreDir/proguard/gms_task.pgcfg") proguardFile("$playcoreDir/proguard/per-feature-proguard-files") ... } debug { ... } } externalNativeBuild { cmake { path = "src/main/CMakeLists.txt" } } } dependencies { // Import these feature-specific AARs for each Google Play Core library. implementation("com.google.android.play:app-update:2.1.0") implementation("com.google.android.play:asset-delivery:2.2.2") implementation("com.google.android.play:integrity:1.4.0") implementation("com.google.android.play:review:2.0.2") // Import these common dependencies. implementation("com.google.android.gms:play-services-tasks:18.0.2") implementation(files("$playcoreDir/playcore-native-metadata.jar")) ... }
Actualiza los archivos
CMakeLists.txt
de tu app como se muestra a continuación:cmake_minimum_required(VERSION 3.6) ... # Add a static library called “playcore” built with the c++_static STL. include(${PLAYCORE_LOCATION}/playcore.cmake) add_playcore_static_library() // In this example “main” is your native code library, i.e. libmain.so. add_library(main SHARED ...) target_include_directories(main PRIVATE ${PLAYCORE_LOCATION}/include ...) target_link_libraries(main android playcore ...)
Recopilación de datos
Para permitir que Google mejore el producto, el SDK nativo de Play Core puede recopilar datos relacionados con la versión como los siguientes:
- Nombre del paquete de la app
- Versión del paquete de la app
- Versión del SDK nativo de Play Core
Estos datos se recopilarán cuando subas el paquete de tu app a Play Console. Para inhabilitar este proceso de recopilación de datos, quita la importación de $playcoreDir/playcore-native-metadata.jar
en el archivo build.gradle.
Ten en cuenta que la recopilación de datos relacionada con tu uso del SDK nativo de Play Core y el uso que Google hace de los datos recopilados es independiente de la colección de dependencias de bibliotecas declarada por Google en Gradle cuando subes tu paquete de app a Play Console.
Después de integrar el SDK nativo de Play Core en tu proyecto, incluye la siguiente línea en los archivos que contengan llamadas a la APIs:
#include "play/app_update.h"
Cómo inicializar la API de actualizaciones integradas en la app
Siempre que uses la API de actualizaciones en la app, debes llamar a la función AppUpdateManager_init()
para inicializarla, como se muestra en el siguiente ejemplo compilado con android_native_app_glue.h
:
void android_main(android_app* app) {
app->onInputEvent = HandleInputEvent;
AppUpdateErrorCode error_code =
AppUpdateManager_init(app->activity->vm, app->activity->clazz);
if (error_code == APP_UPDATE_NO_ERROR) {
// You can use the API.
}
}
Cómo comprobar la disponibilidad de actualizaciones
Antes de solicitar una actualización, verifica si hay alguna disponible para tu app. AppUpdateManager_requestInfo()
inicia una solicitud asíncrona que recopila la información necesaria para iniciar el flujo de actualización integrada en la app más adelante. Esta función muestra APP_UPDATE_NO_ERROR
si la solicitud se inicia correctamente.
AppUpdateErrorCode error_code = AppUpdateManager_requestInfo()
if (error_code == APP_UPDATE_NO_ERROR) {
// The request has successfully started, check the result using
// AppUpdateManager_getInfo.
}
Puedes realizar un seguimiento del proceso en curso y el resultado de la solicitud mediante AppUpdateManager_getInfo()
.
Además del código de error, esta función muestra una estructura opaca AppUpdateInfo
, que puedes usar para recuperar información sobre la solicitud de actualización. Por ejemplo, es posible que desees llamar a esta función en cada bucle de juego hasta que muestre un resultado de info
no nulo:
AppUpdateInfo* info;
GameUpdate() {
// Keep calling this in every game loop until info != nullptr
AppUpdateErrorCode error_code = AppUpdateManager_getInfo(&info);
if (error_code == APP_UPDATE_NO_ERROR && info != nullptr) {
// Successfully started, check the result in the following functions
}
...
}
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 puede ayudarte a decidir si debes iniciar una actualización flexible o una actualización inmediata. Por ejemplo, podrías esperar unos días antes de notificar al usuario con una actualización flexible y, luego, solicitar una actualización inmediata.
Usa AppUpdateInfo_getClientVersionStalenessDays()
para verificar cuántos días pasaron desde que apareció la actualización en Play Store:
int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);
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 actualización inmediata. Actualiza la app solo cuando el usuario no esté interactuando con ella.
- 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 de una actualización, usa el campo inAppUpdatePriority
en Edits.tracks.releases
de la API de Google Play Developer. Se considerará que todas las versiones agregadas en la original tendrán establecida la misma prioridad que este última. Solo se puede establecer la prioridad al momento de lanzar una versión nueva; no se puede cambiar más tarde.
Establece la prioridad mediante la API de Google Play Developer como se describe en la documentación de la API de Play Developer.
Especifica la prioridad de actualización de la app en el recurso Edit.tracks
pasado en el método Edit.tracks: update
. En el siguiente ejemplo, se muestra cómo lanzar una app con código de versión 88 y 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 con AppUpdateInfo_getPriority()
:
int32_t priority = AppUpdateInfo_getPriority(info);
Cómo iniciar una actualización
Después de confirmar que hay una actualización disponible, puedes solicitarla con AppUpdateManager_requestStartUpdate()
:
Antes de hacerlo, obtén un objeto AppUpdateInfo
actualizado y crea un objeto AppUpdateOptions
para configurar el flujo de la actualización. Un objeto AppUpdateOptions
define opciones para un flujo de actualización integrada en la app, que incluye si la actualización debe ser flexible o inmediata.
En el siguiente ejemplo, se crea un objeto AppUpdateOptions
para un flujo de actualización flexible:
// Creates an AppUpdateOptions configuring a flexible in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_FLEXIBLE, &options);
En el siguiente ejemplo, se crea un objeto AppUpdateOptions
para un flujo de actualización inmediato:
// Creates an AppUpdateOptions configuring an immediate in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_IMMEDIATE, &options);
El objeto AppUpdateOptions
también contiene un campo AllowAssetPackDeletion
que define si la actualización puede borrar paquetes de recursos si el almacenamiento del dispositivo es limitado. Este campo se establece en false
de forma predeterminada, pero puedes usar el método AppUpdateOptions_setAssetPackDeletionAllowed()
para establecerlo en true
en su lugar:
bool allow = true;
AppUpdateErrorCode error_code = AppUpdateOptions_setAssetPackDeletionAllowed(options, allow);
Una vez que tengas un objeto AppUpdateInfo
actualizado y un objeto AppUpdateOptions
configurado correctamente, llama a AppUpdateManager_requestStartUpdate()
a fin de solicitar de forma asíncrona un flujo de actualización y pasa una actividad de Android jobject
para el parámetro final.
AppUpdateErrorCode request_error_code =
AppUpdateManager_requestStartUpdate(info, options, app->activity->clazz);
Para despejar recursos, libera instancias de AppUpdateInfo
y AppUpdateOptions
que ya no necesites mediante llamadas a AppUpdateInfo_destroy()
y AppUpdateOptions_destroy()
, respectivamente.
AppUpdateInfo_destroy(info);
AppUpdateOptions_destroy(options);
Para obtener un flujo de actualización inmediata, Google Play muestra una página de confirmación del usuario. Cuando el usuario acepta la solicitud, Google Play descarga e instala automáticamente la actualización en primer plano y, luego, reinicia la app a la versión actualizada si la instalación se realizó correctamente.
Para obtener un flujo de actualización flexible, puedes seguir solicitando objetos AppUpdateInfo
actualizados y hacer un seguimiento del estado actual de la actualización mientras el usuario interactúa con la app. Una vez que la descarga finalice correctamente, debes llamar a AppUpdateManager_requestCompleteUpdate()
y activar la finalización, como se muestra en el siguiente ejemplo:
AppUpdateStatus status = AppUpdateInfo_getStatus(info);
if (status == APP_UPDATE_DOWNLOADED) {
AppUpdateErrorCode error_code = AppUpdateManager_requestCompleteUpdate();
if (error_code != APP_UPDATE_NO_ERROR)
{
// There was an error while completing the update flow.
}
}
Llama a la función AppUpdateManager_destroy()
una vez que tu app haya terminado de usar la API a fin de liberar recursos.
Administración de errores
En esta sección, se detallan soluciones de errores comunes indicados con valores específicos de AppUpdateErrorCode
:
- Un código de error de
-110, APP_UPDATE_INITIALIZATION_NEEDED
indica que la API no se inicializó correctamente. Llama aAppUpdateManager_init()
para inicializarla. - Un código de error de
-4, APP_UPDATE_INVALID_REQUEST
indica que algunos parámetros de la solicitud de flujo de actualización presentan errores de formato. Comprueba que los objetosAppUpdateInfo
yAppUpdateOptions
no sean nulos y tengan el formato correcto. - Un código de error de
-5, APP_UPDATE_UNAVAILABLE
indica que no hay una actualización aplicable disponible. Asegúrate de que la versión de destino tenga el mismo nombre de paquete, ID de aplicación y clave de firma. Si hay una actualización disponible, borra la caché de la app y vuelve a llamar aAppUpdateManager_requestAppUpdateInfo()
para actualizarAppUpdateInfo
. - Un código de error de
-6, APP_UPDATE_NOT_ALLOWED
indica que no se permite el tipo de actualización indicado por el objetoAppUpdateOption
. Comprueba que el objetoAppUpdateInfo
indique que el tipo de actualización está permitido antes de iniciar el flujo correspondiente.
Próximos pasos
Prueba las actualizaciones integradas en la app a fin de verificar que la integración funcione correctamente.