Este guia descreve como oferecer compatibilidade com atualizações no app usando código nativo (C ou C++). Há guias separados para casos em que sua implementação usa a linguagem de programação Kotlin ou Java e outros em que ela usa o Unity.
Visão geral do SDK nativo
O SDK nativo da Play Core faz parte da família do
SDK da Play Core. O SDK nativo
inclui um arquivo principal C, app_update.h
, que envolve o
AppUpdateManager
da biblioteca Java Play In-App Update. Esse arquivo principal permite que o app
chame a API para atualizações no app diretamente pelo código nativo.
Configurar seu ambiente de desenvolvimento
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- 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.
Realize uma das seguintes ações:
- Instale o Android Studio versão 4.0 ou mais recente. Use a IU do SDK Manager para instalar o Android SDK Platform versão 10.0 (nível 29 da API).
- Instale as ferramentas de linha de comando do SDK do Android
e use o
sdkmanager
para instalar o Android SDK Platform versão 10.0 (API de nível 29).
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.
Faça o download do arquivo ZIP e extraia ele junto com o projeto.
Link de download Tamanho Soma de verificação SHA-256 (link em inglês) 36 MiB 782a8522d937848c83a715c9a258b95a3ff2879a7cd71855d137b41c00786a5e 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.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.1' // 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.1") // Import these common dependencies. implementation("com.google.android.gms:play-services-tasks:18.0.2") implementation(files("$playcoreDir/playcore-native-metadata.jar")) ... }
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.
Depois de integrar o SDK nativo da Play Core ao projeto, inclua a linha abaixo nos arquivos que contêm chamadas de API:
#include "play/app_update.h"
Inicializar a API de atualização no app
Sempre que você usar a API de atualização no app, inicialize-a primeiro chamando a função
AppUpdateManager_init()
,
conforme mostrado no exemplo a seguir criado com
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.
}
}
Conferir se há atualizações disponíveis
Antes de solicitar uma atualização, confira se há uma disponível para seu
app.
A função AppUpdateManager_requestInfo()
inicia uma solicitação assíncrona que coleta as informações necessárias para iniciar
o fluxo de atualização no app posteriormente. Ela retornará APP_UPDATE_NO_ERROR
se a
solicitação for iniciada com êxito.
AppUpdateErrorCode error_code = AppUpdateManager_requestInfo()
if (error_code == APP_UPDATE_NO_ERROR) {
// The request has successfully started, check the result using
// AppUpdateManager_getInfo.
}
Você pode rastrear o processo contínuo e o resultado da solicitação usando a
AppUpdateManager_getInfo()
.
Além do código de erro, essa função retorna uma
estrutura AppUpdateInfo
opaca, que pode ser usada para recuperar informações sobre a solicitação de
atualização Por exemplo, você pode querer chamar essa função em cada loop de jogo
até que ela retorne um resultado não nulo para info
:
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
}
...
}
Conferir inatividade de atualização
Além de conferir se uma atualização está disponível, também é possível saber quanto tempo se passou desde que o usuário foi notificado pela última vez sobre uma atualização pela Play Store. Isso pode ajudar você a decidir se deve iniciar uma atualização flexível ou uma imediata. Por exemplo, você pode esperar alguns dias antes de notificar o usuário sobre uma atualização flexível e mais alguns antes de exigir uma imediata.
Use
AppUpdateInfo_getClientVersionStalenessDays()
para verificar o número de dias desde que a atualização foi disponibilizada na Play
Store:
int32_t staleness_days = AppUpdateInfo_getClientVersionStalenessDays(info);
Conferir prioridade de atualização
A API Google Play Developer permite que você defina a prioridade de cada atualização. Isso permite que o app decida como recomendar uma atualização para o usuário. Por exemplo, considere a seguinte estratégia para definir a prioridade de atualização:
- Pequenas melhorias na IU: atualização de baixa prioridade. Não exigem a atualização flexível nem a imediata. Só atualize quando o usuário não estiver interagindo com o app.
- Melhorias de performance: atualização de prioridade média. Exigem uma atualização flexível.
- Atualização crítica de segurança: é de alta prioridade e precisa ser feita de forma imediata.
Para determinar a prioridade, o Google Play usa um valor inteiro entre 0 e 5, sendo 0
o padrão e 5 a prioridade mais alta. Para definir a prioridade de uma
atualização, use o campo inAppUpdatePriority
em Edits.tracks.releases
na API Google Play Developer. Todas as versões recém-adicionadas são
consideradas como tendo a mesma prioridade da versão lançada. A prioridade só pode ser definida ao lançar
uma nova versão e não pode ser mudada posteriormente.
Defina a prioridade usando a API Google Play Developer, conforme descrito na documentação
da API Google Play
Developer.
Especifique a prioridade de atualização no app no
recurso Edit.tracks
transmitido no
método
Edit.tracks: update
. O exemplo a seguir demonstra o lançamento de um app com o código de versão 88
e inAppUpdatePriority
5:
{ "releases": [{ "versionCodes": ["88"], "inAppUpdatePriority": 5, "status": "completed" }] }
No código do app, é possível conferir o nível de prioridade de uma determinada atualização usando
AppUpdateInfo_getPriority()
:
int32_t priority = AppUpdateInfo_getPriority(info);
Iniciar uma atualização
Depois de confirmar que há uma atualização disponível, solicite-a usando
AppUpdateManager_requestStartUpdate()
.
Antes de solicitar, providencie um objeto AppUpdateInfo
atualizado e
crie um
objeto AppUpdateOptions
para configurar o fluxo de atualização. Um objeto AppUpdateOptions
define
opções para um fluxo de atualização no app, incluindo se a atualização precisa ser
flexível ou imediata.
O exemplo a seguir cria um objeto AppUpdateOptions
para um fluxo de atualização
flexível:
// Creates an AppUpdateOptions configuring a flexible in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_FLEXIBLE, &options);
O exemplo a seguir cria um objeto AppUpdateOptions
para um fluxo de atualização
imediata:
// Creates an AppUpdateOptions configuring an immediate in-app update flow.
AppUpdateOptions* options;
AppUpdateErrorCode error_code = AppUpdateOptions_createOptions(APP_UPDATE_TYPE_IMMEDIATE, &options);
O objeto AppUpdateOptions
também contém um campo AllowAssetPackDeletion
que define se a atualização tem permissão para limpar pacotes de
recursos no caso de espaço de armazenamento limitado no dispositivo. Esse
campo é definido como false
por padrão, mas é possível usar o
método AppUpdateOptions_setAssetPackDeletionAllowed()
para defini-lo como true
:
bool allow = true;
AppUpdateErrorCode error_code = AppUpdateOptions_setAssetPackDeletionAllowed(options, allow);
Depois de ter um objeto AppUpdateInfo
atualizado e um objeto AppUpdateOptions
configurado corretamente,
chame AppUpdateManager_requestStartUpdate()
para
solicitar um fluxo de atualização de forma assíncrona, transmitindo uma atividade jobject
do Android
como parâmetro final.
AppUpdateErrorCode request_error_code =
AppUpdateManager_requestStartUpdate(info, options, app->activity->clazz);
Para liberar recursos, deixe de lado instâncias de AppUpdateInfo
e
AppUpdateOptions
que não sejam mais necessárias, chamando
AppUpdateInfo_destroy()
e
AppUpdateOptions_destroy()
,
respectivamente.
AppUpdateInfo_destroy(info);
AppUpdateOptions_destroy(options);
Para um fluxo de atualização imediato, o Google Play exibe uma página de confirmação do usuário. Quando o usuário aceita a solicitação, o Google Play faz automaticamente o download e a instalação da atualização em primeiro plano e, em seguida, reinicia o app para a versão atualizada, caso a instalação seja bem-sucedida.
Para um fluxo de atualização flexível, você pode continuar solicitando objetos AppUpdateInfo
atualizados para acompanhar o status de atualização atual enquanto o usuário continua a
interagir com o app. Depois que o download terminar, acione
a conclusão da atualização, chamando
AppUpdateManager_requestCompleteUpdate()
,
conforme mostrado no exemplo a seguir:
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.
}
}
Quando seu app terminar de usar a API, libere recursos chamando a
função AppUpdateManager_destroy()
.
Gerenciamento de erros
Esta seção descreve soluções para erros comuns indicados por valores
AppUpdateErrorCode
específicos:
- Um código de erro
-110, APP_UPDATE_INITIALIZATION_NEEDED
indica que a API não foi inicializada corretamente. ChameAppUpdateManager_init()
para inicializar a API. - Um código de erro
-4, APP_UPDATE_INVALID_REQUEST
indica que alguns parâmetros da solicitação de fluxo de atualização estão incorretos. Confira se os objetosAppUpdateInfo
eAppUpdateOptions
não são nulos e se estão formatados corretamente. - Um código de erro
-5, APP_UPDATE_UNAVAILABLE
indica que não há uma atualização aplicável disponível. Confira se a versão de destino tem os mesmos nome de pacote, ID do aplicativo e chave de assinatura. Se houver uma atualização disponível, limpe o cache do app e chameAppUpdateManager_requestAppUpdateInfo()
novamente para atualizar o objetoAppUpdateInfo
. - Um código de erro
-6, APP_UPDATE_NOT_ALLOWED
aponta que o tipo de atualização indicado pelo objetoAppUpdateOption
não é permitido. Confira se o objetoAppUpdateInfo
indica que o tipo de atualização é permitido antes de iniciar o fluxo de atualização.
A seguir
Testar as atualizações no app para verificar se a integração está funcionando corretamente.