Integrar a entrega de recursos (nativo)

Use as etapas deste guia para acessar os pacotes de recursos do app a partir do código C e C++.

Há um código de integração (link em inglês) de exemplo disponível no GitHub.

Criar para nativo

Use as etapas a seguir para criar o Play Asset Delivery no Android App Bundle do seu projeto. Não é necessário usar o Android Studio para executar estas etapas.

  1. Atualize a versão do Plug-in do Android para Gradle no arquivo build.gradle do projeto para 4.0.0 ou mais recente.

  2. No diretório de nível superior do projeto, crie um diretório para o pacote de recursos. O nome do diretório é usado como nome do pacote de recursos. Os nomes de pacotes de recursos precisam começar com uma letra e só podem conter letras, números e sublinhados.

  3. No diretório do pacote de recursos, crie um arquivo build.gradle e adicione o seguinte código. Especifique o nome do pacote de recursos e apenas um 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. No arquivo build.gradle do app do projeto, adicione o nome de cada pacote de recursos, conforme mostrado abaixo:

    // In the app build.gradle file:
    android {
        ...
        assetPacks = [":asset-pack-name", ":asset-pack2-name"]
    }
    
  5. No arquivo settings.gradle do projeto, inclua todos os pacotes de recursos, conforme mostrado abaixo:

    // In the settings.gradle file:
    include ':app'
    include ':asset-pack-name'
    include ':asset-pack2-name'
    
  6. No diretório do pacote de recursos, crie o seguinte subdiretório: src/main/assets.

  7. Coloque recursos no diretório src/main/assets. Você também pode criar subdiretórios nesse local. A estrutura de diretórios do seu app agora terá a seguinte aparência:

    • build.gradle
    • settings.gradle
    • app/
    • asset-pack-name/build.gradle
    • asset-pack-name/src/main/assets/your-asset-directories
  8. Crie o Android App Bundle com o Gradle. No pacote de apps gerado, o diretório de nível raiz agora inclui o seguinte:

    • asset-pack-name/manifest/AndroidManifest.xml: configura o identificador e o modo de entrega do pacote de recursos
    • asset-pack-name/assets/your-asset-directories: diretório que contém todos os recursos enviados como parte do pacote de recursos

    O Gradle gera o manifesto para cada pacote de recursos e gera o diretório assets/ para você.

  9. (Opcional) Configure seu pacote de apps para oferecer suporte a diferentes formatos de compactação de textura.

Integrar com a biblioteca Play Asset Delivery

Implemente essa API de acordo com o tipo de entrega do pacote de recursos que você quer acessar. Essas etapas são mostradas no fluxograma a seguir.

Diagrama de fluxo de pacotes de recursos para código nativo

Figura 1. Diagrama de fluxo para acessar pacotes de recursos.

O SDK nativo do Play Core fornece o arquivo principal C play/asset_pack.h para solicitar pacotes de recursos, gerenciar downloads e acessar os recursos.

Configurar o ambiente de desenvolvimento para o SDK nativo da Play Core

Fazer o download Play Core Native SDK

Antes de fazer o download, você precisa concordar com os seguintes Termos e Condições.

Termos e Condições

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.
Fazer download Play Core Native SDK

play-core-native-sdk-1.14.0.zip

  1. Realize uma das ações abaixo:

  2. Prepare o Android Studio para o desenvolvimento nativo usando o SDK Manager para instalar o CMake e o Android Native Development Kit (NDK) mais recentes. Para saber mais sobre como criar ou importar projetos nativos, consulte Começar a usar o NDK.

  3. Faça o download do arquivo ZIP e extraia ele junto com o projeto.

    Link de download Tamanho Soma de verificação SHA-256
    36 MiB 782a8522d937848c83a715c9a258b95a3ff2879a7cd71855d137b41c00786a5e
  4. Atualize o arquivo build.gradle do app como mostrado abaixo:

    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.0.0'
            implementation 'com.google.android.play:asset-delivery:2.0.0'
            implementation 'com.google.android.play:integrity:1.0.1'
            implementation 'com.google.android.play:review:2.0.0'
    
            // 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.0.0")
        implementation("com.google.android.play:asset-delivery:2.0.0")
        implementation("com.google.android.play:integrity:1.0.1")
        implementation("com.google.android.play:review:2.0.0")
    
        // Import these common dependencies.
        implementation("com.google.android.gms:play-services-tasks:18.0.2")
        implementation(files("$playcoreDir/playcore-native-metadata.jar"))
        ...
    }
    
  5. Atualize os arquivos CMakeLists.txt do app como mostrado abaixo:

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

Coleta de dados

O SDK nativo da Play Core pode coletar dados relacionados à versão para que o Google melhore o produto, incluindo:

  • Nome do pacote do app
  • Versão do pacote do app
  • Versão do SDK nativo da Play Core

