Cómo integrar Asset Delivery (código nativo)

Sigue los pasos que se indican en esta guía para acceder a los paquetes de elementos de tu app desde código de C y C++.

El código de integración de ejemplo está disponible en GitHub.

Crea contenido nativo

Usa los siguientes pasos para integrar Play Asset Delivery en el Android App Bundle de tu proyecto. No es necesario que uses Android Studio para seguir estos pasos.

  1. Actualiza la versión del complemento de Android para Gradle en el archivo build.gradle de tu proyecto a 4.0.0 o a una versión posterior.

  2. En el directorio de nivel superior de tu proyecto, crea un directorio para el paquete de recursos. Se usa el nombre de ese directorio como el nombre del paquete de recursos. Los nombres de los paquetes de recursos deben comenzar con una letra y solo pueden contener letras, números y guiones bajos.

  3. En el directorio del paquete de recursos, crea un archivo build.gradle y agrega el siguiente código. Asegúrate de especificar el nombre del paquete de recursos y solo un tipo de entrega:

    // In the asset pack’s build.gradle file:
    plugins {
        id 'com.android.asset-pack'
    }
    
    assetPack {
        packName = "asset-pack-name" // Directory name for the asset pack
        dynamicDelivery {
            deliveryType = "[ install-time | fast-follow | on-demand ]"
        }
    }
  4. En el archivo build.gradle de la app del proyecto, agrega el nombre de cada paquete de recursos de tu proyecto, como se muestra a continuación:

    // In the app build.gradle file:
    android {
        ...
        assetPacks = [":asset-pack-name", ":asset-pack2-name"]
    }
  5. En el archivo settings.gradle del proyecto, incluye todos los paquetes de recursos de tu proyecto, como se muestra a continuación:

    // In the settings.gradle file:
    include ':app'
    include ':asset-pack-name'
    include ':asset-pack2-name'
  6. En el directorio del paquete de recursos, crea el siguiente subdirectorio: src/main/assets.

  7. Coloca los recursos en el directorio src/main/assets. Aquí también puedes crear subdirectorios. Ahora la estructura del directorio de tu app debería verse de la siguiente manera:

    • build.gradle
    • settings.gradle
    • app/
    • asset-pack-name/build.gradle
    • asset-pack-name/src/main/assets/your-asset-directories
  8. Compila el Android App Bundle con Gradle. En el paquete de aplicación que se generó, el directorio raíz ahora incluye lo siguiente:

    • asset-pack-name/manifest/AndroidManifest.xml: Configura el identificador y el modo de entrega del paquete de recursos.
    • asset-pack-name/assets/your-asset-directories: Es el directorio que contiene todos los recursos entregados como parte del paquete de recursos.

    Gradle genera el manifiesto para cada paquete de recursos y te proporciona el directorio assets/.

  9. Opcional: Configura el paquete de aplicación para que sea compatible con diferentes formatos de compresión de texturas.

Cómo realizar la integración con la biblioteca de Play Asset Delivery

Debes implementar esta API según el tipo de entrega del paquete de recursos al que deseas acceder. Estos pasos se muestran en el siguiente diagrama de flujo.

Diagrama de flujo del paquete de recursos para el código nativo

Figura 1: Diagrama de flujo para acceder a paquetes de recursos

El SDK nativo de Play Core proporciona el archivo de encabezado de C de play/asset_pack.h para solicitar paquetes de recursos, administrar descargas y acceder a los recursos.

Cómo configurar tu entorno de desarrollo para el SDK nativo de Play Core

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
  1. 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.
  2. For purposes of these terms, "APIs" means Google's APIs, other developer services, and associated software, including any Redistributable Code.
  3. “Redistributable Code” means Google-provided object code or header files that call the APIs.
  4. 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.
  5. 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.
Descargar Play Core Native SDK

play-core-native-sdk-1.15.3.zip

  1. Elige una de las siguientes opciones:

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

  3. 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
  4. 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"))
        ...
    }
  5. 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 recopilación de datos de dependencias de bibliotecas declaradas por Google en Gradle cuando subes tu paquete de app a Play Console.

Entrega durante la instalación

Los paquetes de recursos configurados como install-time están disponibles apenas se inicia la app. Usa la API de NDK de AAssetManager para acceder a los recursos que se entregan en este modo:

#include <android/asset_manager.h>
#include <android_native_app_glue.h>
...
AAssetManager* assetManager = app->activity->assetManager;
AAsset* asset = AAssetManager_open(assetManager, "asset-name", AASSET_MODE_BUFFER);
size_t assetLength = AAsset_getLength(asset);
char* buffer = (char*) malloc(assetLength + 1);
AAsset_read(asset, buffer, assetLength);

Entrega rápida y a pedido

En las siguientes secciones, se muestra cómo inicializar la API, obtener información sobre los paquetes de recursos antes de descargarlos, llamar a la API para iniciar la descarga y acceder a los paquetes descargados. Estas secciones se aplican a los paquetes de recursos fast-follow y on-demand.

Inicio de la app

Siempre llama a AssetPackManager_init() para inicializar la API del paquete de recursos antes de llamar a cualquier otra función. Comprueba si hay códigos de error del paquete de recursos.

