Correção

Nesta página, descrevemos como lidar com problemas com vereditos de integridade.

Quando um token de integridade é solicitado, você tem a opção de mostrar uma caixa de diálogo do Google Play para o usuário. Você pode mostrar a caixa de diálogo quando houver um ou mais problemas com o veredito de integridade. A caixa de diálogo aparece na parte de cima do app e solicita que os usuários resolvam a causa do problema. Depois que a caixa de diálogo for fechada, confira se o problema foi corrigido fazendo outra solicitação para a API Integrity.

Caixas de diálogo de integridade

GET_LICENSED (código de tipo 1)

Problema de veredito

Quando appLicensingVerdict == "UNLICENSED". Isso significa que a conta do usuário não está licenciada. Em outras palavras, a pessoa não instalou nem comprou o app pelo Google Play.

Correção

Você pode mostrar a caixa de diálogo GET_LICENSED para pedir que o usuário faça o download do seu app no Google Play. Se o usuário aceitar, a conta de usuário será licenciada (appLicensingVerdict == "LICENSED"). O app será adicionado à biblioteca do Google Play do usuário, e a plataforma poderá fornecer atualizações do app em seu nome.

Exemplo de UX

Caixa de diálogo GET_LICENSED do Google Play

CLOSE_UNKNOWN_ACCESS_RISK (código de tipo 2)

Problema de veredito

Quando environmentDetails.appAccessRiskVerdict.appsDetected contém "UNKNOWN_CAPTURING" ou "UNKNOWN_CONTROLLING", significa que há apps desconhecidos em execução no dispositivo que podem estar capturando a tela ou controlando o dispositivo.

Correção

Você pode mostrar a caixa de diálogo CLOSE_UNKNOWN_ACCESS_RISK para solicitar que o usuário feche todos os apps desconhecidos que podem estar capturando a tela ou controlando o dispositivo. Se o usuário tocar no botão Close all, todos esses apps serão fechados.

Exemplo de UX

Caixa de diálogo para o risco de acesso ao fechamento desconhecido

CLOSE_ALL_ACCESS_RISK (código de tipo 3)

Problema de veredito

Quando environmentDetails.appAccessRiskVerdict.appsDetected contém "KNOWN_CAPTURING", "KNOWN_CONTROLLING","UNKNOWN_CAPTURING" ou "UNKNOWN_CONTROLLING", significa que há apps em execução no dispositivo que podem estar capturando a tela ou controlando o dispositivo.

Correção

Você pode mostrar a caixa de diálogo CLOSE_ALL_ACCESS_RISK para pedir que o usuário feche todos os apps que podem estar capturando a tela ou controlando o dispositivo. Se o usuário tocar no botão Close all, todos esses apps serão fechados no dispositivo.

Exemplo de UX

Caixa de diálogo para fechar todos os riscos de acesso

Solicitar uma caixa de diálogo de integridade

Quando o cliente solicita um token de integridade, é possível usar o método oferecido no StandardIntegrityToken (API padrão) e na IntegrityTokenResponse (API clássica): showDialog(Activity activity, int integrityDialogTypeCode).