Esses dados vão ser coletados quando você fizer upload do seu pacote de apps para o Play Console. Para desativar esse processo de coleta de dados, remova a importação de $playcoreDir/playcore-native-metadata.jar no arquivo build.gradle.

Essa coleta de dados relacionada ao seu uso do SDK nativo da Play Core e o uso do Google dos dados coletados são independentes e não estão relacionados à coleta de dependências de biblioteca do Google declaradas no Gradle quando você faz upload do pacote do app para o Play Console.

Envio na instalação

Os pacotes de recursos configurados como install-time estão imediatamente disponíveis no lançamento do app. Use a API NDK AAssetManager para acessar os recursos disponibilizados neste 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);

Envio rápido e sob demanda

As seções a seguir mostram como inicializar a API, receber informações sobre pacotes de recursos antes de fazer o download deles, como chamar a API para iniciar o download e como acessar os pacotes baixados. Essas seções se aplicam aos pacotes de recursos fast-follow e on-demand.

Lançamento do app

Sempre chame AssetPackManager_init() para inicializar a API do pacote de recursos antes de chamar qualquer outra função. Verifique se há códigos de erro de pacote de recursos.

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

Além disso, chame as seguintes funções em onPause() e onResume() de ANativeActivityCallbacks:

Receber informações de download sobre pacotes de recursos

Os apps precisam divulgar o tamanho do download antes de buscar o pacote de recursos. Use a função AssetPackManager_requestInfo() para iniciar uma solicitação assíncrona para o tamanho do download e se o pacote já está sendo baixado. Em seguida, use AssetPackManager_getDownloadState() para pesquisar o estado do download. Por exemplo, chame essa função uma vez por frame no loop de jogo. Se uma solicitação falhar, verifique os códigos de erro do pacote de recursos.

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

A função AssetPackManager_getDownloadState() retorna o tipo opaco AssetPackDownloadState como um ponteiro de saída. Use este ponteiro para chamar as seguintes funções:

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

Use AssetPackManager_requestDownload() para começar a fazer o download de um pacote de recursos pela primeira vez ou para solicitar a atualização:

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

A função AssetPackManager_getDownloadState() retorna o tipo opaco AssetPackDownloadState. Para informações sobre como usar esse tipo, consulte Receber informações de download.

Downloads grandes

Se o download for maior que 200 MB e o usuário não estiver conectado ao Wi-Fi, o download não será iniciado até que o usuário dê explicitamente o consentimento para prosseguir com o download usando uma conexão de dados móveis. Da mesma forma, se o download for grande e o usuário perder o Wi-Fi, o download será pausado e o consentimento explícito será necessário para continuar usando uma conexão de dados móveis. Um pacote pausado tem o estado WAITING_FOR_WIFI. Para acionar o fluxo da IU para solicitar o consentimento do usuário, use o seguinte:

Confirmação obrigatória do usuário

Se um pacote tiver o status REQUIRES_USER_CONFIRMATION, o download não continuará até que o usuário aceite a caixa de diálogo mostrada com AssetPackManager_showConfirmationDialog(). Esse status poderá surgir se o app não for reconhecido pelo Google Play. Observe que chamar AssetPackManager_showConfirmationDialog() nesse caso faz com que o app seja atualizado. Após a atualização, solicite os recursos novamente.

Acessar pacotes de recursos

É possível acessar um pacote de recursos usando chamadas do sistema de arquivos após a solicitação de download chegar ao estado COMPLETED. Cada pacote de recursos é armazenado em um diretório separado no armazenamento interno do app. Use AssetPackManager_getAssetPackLocation() para receber um AssetPackLocation para o pacote de recursos especificado. Use AssetPackLocation_getStorageMethod() nesse local para determinar o método de armazenamento:

  • ASSET_PACK_STORAGE_APK: o pacote de recursos está instalado como um APK. Consulte Envio no momento da instalação para acessar esses recursos.
  • ASSET_PACK_STORAGE_FILES: use AssetPackLocation_getAssetsPath() para extrair um caminho de arquivo para o diretório que contém os recursos ou retorna nulo se os recursos não foram transferidos por download. Não modifique arquivos transferidos por download nesse caminho.
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);
}

Depois de localizar os recursos, use funções como fopen ou ifstream para acessar os arquivos.

Outros métodos da API Play Core

Veja a seguir alguns métodos adicionais de API que podem ser usados no seu app.

Cancelar solicitação

Use AssetPackManager_cancelDownload() para cancelar uma solicitação ativa de pacote de recursos. Observe que essa solicitação é uma operação de melhor esforço.

Solicitar remoção

Use AssetPackManager_requestRemoval() para programar a remoção de um pacote de recursos.

Próximas etapas

Teste o Play Asset Delivery localmente e no Google Play.