1. Introdução
Última atualização: 4 de janeiro de 2023
O que é a Play Integrity?
A API Play Integrity ajuda a proteger apps e jogos contra interações possivelmente perigosas e fraudulentas. Você pode usar a API Play Integrity para receber vereditos de integridade do seu app e dispositivo, o que pode ajudar a responder com as ações adequadas para reduzir ataques e abusos, como fraude, trapaças e acesso não autorizado.
Soluções anteriores
A API Play Integrity substitui duas soluções anteriores: a biblioteca App Licensing e a API SafetyNet Attestation. A Play Integrity é recomendada para novos aplicativos. Recomendamos atualizar os aplicativos atuais que usam as soluções anteriores para usar a Play Integrity.
Como escolher um caminho
A Play Integrity inclui opções de biblioteca para diferentes tipos de apps:
- Jogos ou outros apps criados em C/C++.
- Apps criados na linguagem de programação Kotlin ou Java.
- Jogos desenvolvidos com o mecanismo do Unity.
Este codelab inclui caminhos para as três opções. Você pode escolher os caminhos que são relevantes para suas necessidades de desenvolvimento. O codelab envolve a criação e a implantação de um servidor de back-end. Esse servidor é compartilhado nos três tipos de app.
O que você vai criar
Neste codelab, você vai integrar a Play Integrity a um app de exemplo e usar a API para verificar a integridade do dispositivo e do app. Você implantará um pequeno aplicativo de servidor de back-end usado para dar suporte ao processo de verificação de integridade.
O que você vai aprender
- Como integrar a biblioteca Play Integrity a um app.
- Como usar a API Play Integrity para fazer uma verificação de integridade.
- Como processar um veredito de integridade com segurança usando um servidor.
- Como interpretar os resultados do veredito de integridade.
O foco deste codelab é a Play Integrity. Conceitos não relevantes e blocos de código não são explicados em detalhes e são fornecidos para que você apenas copie e cole.
O que é necessário
- Uma Conta do Google com um registro de desenvolvedor Android ativo, acesso ao Play Console e ao console do Google Cloud.
- Para os caminhos C++ ou Kotlin, use o Android Studio 2021.1.1 ou mais recente.
- Para o caminho do Unity, use o Unity 2020 LTS ou uma versão mais recente.
- Um dispositivo Android conectado ao computador com as Opções do desenvolvedor e a Depuração USB ativadas.
Este codelab inclui links para recursos sobre como assinar e fazer upload de builds para o Play Console, mas é necessário que você tenha alguma familiaridade com esse processo.
2. Acessar o código
Os projetos do codelab estão disponíveis em um repositório Git. Há quatro diretórios no diretório pai do repositório:
- O diretório
server
contém o código do servidor de exemplo que você implantará. - O diretório
cpp
contém um projeto do Android Studio para adicionar a Play Integrity a um jogo ou app C++. - O diretório
kotlin
contém um projeto do Android Studio para adicionar a Play Integrity a um app Android padrão. - O diretório
unity
contém um projeto criado com a versão 2020 LTS do mecanismo do Unity para adicionar a Play Integrity a um projeto do Unity.
Em cada um dos diretórios de exemplo do cliente há dois subdiretórios:
- O diretório
start
, que tem a versão do projeto que vamos modificar para este codelab. - O diretório
final
, que tem uma versão do projeto que corresponde à aparência que ele vai ter após a conclusão do codelab.
Como clonar o repositório
Na linha de comando, mude para o diretório que você quer que contenha o diretório raiz add-play-integrity-codelab
e, em seguida, clone o projeto do GitHub usando esta sintaxe:
git clone https://github.com/android/add-play-integrity-codelab.git
Como adicionar dependências (somente C++)
Se você pretende usar o caminho C++, é necessário inicializar os submódulos do repositório para configurar a biblioteca Dear ImGui (link em inglês), usada para a interface do usuário. Para fazer isso, na linha de comando:
- Mude o diretório de trabalho para:
add-play-integrity-codelab/cpp/start/third-party
git submodule update --init
3. Entender as funções de cliente e servidor
Um elemento importante do modelo de segurança da Play Integrity é mover as operações de validação do dispositivo para um servidor seguro que você controla. A execução dessas operações no servidor protege contra situações como um dispositivo comprometido tentando implantar um ataque de repetição ou adulterando o conteúdo da mensagem.
O servidor do codelab é um exemplo e, para simplificar, não contém muitos recursos que seriam desejáveis em um ambiente de produção. A lista de valores gerados é armazenada apenas na memória e não tem suporte do armazenamento permanente. Os endpoints do servidor não estão configurados para exigir autenticação (link em inglês).
O endpoint performCommand
O servidor fornece um endpoint /performCommand
acessado por uma solicitação HTTP POST
. O corpo da solicitação precisa ser um payload JSON com estes pares de chave-valor:
{
"commandString": "command-here",
"tokenString": "token-here"
}
O endpoint /performCommand
retorna um payload JSON com estes pares de chave-valor:
{
"commandSuccess": true/false,
"diagnosticMessage": "summary text",
"expressToken": "token-here"
}
O conteúdo real do parâmetro commandString
não importa. O servidor valida a integridade da commandString
ao usar a Play Integrity, mas não usa o valor do comando. Todas as versões de cliente usam o valor "TRANSFER FROM alice TO bob CURRENCY gems QUANTITY 1000"
.
O valor do parâmetro tokenString
precisa ser:
- Um token gerado pela API Play Integrity.
- Um token expresso retornado por uma chamada anterior para
/performCommand
.
O servidor descriptografa e valida o token fornecido pela API Play Integrity. O resultado da descriptografia é um payload JSON de sinais de integridade. Dependendo do valor dos sinais, o servidor pode aprovar ou rejeitar o comando. Se o token for descriptografado, uma descrição resumida dos indicadores será retornada em diagnosticMessage
. Normalmente, essas informações não são retornadas ao cliente em um aplicativo de produção, mas são usadas pelos clientes do codelab para mostrar o resultado da operação sem a necessidade de analisar os registros do servidor. Se ocorrer uma condição de erro durante o processamento do token, o erro será retornado em diagnosticMessage
.
Geração de valores de uso único
Para fazer uma solicitação à Play Integrity, gere e associe um valor de uso único à solicitação. O valor de uso único é usado para ajudar a garantir que uma solicitação de integridade seja única e processada somente uma vez. Ele também é usado para verificar se o conteúdo da mensagem associada à solicitação de integridade não foi adulterado. Para mais informações sobre valores de uso único da Play Integrity, consulte a documentação.
Neste codelab, o valor de uso único é gerado combinando dois valores:
- Um número aleatório de 128 bits gerado por um gerador de números aleatórios criptograficamente seguro
- Um hash SHA-256 do valor
commandString
A API Play Integrity espera que o valor de uso único seja uma string Base64 sem padding codificada em URL. Para criar a string de valor de uso único, este codelab converte as matrizes de bytes do número aleatório e dos valores de hash em strings hexadecimais e as concatena. A string resultante é uma string Base64 válida, mas não é codificada nem decodificada dessa forma.
Os clientes do codelab extraem o número aleatório chamando um endpoint /getRandom
no servidor com uma solicitação HTTP GET
. Esse é o método mais seguro de geração aleatória, já que o servidor pode verificar se ele foi a origem do número aleatório usado na solicitação de comando. No entanto, isso envolve uma chamada de ida e volta extra ao servidor. Os clientes podem eliminar essa etapa extra gerando o número aleatório por conta própria, abrindo mão de um pouco de segurança.
Token expresso
Como chamar a PIA é caro, o servidor também fornece um token expresso, um método alternativo de autenticação que fornece segurança mais baixa a um custo computacional menor. Um token expresso é retornado no campo expressToken
por uma chamada para /serverCommand
com uma verificação de integridade aprovada. Chamar a API Play Integrity é algo computacionalmente caro e tem como objetivo proteger as operações de alto valor. Ao retornar o token expresso, o servidor fornece uma autenticação de segurança mais baixa para a execução de operações que podem ser menos importantes ou ocorrer com muita frequência para justificar a validação completa com a API Play Integrity. Um token expresso pode ser usado em vez de um token da Play Integrity ao chamar /serverCommand
. Cada token expresso é de uso único. Chamadas para /serverCommand
que usam um token expresso válido retornam um novo token expresso.
Na implementação do codelab, como o token expresso é gerado de maneira exclusiva no servidor, os comandos ainda estão protegidos contra ataques de repetição. No entanto, os tokens expressos são menos seguros, já que omitem a proteção contra hash da modificação do comando e não detectam modificações do dispositivo que ocorreram após a chamada inicial para a API Play Integrity.
Arquitetura do servidor do codelab
Neste codelab, você pode instanciar um servidor usando o programa de servidor de exemplo criado em Kotlin usando o framework Ktor (link em inglês). O projeto inclui arquivos de configuração para implantar no Google Cloud App Engine. As instruções deste codelab abrangem a criação e a implantação no App Engine. Se você usa outro provedor de nuvem, o Ktor tem instruções de implantação (em inglês) para vários serviços de nuvem. É possível modificar o projeto e implantá-lo no serviço que preferir. A implantação na sua própria instância de servidor local também é uma opção.
Não é necessário usar o código de exemplo para seu servidor. Se você tiver um framework de aplicativos da Web preferido, é possível implementar os endpoints /getRandom
e /performCommand
no seu próprio framework usando o servidor de exemplo do codelab como guia.
Design do cliente
As três versões do cliente (C++, Kotlin e Unity) apresentam uma interface do usuário semelhante.
O botão Request random (solicitar aleatório) chama o endpoint /getRandom
no servidor. O resultado aparece em um campo de texto. Isso pode ser usado para verificar a conexão e a função do servidor antes de adicionar a integração da Play Integrity.
O botão Call server with integrity check (chamar servidor para verificação de integridade) não faz nada no início do codelab. Siga as etapas para adicionar o código nestas operações:
- Chamar
/getRandom
para receber um número aleatório. - Gerar um valor de uso único.
- Criar uma solicitação da Play Integrity com o valor de uso único.
- Chamar
/performCommand
usando o token gerado pela solicitação de Play Integrity. - Mostrar os resultados de
/performCommand
.
Os resultados do comando aparecem em um campo de texto. Para um comando bem-sucedido, um resumo das informações de veredito do dispositivo retornadas pela verificação de Play Integrity é mostrado.
O botão Call server with express token (chamar servidor com token expresso) aparece após uma operação bem-sucedida do botão Call server with integrity check. Ele chama /performCommand
usando o token expresso do /performCommand
anterior. Um campo de texto é usado para mostrar o sucesso ou a falha do comando. O valor de um token expresso retornado aparece no campo de texto usado para números aleatórios.
As funções da API Play Integrity que informam erros fazem isso retornando um código de erro. Para mais detalhes sobre esses códigos de erro, consulte a documentação da Play Integrity. Alguns erros podem ser causados por condições do ambiente, como uma conexão de Internet instável ou um dispositivo sobrecarregado. Para esses erros, pense em incluir uma opção para tentar de novo com espera exponencial. Neste codelab, os erros da Play Integrity são mostrados no Logcat.
4. Como configurar o Google Cloud App Engine
Para usar o Google Cloud, siga estas etapas:
- Inscreva-se no Google Cloud Platform. Use a mesma Conta do Google registrada no Play Console.
- Crie uma conta de faturamento.
- Instale e inicialize o SDK Google Cloud.
Use o CLI do Google Cloud recém-instalado para executar estes comandos:
- Instale a extensão do App Engine para Java:
gcloud components install app-engine-java
- Crie um novo projeto do Cloud, substituindo
$yourname
por um identificador exclusivo neste comando:gcloud projects create $yourprojectname --set-as-default
- Crie um aplicativo do App Engine no projeto do Cloud:
gcloud app create
5. Implantar o servidor
Definir o nome do pacote do aplicativo
Nesta etapa, você vai adicionar o nome do pacote do aplicativo ao código do servidor. Em um editor de texto, abra o arquivo de origem ValidateCommand.kt
. Ele está localizado neste diretório:
add-play-integrity-codelab/server/src/main/kotlin/com/google/play/integrity/codelab/server/util
Encontre a linha abaixo, substitua o texto do marcador de posição por um identificador de pacote exclusivo e salve o arquivo:
const val APPLICATION_PACKAGE_IDENTIFIER = "com.your.app.package"
Mais adiante, você definirá esse identificador no projeto do cliente antes de fazer upload do app no Play Console.
Criar o servidor e implantar no App Engine
Use o Google Cloud CLI para executar o comando abaixo no diretório add-play-integrity/server
para criar e implantar o servidor:
No Linux ou no macOS:
./gradlew appengineDeploy
No Microsoft Windows:
gradlew.bat appengineDeploy
Anote o local do Serviço implantado que aparecerá na saída de uma implantação bem-sucedida. Você precisará desse URL para configurar o cliente para se comunicar com o servidor.
Verificar a implantação
Use o Google Cloud CLI para executar o comando abaixo e verificar se o servidor está funcionando corretamente:
gcloud app browse
Esse comando abrirá um navegador da Web e o URL raiz. O servidor de exemplo mostrará uma mensagem Hello World! quando acessado pelo URL raiz.
6. Configurar o app no Play Console
Configurar a integridade do app no Play Console
Se você já tiver uma entrada de app no Play Console, poderá usá-la para este codelab. Como alternativa, siga as etapas para criar um novo app no Play Console. Depois de selecionar ou criar o app no Play Console, você precisará configurar a integridade do app. No menu do Play Console à esquerda, acesse Integridade do app na seção Versão.
Criar e vincular o projeto do Google Cloud
Clique no botão Vincular projeto do Cloud. Selecione o projeto do Google Cloud usado com o servidor e clique no botão Vincular projeto.
Acesso ao Google Cloud para seu servidor
O servidor de back-end precisa descriptografar o token de integridade gerado no cliente pela API Play Integrity. A Play Integrity oferece duas opções de gerenciamento: chaves geradas e gerenciadas pelo Google ou chaves fornecidas pelo desenvolvedor. Este codelab usa o comportamento padrão recomendado das chaves gerenciadas pelo Google.
Com chaves gerenciadas pelo Google, seu servidor de back-end transmite o token de integridade criptografado aos servidores do Google Play para descriptografia. O servidor do codelab usa a biblioteca de cliente das APIs do Google (link em inglês) para se comunicar com os servidores do Google Play.
Agora que o servidor está funcionando e você configurou o app no Play Console, comece a personalizar os clientes correspondentes às plataformas escolhidas. Todas as etapas de uma determinada plataforma são agrupadas para que você possa pular as instruções para as plataformas que não estiver usando.
7. Criar e executar o cliente (C++)
Execute o Android Studio. Na janela Welcome to Android Studio, clique no botão Open e abra o projeto do Android Studio localizado em add-play-integrity-codelab/cpp/start
.
Atualizar o ID do aplicativo
Antes de fazer upload de uma versão para o Google Play, é necessário alterar o ID do aplicativo do padrão para algo único. Siga estas etapas:
- No painel Project do Android Studio, encontre e abra o arquivo
build.gradle
emstart/app
. - Encontre a instrução
applicationId
. - Mude
com.google.play.integrity.codelab.cpp
para o nome do pacote escolhido ao implantar o servidor e salve o arquivo. - Na parte de cima do arquivo, um banner aparecerá informando que os arquivos do Gradle mudaram. Clique em Sync Now para recarregar e sincronizar o arquivo de novo.
- No painel Project do Android Studio, abra o arquivo
AndroidManifest.xml
emstart/app/src/main
. - Encontre a instrução
package="com.example.google.codelab.playintegritycpp"
. - Substitua
com.example.google.codelab.playintegritycpp
pelo nome do pacote exclusivo e salve o arquivo. - No painel Project do Android Studio, abra o arquivo
PlayIntegrityCodelabActivity
emstart/app/src/main/java/com.example.google.codelab.playintegritycpp
. - Encontre a instrução
package com.example.google.codelab.playintegritycpp
. - Substitua
com.example.google.codelab.playintegritycpp
pelo nome de pacote exclusivo. - Clique com o botão direito do mouse no nome do novo pacote e escolha Show Context Actions.
- Escolha Move to (novo nome do pacote).
- Se aparecer, escolha o botão Sync Now na parte de cima do arquivo.
Atualizar os URLs do servidor
O projeto precisa ser atualizado para apontar para os locais do URL em que você implantou o servidor.
- No painel Project do Android Studio, abra o arquivo
server_urls.hpp
emstart/app/src/main/cpp
. - Adicione o URL raiz mostrado quando você implantou o servidor nas definições de
GET_RANDOM_URL
ePERFORM_COMMAND_URL
e salve o arquivo.
O resultado será semelhante a este:
constexpr char GET_RANDOM_URL[] = "https://your-play-integrity-server.uc.r.appspot.com/getRandom";
constexpr char PERFORM_COMMAND_URL[] = "https://your-play-integrity-server.uc.r.appspot.com/performCommand";
O URL específico varia de acordo com o nome do projeto e a região do Google Cloud usada para implantar o servidor.
Criar e executar
Conectar um dispositivo Android configurado para desenvolvimento. No Android Studio, crie o projeto e execute no dispositivo conectado. O app ficará assim:
Toque no botão Request Random para executar um código que faz uma solicitação HTTP ao seu servidor para solicitar um número aleatório. Após um breve atraso, o número aleatório aparecerá na tela:
Se uma mensagem de erro aparecer, a saída do painel Logcat poderá conter mais detalhes.
Depois de verificar se está se comunicando com o servidor e extraindo um valor aleatório, você pode começar a integrar a API Play Integrity.
8. Adicionar a Play Integrity ao projeto (C++)
Fazer o download do SDK
Você precisará fazer o download e extrair o SDK do Play Core. Siga estas etapas:
- Faça o download do SDK da Play Core empacotado em um arquivo .zip na página do SDK nativo da Play Core.
- Extraia o arquivo ZIP.
- Verifique se o diretório recém-extraído chama
play-core-native-sdk
e copie ou mova-o para o diretórioadd-play-integrity-codelab/cpp/start
.
Atualizar o build.gradle
No painel Project do Android Studio, abra o arquivo build.gradle
do módulo no diretório start/app
.
Adicione, abaixo da linha apply plugin: 'com.android.application'
, a linha mostrada no snippet:
def playcoreDir = file("../play-core-native-sdk")
Localize o bloco externalNativeBuild
no bloco defaultConfig
e mude a instrução arguments
no bloco cmake
para corresponder ao seguinte:
arguments "-DANDROID_STL=c++_shared",
"-DPLAYCORE_LOCATION=$playcoreDir"
Adicione o código abaixo ao final do bloco android
:
buildTypes {
release {
proguardFiles getDefaultProguardFile("proguard-android.txt"),
"proguard-rules.pro",
"$playcoreDir/proguard/common.pgcfg",
"$playcoreDir/proguard/integrity.pgcfg"
}
}
Adicione a linha abaixo dentro e ao final do bloco dependencies
:
implementation files("$playcoreDir/playcore.aar")
Salve as mudanças. Na parte de cima do arquivo, um banner aparecerá informando que os arquivos do Gradle mudaram. Clique em Sync Now para recarregar e sincronizar o arquivo de novo.
Atualizar CMakeList.txt
No painel Project do Android Studio, abra o arquivo CMakeLists.txt
no diretório start/app/src/main/cpp
.
Adicione, abaixo dos comandos find_package
, estas linhas:
include("${PLAYCORE_LOCATION}/playcore.cmake")
add_playcore_static_library()
Localize a linha target_include_directories(game PRIVATE
e adicione esta linha abaixo dela:
${PLAYCORE_LOCATION}/include
Localize a linha target_link_libraries(game
e adicione esta linha abaixo dela:
playcore
Salve o arquivo. Na parte de cima do arquivo, vai aparecer um banner informando que os arquivos de build externos mudaram. Clique em Sync Now para recarregar e sincronizar o arquivo de novo.
Escolha Make Project no menu Build e verifique se o projeto foi criado.
9. Fazer uma solicitação de integridade (C++)
O app recebe informações de integridade usando a API Play Integrity para solicitar um token, que você envia ao servidor para descriptografia e verificação. Agora você vai adicionar um código ao projeto para inicializar a API Play Integrity e usá-la para fazer uma solicitação de integridade.
Adicionar um botão de comando
Em um app ou jogo real, você pode realizar uma verificação de integridade antes de atividades específicas, como fazer uma compra na loja ou participar de uma sessão de jogo multiplayer. Neste codelab, adicionaremos um botão à interface para acionar manualmente uma verificação de integridade e chamar o servidor, transmitindo o token da Play Integrity gerado.
O projeto do codelab contém uma classe ClientManager
, definida nos arquivos de origem client_manager.cpp
e client_manager.hpp
. Por conveniência, esse arquivo já foi adicionado ao projeto, mas não tem o código de implementação que você vai adicionar agora.
Para adicionar o botão da interface, comece abrindo o arquivo demo_scene.cpp
no painel Project do Android Studio, no diretório start/app/src/main/cpp
. Primeiro, localize a função DemoScene::GenerateCommandIntegrity()
vazia e adicione este código:
const auto commandResult =
NativeEngine::GetInstance()->GetClientManager()->GetOperationResult();
if (commandResult != ClientManager::SERVER_OPERATION_PENDING) {
if (ImGui::Button("Call server with integrity check")) {
DoCommandIntegrity();
}
}
Em seguida, localize a função DemoScene::DoCommandIntegrity()
vazia. Adicione o código abaixo.
ClientManager *clientManager = NativeEngine::GetInstance()->GetClientManager();
clientManager->StartCommandIntegrity();
mServerRandom = clientManager->GetCurrentRandomString();
Salve o arquivo. Agora, você vai atualizar a classe ClientManager
do exemplo para adicionar a funcionalidade da Play Integrity.
Atualizar o arquivo principal do gerenciador
Abra o arquivo client_manager.hpp
no painel Project do Android Studio, no diretório start/app/src/main/cpp
.
Inclua o arquivo principal da API Play Integrity adicionando a seguinte linha abaixo da linha #include "util.hpp"
:
#include "play/integrity.h"
A classe ClientManager
precisará conter referências a objetos IntegrityTokenRequest
e IntegrityTokenResponse
. Adicione as linhas mostradas no snippet à parte de baixo da definição da classe ClientManager
:
IntegrityTokenRequest *mTokenRequest;
IntegrityTokenResponse *mTokenResponse;
Salve o arquivo.
Inicializar e encerrar a Play Integrity
No painel Project do Android Studio, abra o arquivo client_manager.cpp
no diretório start/app/src/main/cpp
.
Encontre o construtor ClientManager::ClientManager()
. Substitua a instrução mInitialized = false;
por este código:
mTokenRequest = nullptr;
mTokenResponse = nullptr;
const android_app *app = NativeEngine::GetInstance()->GetAndroidApp();
const IntegrityErrorCode errorCode = IntegrityManager_init(app->activity->vm,
app->activity->javaGameActivity);
if (errorCode == INTEGRITY_NO_ERROR) {
mInitialized = true;
} else {
mInitialized = false;
ALOGE("Play Integrity initialization failed with error: %d", errorCode);
ALOGE("Fatal Error: Play Integrity is unavailable and cannot be used.");
}
Adicione o código abaixo ao destrutor ClientManager::~ClientManager()
:
if (mInitialized) {
IntegrityManager_destroy();
mInitialized = false;
}
Solicitar um token de integridade
A solicitação de um token de integridade da API Play Integrity é uma operação assíncrona. Você precisará criar um objeto de solicitação de token, atribuir um valor de uso único a ele e fazer a solicitação de token. Para fazer isso, adicione o código abaixo à função ClientManager::StartCommandIntegrity()
vazia:
// Only one request can be in-flight at a time
if (mStatus != CLIENT_MANAGER_REQUEST_TOKEN) {
mResult = SERVER_OPERATION_PENDING;
// Request a fresh random
RequestRandom();
if (mValidRandom) {
GenerateNonce();
IntegrityTokenRequest_create(&mTokenRequest);
IntegrityTokenRequest_setNonce(mTokenRequest, mCurrentNonce.c_str());
const IntegrityErrorCode errorCode =
IntegrityManager_requestIntegrityToken(mTokenRequest, &mTokenResponse);
if (errorCode != INTEGRITY_NO_ERROR) {
// Log the error, in a real application, for potentially
// transient errors such as network connectivity, you should
// add retry with an exponential backoff
ALOGE("Play Integrity returned error: %d", errorCode);
CleanupRequest();
mStatus = CLIENT_MANAGER_IDLE;
} else {
mStatus = CLIENT_MANAGER_REQUEST_TOKEN;
}
}
}
Como a solicitação de token opera de forma assíncrona, será necessário verificar a conclusão dela. A classe ClientManager
tem uma função Update()
, que é chamada como parte da repetição de atualização do app. Adicione o código abaixo à função ClientManager::Update()
para verificar o status da solicitação de token e processar o resultado depois que ele for concluído:
if (mStatus == CLIENT_MANAGER_REQUEST_TOKEN) {
IntegrityResponseStatus responseStatus = INTEGRITY_RESPONSE_UNKNOWN;
const IntegrityErrorCode errorCode =
IntegrityTokenResponse_getStatus(mTokenResponse, &responseStatus);
if (errorCode != INTEGRITY_NO_ERROR) {
// Log the error, in a real application, for potentially
// transient errors such as network connectivity, you should
// add retry with an exponential backoff
ALOGE("Play Integrity returned error: %d", errorCode);
CleanupRequest();
mStatus = CLIENT_MANAGER_IDLE;
} else if (responseStatus == INTEGRITY_RESPONSE_COMPLETED) {
std::string tokenString = IntegrityTokenResponse_getToken(mTokenResponse);
SendCommandToServer(tokenString);
CleanupRequest();
mStatus = CLIENT_MANAGER_RESPONSE_AVAILABLE;
}
}
Limpar os objetos de solicitação
Você precisa informar à API Play Integrity quando terminar de lidar com objetos de solicitação e resposta de token para que ela possa destruí-los e recuperar os recursos. Adicione o código abaixo à função ClientManager::CleanupRequest()
:
if (mTokenResponse != nullptr) {
IntegrityTokenResponse_destroy(mTokenResponse);
mTokenResponse = nullptr;
}
if (mTokenRequest != nullptr) {
IntegrityTokenRequest_destroy(mTokenRequest);
mTokenRequest = nullptr;
}
Escolha Make Project no menu Build e verifique se o projeto foi criado.
10. Enviar o token para o servidor (C++)
Agora você vai adicionar um código para enviar um comando ao seu servidor que inclui o token de integridade. Você também vai adicionar um código para processar o resultado.
Adicione o código abaixo à função ClientManager::SendCommandToServer()
:
// Note that for simplicity, we are doing HTTP operations as
// synchronous blocking instead of managing them from a
// separate network thread
HTTPClient client;
std::string errorString;
// Manually construct the json payload for ServerCommand
std::string payloadString = COMMAND_JSON_PREFIX;
payloadString += TEST_COMMAND;
payloadString += COMMAND_JSON_TOKEN;
payloadString += token;
payloadString += COMMAND_JSON_SUFFIX;
auto result = client.Post(PERFORM_COMMAND_URL, payloadString, &errorString);
if (!result) {
ALOGE("SendCommandToServer Curl reported error: %s", errorString.c_str());
mResult = SERVER_OPERATION_NETWORK_ERROR;
} else {
ALOGI("SendCommandToServer result: %s", (*result).c_str())
// Preset to success, ParseResult will set a failure result if the parsing
// errors.
mResult = SERVER_OPERATION_SUCCESS;
ParseResult(*result);
}
Adicione o código abaixo à função ClientManager::ParseResult()
:
bool validJson = false;
JsonLookup jsonLookup;
if (jsonLookup.ParseJson(resultJson)) {
// Look for all of our needed fields in the returned json
auto commandSuccess = jsonLookup.GetBoolValueForKey(COMMANDSUCCESS_KEY);
if (commandSuccess) {
auto diagnosticString = jsonLookup.GetStringValueForKey(DIAGNOSTICMESSAGE_KEY);
if (diagnosticString) {
auto expressString = jsonLookup.GetStringValueForKey(EXPRESSTOKEN_KEY);
if (expressString) {
if (*commandSuccess) {
// Express token only valid if the server reports the command succeeded
mValidExpressToken = true;
} else {
mValidExpressToken = false;
mResult = SERVER_OPERATION_REJECTED_VERDICT;
}
mCurrentSummary = *diagnosticString;
mCurrentExpressToken = *expressString;
validJson = true;
}
}
}
}
if (!validJson) {
mResult = SERVER_OPERATION_INVALID_RESULT;
}
Agora você vai gerar um pacote de app assinado e fazer upload dele ao Play Console para testar o app.
11. Criar e fazer upload (C++)
Criar e configurar um keystore para o app
O Android exige que todos os apps sejam assinados digitalmente com um certificado antes de serem instalados ou atualizados em um dispositivo.
Criaremos um Keystore para o app neste codelab. Se você estiver publicando uma atualização de um jogo atual, reutilize o mesmo Keystore que usou para lançar versões anteriores do app.
Criar um keystore e um pacote de app de lançamento
Siga as etapas em Keystore com o Android Studio para criar um keystore e usá-lo para gerar um build de lançamento assinado do jogo. No Android Studio, escolha Generate Signed Bundle / APK no menu Build para iniciar o processo de build. Escolha App Bundle quando aparecer a opção para selecionar um Android App Bundle ou APK. No final do processo, você terá um arquivo .aab adequado para upload ao Google Play Console.
Fazer upload para o Play Console
Depois de criar um arquivo de pacote de app, faça upload dele para o Play Console. Recomendamos usar a faixa de teste interno para facilitar o acesso rápido ao build.
Executar o build de teste
Agora, faça o download e execute o build de teste na Play Store. No momento, há um código marcador de posição que mostra o sucesso na função que enviará o token de integridade para seu servidor. Assim, a inicialização de uma verificação de integridade precisa ser bem-sucedida e ter este resultado:
Parabéns, você integrou a Play Integrity a um app C++. Continue para outros exemplos de cliente ou vá para o final deste codelab.
12. Criar e executar o cliente (Unity)
O projeto Unity do codelab foi criado usando o Unity 2020 LTS (2020.3.31f1), mas é compatível com versões mais recentes do Unity. O plug-in da Play Integrity para Unity é compatível com o Unity 2018 LTS e versões mais recentes.
Configuração do projeto
Siga estas etapas:
- No Unity Hub ou Unity Editor, abra o projeto do Unity localizado em
add-play-integrity-codelab/unity/start
. - Depois que o projeto for carregado, selecione Build Settings… no menu File do Unity.
- Na janela Build Settings, mude a plataforma para Android.
- Na janela Build Settings, clique no botão Player Settings….
- Na janela Project Settings, com a categoria Player selecionada, procure a seção Settings for Android. Abra a lista Other Settings.
- Encontre a entrada Package Name em Identification.
- Mude o nome do pacote para o identificador que você escolheu ao implantar o servidor.
- Feche a janela Project Settings.
- Selecione Save Project no menu File do Unity.
Atualizar URLs do servidor
O projeto precisa ser atualizado para apontar para os locais do URL em que você implantou o servidor. Para fazer isso, siga estas etapas:
- Abra o arquivo
PlayIntegrityController.cs
na pastaScripts
em um ambiente de desenvolvimento integrado ou em um editor de texto. - Mude os valores das variáveis
URL_GETRANDOM
eURL_PERFORMCOMMAND
para apontar para seu servidor. - Salve o arquivo.
O resultado será semelhante a este:
private readonly string URL_GETRANDOM = "https://your-play-integrity-server.uc.r.appspot.com/getRandom";
private readonly string URL_PERFORMCOMMAND = "https://your-play-integrity-server.uc.r.appspot.com/performCommand";
O URL específico varia de acordo com o nome do projeto e a região do Google Cloud usada para implantar o servidor.
Testar a funcionalidade do servidor
Você pode testar a funcionalidade do servidor executando o projeto no editor do Unity. Siga estas etapas:
- Abra o arquivo de cena
SampleScene
localizado na pastaScenes
. - Clique no botão Play no editor.
- Clique no botão Request Random na tela Game.
Após um breve atraso, o valor aleatório vai aparecer na tela, semelhante ao seguinte:
13. Adicionar o plug-in da Play Integrity ao projeto (Unity)
Fazer o download do plug-in
Em um navegador da Web, abra a página de versões (link em inglês) do repositório GitHub dos plug-ins do Unity para o Google Play. Use a versão mais recente dos plug-ins. Faça o download do arquivo com.google.play.integrity-<version>
.unitypackage
para a Play Integrity na lista Assets.
Instalar o plug-in
Na barra de menus do editor do Unity, selecione Assets -> Import Package -> Custom Package… e abra o arquivo .unitypackage
que você transferiu por download. Clique no botão Import depois que a janela Import Unity Package aparecer.
O plug-in inclui o External Dependency Manager (link em inglês) para Unity (EDM4U). O EDM4U implementa a resolução de dependências automática para os componentes Java necessários para usar a Play Integrity. Quando for solicitado que você ative a resolução automática de dependências, clique no botão Enable.
É altamente recomendável usar a resolução automática. Problemas de dependência podem resultar na falha da criação ou execução do projeto.
14. Fazer uma solicitação de integridade (Unity)
Criar uma solicitação de integridade
Para criar uma solicitação de integridade, siga estas etapas.
- Abra o arquivo
PlayIntegrityController.cs
na pastaScripts
em um ambiente de desenvolvimento integrado ou em um editor de texto. - Adicione a linha abaixo ao bloco de instruções
using
na parte de cima do arquivo:
using Google.Play.Integrity;
- Encontre a função
RunIntegrityCommand()
e substitua a instruçãoyield return null;
por este código:
// Call our server to retrieve a random number.
yield return GetRandomRequest();
if (!string.IsNullOrEmpty(_randomString))
{
// Create an instance of an integrity manager.
var integrityManager = new IntegrityManager();
// Request the integrity token by providing a nonce.
var tokenRequest = new IntegrityTokenRequest(GenerateNonceString(_randomString,
TEST_COMMAND));
var requestIntegrityTokenOperation =
integrityManager.RequestIntegrityToken(tokenRequest);
// Wait for PlayAsyncOperation to complete.
yield return requestIntegrityTokenOperation;
// Check the resulting error code.
if (requestIntegrityTokenOperation.Error != IntegrityErrorCode.NoError)
{
// Log the error, in a real application, for potentially
// transient errors such as network connectivity, you should
// add retry with an exponential backoff
Debug.Log($@"IntegrityAsyncOperation failed with error:
{requestIntegrityTokenOperation.Error.ToString()}");
yield break;
}
// Get the response.
var tokenResponse = requestIntegrityTokenOperation.GetResult();
// Send the command to our server with a POST request, including the
// token, which will be decrypted and verified on the server.
yield return PostServerCommand(tokenResponse.Token);
}
Enviar o comando ao servidor
Continue editando o arquivo PlayIntegrityController.cs
, encontre a função PostServerCommand()
substitua a instrução yield return null;
por este código:
// Start a HTTP POST request to the performCommand URL, sending it the
// command and integrity token data provided by Play Integrity.
var serverCommand = new ServerCommand(TEST_COMMAND, tokenResponse);
var commandRequest = new UnityWebRequest(URL_PERFORMCOMMAND, "POST");
string commandJson = JsonUtility.ToJson(serverCommand);
byte[] jsonBuffer = Encoding.UTF8.GetBytes(commandJson);
commandRequest.uploadHandler = new UploadHandlerRaw(jsonBuffer);
commandRequest.downloadHandler = new DownloadHandlerBuffer();
commandRequest.SetRequestHeader(CONTENT_TYPE, JSON_CONTENT);
yield return commandRequest.SendWebRequest();
if (commandRequest.result == UnityWebRequest.Result.Success)
{
// Parse the command result Json
var commandResult = JsonUtility.FromJson<CommandResult>(
commandRequest.downloadHandler.text);
if (commandResult != null)
{
resultLabel.text = commandResult.diagnosticMessage;
_expressToken = commandResult.expressToken;
if (commandResult.commandSuccess)
{
resultLabel.color = Color.green;
expressButton.SetActive(true);
}
else
{
resultLabel.color = Color.black;
expressButton.SetActive(false);
}
}
else
{
Debug.Log("Invalid CommandResult json");
}
}
else
{
Debug.Log($"Web request error on processToken: {commandRequest.error}");
}
Salve o arquivo.
15. Criar e fazer upload (Unity)
Use o editor Android Keystore Manager (link em inglês) do Unity para configurar a assinatura do seu build para upload no Play Console.
Depois de configurar as informações de assinatura, siga estas etapas:
- Selecione Build -> Build Settings… no menu File do Unity.
- Confira se a
SampleScene
está incluída na lista Scenes in Build. - Verifique se a caixa Build App Bundle (Google Play) está marcada.
- Clique no botão Build e escolha um nome para o arquivo de exportação.
Depois de criar um arquivo de pacote de app, faça upload dele para o Play Console. Recomendamos usar a faixa de teste interno para facilitar o acesso rápido ao build.
Agora você pode fazer o download e instalar seu build para executar uma verificação de integridade. Os resultados serão semelhantes a estes:
Parabéns! Você integrou a Play Integrity a um projeto do mecanismo do Unity. Continue para outros exemplos de cliente ou vá para o final deste codelab.
16. Criar e executar o projeto (Kotlin)
Execute o Android Studio. Na janela Welcome to Android Studio, clique no botão Open e abra o projeto do Android Studio localizado em add-play-integrity-codelab/kotlin/start
.
Atualizar o ID do aplicativo
Antes de fazer upload de uma versão para o Google Play, é necessário alterar o ID do aplicativo do padrão para algo único. Siga estas etapas:
- No painel Project do Android Studio, abra o arquivo
build.gradle
do móduloPlayIntegrityCodelab.app
. - Encontre a instrução
applicationId
. - Mude
com.example.google.codelab.playintegritykotlin
para o identificador que você escolheu ao implantar o servidor e salve o arquivo. - Na parte de cima do arquivo, um banner aparecerá informando que os arquivos do Gradle mudaram. Clique em Sync Now para recarregar e sincronizar o arquivo de novo.
Atualizar os URLs do servidor
O projeto precisa ser atualizado para apontar para o local do URL em que você implantou o servidor. Para fazer isso, siga estas etapas:
- No painel Project do Android Studio, abra o arquivo
IntegrityServer
emstart/app/src/main/java/com.example.google.codelab.playintegritykotlin/integrity
. - Mude o URL de
‘https://your.play-integrity.server.com'
para o URL de base do seu servidor e salve o arquivo.
O resultado será semelhante a este:
private val SERVER_URL: String = "https://your-play-integrity-server.uc.r.appspot.com"
O URL específico varia de acordo com o nome do projeto e a região do Google Cloud usada para implantar o servidor.
Criar e executar
Conectar um dispositivo Android configurado para desenvolvimento. No Android Studio, crie o projeto e execute no dispositivo conectado. O app ficará assim:
Na inicialização, o app chama o endpoint getRandom
no servidor e mostra o resultado. Se ocorrer um erro, como um URL incorreto ou o servidor não estiver funcionando, uma caixa de diálogo de erro vai aparecer. Selecione o botão Request Random para receber um novo número aleatório do servidor. O botão Call server with integrity check ainda não faz nada. Você vai adicionar essa funcionalidade nas próximas seções.
17. Adicionar a Play Integrity ao projeto (Kotlin)
Para adicionar a biblioteca Play Integrity e as dependências de suporte ao projeto, siga estas etapas:
- No painel Project do Android Studio, abra o arquivo
build.gradle
emstart/app
. - Localize o bloco
dependencies
na parte de baixo do arquivo. - Adicione estas linhas à parte de baixo do bloco
dependencies
:
implementation "com.google.android.play:integrity:1.0.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.1"
- Salve o arquivo.
- Na parte de cima do arquivo, um banner aparecerá informando que os arquivos do Gradle mudaram. Clique em Sync Now para recarregar e sincronizar o arquivo de novo.
O exemplo de Kotlin usa corrotinas. A biblioteca kotlinx-coroutines-play-services
adiciona extensões que facilitam o trabalho com objetos Task
assíncronos da Play Integrity de dentro de corrotinas Kotlin.
18. Fazer uma solicitação de integridade (Kotlin)
No painel Project do Android Studio, abra o arquivo IntegrityServer
em start/app/src/main/java/com.example.google.codelab.playintegritykotlin/integrity
. Na parte de baixo do arquivo, há uma função integrityCommand
vazia. A interface chama essa função quando o botão Call server with integrity check é pressionado.
Adicione o código à função integrityCommand
para realizar estas operações:
- Extrair um novo número aleatório do servidor para usar ao criar um valor de uso único para associar à verificação de integridade.
- Chamar a API Play Integrity para fazer uma solicitação de integridade e receber um token de integridade com os resultados.
- Enviar o comando e o token de integridade ao servidor usando uma solicitação HTTP
POST
. - Processar e mostrar os resultados.
Adicione o código abaixo à função integrityCommand
vazia:
// Set our state to working to trigger a switch to the waiting UI
_serverState.emit(ServerState(
ServerStatus.SERVER_STATUS_WORKING))
// Request a fresh random from the server as part
// of the nonce we will generate for the request
var integrityRandom = IntegrityRandom("", 0U)
try {
val returnedRandom = httpClient.get<IntegrityRandom>(
SERVER_URL + "/getRandom")
integrityRandom = returnedRandom
} catch (t: Throwable) {
Log.d(TAG, "getRandom exception " + t.message)
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_UNREACHABLE,
IntegrityRandom("", 0U)))
}
// If we have a random, we are ready to request an integrity token
if (!integrityRandom.random.isNullOrEmpty()) {
val nonceString = GenerateNonce.GenerateNonceString(TEST_COMMAND,
integrityRandom.random)
// Create an instance of an IntegrityManager
val integrityManager = IntegrityManagerFactory.create(context)
// Use the nonce to configure a request for an integrity token
try {
val integrityTokenResponse: Task<IntegrityTokenResponse> =
integrityManager.requestIntegrityToken(
IntegrityTokenRequest.builder()
.setNonce(nonceString)
.build()
)
// Wait for the integrity token to be generated
integrityTokenResponse.await()
if (integrityTokenResponse.isSuccessful && integrityTokenResponse.result != null) {
// Post the received token to our server
postCommand(integrityTokenResponse.result!!.token(), integrityRandom)
} else {
Log.d(TAG, "requestIntegrityToken failed: " +
integrityTokenResponse.result.toString())
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_FAILED_TO_GET_TOKEN))
}
} catch (t: Throwable) {
Log.d(TAG, "requestIntegrityToken exception " + t.message)
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_FAILED_TO_GET_TOKEN))
}
}
O código para POST
(enviar) o comando para seu servidor foi dividido em uma função postCommand
separada. Adicione o código abaixo à função postCommand
vazia:
try {
val commandResult = httpClient.post<CommandResult>(
SERVER_URL + "/performCommand") {
contentType(ContentType.Application.Json)
body = ServerCommand(TEST_COMMAND, tokenString)
}
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_REACHABLE,
integrityRandom,
commandResult.diagnosticMessage,
commandResult.commandSuccess,
commandResult.expressToken))
} catch (t: Throwable) {
Log.d(TAG, "performCommand exception " + t.message)
_serverState.emit(ServerState(ServerStatus.SERVER_STATUS_UNREACHABLE))
}
Resolva todas as importações ausentes e salve o arquivo.
19. Mostrar os resultados (Kotlin)
Atualizar a interface com o resumo do veredito
No momento, a interface mostra o texto do marcador de posição para o resumo do veredito de integridade. Para substituir o marcador de posição pelo resumo real, siga estas etapas:
- No painel Project do Android Studio, abra o arquivo
MainView.kt
emstart/app/src/main/java/com.example.google.codelab.playintegritykotlin/ui/main
. - No final da função MainUI, localize e substitua a instrução
text = "None",
por este código:
text = state.serverState.serverVerdict,
- Resolva todas as importações ausentes e salve o arquivo.
20. Criar e fazer upload (Kotlin)
Criar e configurar um keystore para o app
O Android exige que todos os apps sejam assinados digitalmente com um certificado antes de serem instalados ou atualizados em um dispositivo.
Criaremos um Keystore para o app neste codelab. Se você estiver publicando uma atualização de um jogo atual, reutilize o mesmo Keystore que usou para lançar versões anteriores do app.
Criar um keystore e um pacote de app de lançamento
Siga as etapas em Keystore com o Android Studio para criar um keystore e usá-lo para gerar um build de lançamento assinado do jogo. No Android Studio, escolha Generate Signed Bundle / APK no menu Build para iniciar o processo de build. Escolha App Bundle quando aparecer a opção para selecionar um Android App Bundle ou APK. No final do processo, você terá um arquivo .aab adequado para upload ao Google Play Console.
Fazer upload para o Play Console
Depois de criar um arquivo de pacote de app, faça upload dele para o Play Console. Recomendamos usar a faixa de teste interno para facilitar o acesso rápido ao build.
Executar o build de teste
Agora, faça o download e execute o build de teste na Play Store. A seleção do botão Call server with integrity check vai funcionar e resultará nesta tela:
21. Parabéns
Parabéns! Você adicionou a Play Integrity a um app Android.