#include "play/asset_pack.h"
...
AssetPackErrorCode AssetPackManager_init(JavaVM* jvm, jobject android_context);

Además, asegúrate de llamar a las siguientes funciones en onPause() y onResume() de ANativeActivityCallbacks:

Obtén información de descarga sobre paquetes de recursos

Las apps deben divulgar el tamaño de la descarga antes de recuperar el paquete de recursos. Usa la función AssetPackManager_requestInfo() para iniciar una solicitud asíncrona del tamaño de la descarga y aunque el paquete ya se esté descargando. Luego, usa AssetPackManager_getDownloadState() para sondear el estado de descarga (por ejemplo, llama a esta función una vez por fotograma en el bucle de juego). Si falla una solicitud, consulta los códigos de error del paquete de recursos.

AssetPackErrorCode AssetPackManager_requestInfo();      // Call once
AssetPackErrorCode AssetPackManager_getDownloadState(); // Call once per frame in your game loop

La función AssetPackManager_getDownloadState() muestra el tipo opaco AssetPackDownloadState como un puntero de salida. Usa ese puntero para llamar a las siguientes funciones:

AssetPackDownloadState* state;
AssetPackErrorCode error_code = AssetPackManager_getDownloadState(asset-pack-name, &state);
AssetPackDownloadStatus status = AssetPackDownloadState_getStatus(state);
uint64_t downloadedBytes = AssetPackDownloadState_getBytesDownloaded(state);
uint64_t totalBytes = AssetPackDownloadState_getTotalBytesToDownload(state));
AssetPackDownloadState_destroy(state);

Instalar

Usa AssetPackManager_requestDownload() para comenzar a descargar un paquete de recursos por primera vez o solicitar que se complete la actualización de un paquete:

AssetPackErrorCode AssetPackManager_requestDownload();  // Call once
AssetPackErrorCode AssetPackManager_getDownloadState(); // Call once per frame in your game loop

La función AssetPackManager_getDownloadState() muestra el tipo opaco AssetPackDownloadState. Para obtener información sobre cómo usar este tipo, consulta Obtén información de descarga.

Descargas grandes

Si la descarga supera los 200 MB y el usuario no está conectado a una red Wi-Fi, no se iniciará la descarga hasta que el usuario otorgue explícitamente su consentimiento para continuar con la descarga mediante una conexión de datos móviles. Del mismo modo, si la descarga es grande y el usuario pierde la conexión Wi-Fi, se detendrá el proceso y se necesitará el consentimiento explícito para continuar usando una conexión de datos móviles. Un paquete detenido tiene el estado WAITING_FOR_WIFI. Para activar el flujo de la IU y solicitar el consentimiento del usuario, usa lo siguiente:

Confirmación del usuario obligatoria

Si un paquete tiene el estado REQUIRES_USER_CONFIRMATION, la descarga no se completa hasta que el usuario acepta el diálogo que se muestra con AssetPackManager_showConfirmationDialog(). Este estado puede ocurrir si Play no reconoce la app. Ten en cuenta que llamar a AssetPackManager_showConfirmationDialog() en este caso hace que se actualice la app. Después de la actualización, vuelve a solicitar los recursos.

Accede a los paquetes de recursos

Puedes acceder a un paquete de recursos a través de llamadas al sistema de archivos después de que la solicitud de descarga alcance el estado COMPLETED. Cada paquete de recursos se almacena en un directorio independiente, en el almacenamiento interno de la app. Usa AssetPackManager_getAssetPackLocation() a los efectos de obtener un AssetPackLocation para el paquete de recursos especificado. Usa AssetPackLocation_getStorageMethod() en esa ubicación para determinar el método de almacenamiento:

  • ASSET_PACK_STORAGE_APK: el paquete de recursos se instala como un APK. Consulta Entrega durante la instalación para acceder a estos recursos.
  • ASSET_PACK_STORAGE_FILES: usa AssetPackLocation_getAssetsPath() para obtener una ruta de acceso del archivo al directorio que contiene los recursos, o valores nulos si estos no se descargaron. No modifiques los archivos descargados en esta ruta de acceso del archivo.
AssetPackLocation* location;

AssetPackErrorCode error_code = AssetPackManager_getAssetPackLocation(asset-pack-name, &location);

if (error_code == ASSET_PACK_NO_ERROR) {
    AssetPackStorageMethod storage_method = AssetPackLocation_getStorageMethod(location);
    const char* assets_path = AssetPackLocation_getAssetsPath(location);
    AssetPackLocation_destroy(location);
}

Una vez que encuentres los recursos, usa funciones como fopen o ifstream para acceder a los archivos.

Otros métodos de la API de Play Core

Estos son algunos métodos de API adicionales que recomendamos que uses en tu app.

Cancela una solicitud

Usa AssetPackManager_cancelDownload() para cancelar una solicitud activa de paquete de recursos. Ten en cuenta que esta solicitud es una operación de mejor esfuerzo.

Solicitar eliminación

Usa AssetPackManager_requestRemoval() para programar la eliminación de un paquete de recursos.

Próximos pasos

Prueba Play Asset Delivery de forma local y desde Google Play.