Compatibilidade com atualizações no app (nativo)

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 une a classe AppUpdateManager do SDK da Play Core do Java. Esse arquivo principal permite que o app chame a API para atualizações no app diretamente pelo código nativo.

Configurar o ambiente para desenvolvedores

Para configurar o ambiente para desenvolvedores, siga as instruções de configuração da seção Nativo do guia da biblioteca Play Core.

Depois de integrar o SDK nativo da Play Core ao seu projeto, inclua a seguinte linha 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 desempenho: atualização de prioridade média. Exigem uma atualização flexível.
  • Atualização crítica de segurança: atualização de alta prioridade. Exige uma atualização 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. Chame AppUpdateManager_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 objetos AppUpdateInfo e AppUpdateOptions 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 chame AppUpdateManager_requestAppUpdateInfo() novamente para atualizar o objeto AppUpdateInfo.
  • Um código de erro -6, APP_UPDATE_NOT_ALLOWED aponta que o tipo de atualização indicado pelo objeto AppUpdateOption não é permitido. Confira se o objeto AppUpdateInfo 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.