As etapas abaixo descrevem como usar a API Play Integrity para mostrar a caixa de diálogo GET_LICENSED:

  1. Solicite um token de integridade do app e o envie ao servidor. Você pode usar a solicitação padrão ou clássica.

    Kotlin

    // Request an integrity token
    val tokenResponse: StandardIntegrityToken = requestIntegrityToken()
    // Send token to app server and get response on what to do next
    val yourServerResponse: YourServerResponse = sendToServer(tokenResponse.token())  

    Java

    // Request an integrity token
    StandardIntegrityToken tokenResponse = requestIntegrityToken();
    // Send token to app server and get response on what to do next
    YourServerResponse yourServerResponse = sendToServer(tokenResponse.token());  

    Unity

    // Request an integrity token
    StandardIntegrityToken tokenResponse = RequestIntegrityToken();
    // Send token to app server and get response on what to do next
    YourServerResponse yourServerResponse = sendToServer(tokenResponse.Token); 

    Nativo

    /// Request an integrity token
    StandardIntegrityToken* response = requestIntegrityToken();
    /// Send token to app server and get response on what to do next
    YourServerResponse yourServerResponse = sendToServer(StandardIntegrityToken_getToken(response));
  2. No servidor, descriptografe o token de integridade e confira o campo appLicensingVerdict. Ele poderia ficar assim:

    // Licensing issue
    {
      ...
      accountDetails: {
          appLicensingVerdict: "UNLICENSED"
      }
    }
  3. Se o token contiver appLicensingVerdict: "UNLICENSED", responda ao cliente do app, solicitando que ele mostre a caixa de diálogo de licenciamento:

    Kotlin

    private fun getDialogTypeCode(integrityToken: String): Int{
      // Get licensing verdict from decrypted and verified integritytoken
      val licensingVerdict: String = getLicensingVerdictFromDecryptedToken(integrityToken)
    
      return if (licensingVerdict == "UNLICENSED") {
              1 // GET_LICENSED
          } else 0
    }

    Java

    private int getDialogTypeCode(String integrityToken) {
      // Get licensing verdict from decrypted and verified integrityToken
      String licensingVerdict = getLicensingVerdictFromDecryptedToken(integrityToken);
    
      if (licensingVerdict.equals("UNLICENSED")) {
        return 1; // GET_LICENSED
      }
      return 0;
    }

    Unity

    private int GetDialogTypeCode(string IntegrityToken) {
      // Get licensing verdict from decrypted and verified integrityToken
      string licensingVerdict = GetLicensingVerdictFromDecryptedToken(IntegrityToken);
    
      if (licensingVerdict == "UNLICENSED") {
        return 1; // GET_LICENSED
      }
      return 0;
    } 

    Nativo

    private int getDialogTypeCode(string integrity_token) {
      /// Get licensing verdict from decrypted and verified integrityToken
      string licensing_verdict = getLicensingVerdictFromDecryptedToken(integrity_token);
    
      if (licensing_verdict == "UNLICENSED") {
        return 1; // GET_LICENSED
      }
      return 0;
    }
  4. No seu app, chame showDialog com o código solicitado extraído do seu servidor:

    Kotlin

    // Show dialog as indicated by the server
    val showDialogType: Int? = yourServerResponse.integrityDialogTypeCode()
    if (showDialogType != null) {
      // Call showDialog with type code, the dialog will be shown on top of the
      // provided activity and complete when the dialog is closed.
      val integrityDialogResponseCode: Task<Int> =
      tokenResponse.showDialog(activity, showDialogType)
      // Handle response code, call the Integrity API again to confirm that
      // verdicts have been resolved.
    } 

    Java

    // Show dialog as indicated by the server
    @Nullable Integer showDialogType = yourServerResponse.integrityDialogTypeCode();
    if (showDialogType != null) {
      // Call showDialog with type code, the dialog will be shown on top of the
      // provided activity and complete when the dialog is closed.
      Task<Integer> integrityDialogResponseCode =
          tokenResponse.showDialog(activity, showDialogType);
      // Handle response code, call the Integrity API again to confirm that
      // verdicts have been resolved.
    }

    Unity

    IEnumerator ShowDialogCoroutine() {
      int showDialogType = yourServerResponse.IntegrityDialogTypeCode();
    
      // Call showDialog with type code, the dialog will be shown on top of the
      // provided activity and complete when the dialog is closed.
      var showDialogTask = tokenResponse.ShowDialog(showDialogType);
    
      // Wait for PlayAsyncOperation to complete.
      yield return showDialogTask;
    
      // Handle response code, call the Integrity API again to confirm that
      // verdicts have been resolved.
    } 

    Nativo

    // Show dialog as indicated by the server
    int show_dialog_type = yourServerResponse.integrityDialogTypeCode();
    if (show_dialog_type != 0) {
      /// Call showDialog with type code, the dialog will be shown on top of the
      /// provided activity and complete when the dialog is closed.
      StandardIntegrityErrorCode error_code =
          IntegrityTokenResponse_showDialog(response, activity, show_dialog_type);
    
      /// Proceed to polling iff error_code == STANDARD_INTEGRITY_NO_ERROR
      if (error_code != STANDARD_INTEGRITY_NO_ERROR)
      {
          /// Remember to call the *_destroy() functions.
          return;
      }
    
      /// Use polling to wait for the async operation to complete.
      /// Note, the polling shouldn't block the thread where the IntegrityManager
      /// is running.
    
      IntegrityDialogResponseCode* response_code;
      error_code = StandardIntegrityToken_getDialogResponseCode(response, response_code);
    
      if (error_code != STANDARD_INTEGRITY_NO_ERROR)
      {
          /// Remember to call the *_destroy() functions.
          return;
      }
    
      /// Handle response code, call the Integrity API again to confirm that
      /// verdicts have been resolved.
    }
  5. A caixa de diálogo aparece na parte de cima da atividade fornecida. Quando o usuário fecha a caixa de diálogo, a tarefa é concluída com um código de resposta.

  6. (Opcional) Solicite outro token para mostrar outras caixas de diálogo. Se você fizer solicitações padrão, será necessário ativar o provedor de token novamente para receber um novo veredito.