Vereditos de integridade

Esta página descreve como interpretar e trabalhar com o veredito de integridade retornado. Se você fizer uma solicitação de API padrão ou clássica, o veredito de integridade será retornado no mesmo formato com conteúdo semelhante. O veredito de integridade comunica informações sobre a validade de dispositivos, apps e contas. O servidor do app pode usar o payload resultante em um veredito descriptografado e verificado para determinar a melhor forma de prosseguir com uma ação ou solicitação específica no app.

Formato de veredito de integridade retornado

O payload é JSON em texto simples e contém sinais de integridade e informações fornecidas pelo desenvolvedor.

A estrutura geral do payload é esta:

{
  "requestDetails": { ... },
  "appIntegrity": { ... },
  "deviceIntegrity": { ... },
  "accountDetails": { ... },
  "environmentDetails": { ... }
}

Primeiro, confira se os valores no campo requestDetails correspondem aos da solicitação original antes de verificar cada veredito de integridade. As seções abaixo descrevem cada campo em mais detalhes.

Campo de detalhes da solicitação

O campo requestDetails contém informações sobre a solicitação, incluindo informações fornecidas pelo desenvolvedor no requestHash para solicitações padrão e no nonce para solicitações clássicas.

Para solicitações de API padrão:

"requestDetails": {
  // Application package name this attestation was requested for.
  // Note that this field might be spoofed in the middle of the request.
  "requestPackageName": "com.package.name",
  // Request hash provided by the developer.
  "requestHash": "aGVsbG8gd29scmQgdGhlcmU",
  // The timestamp in milliseconds when the integrity token
  // was requested.
  "timestampMillis": "1675655009345"
}

Esses valores precisam corresponder aos da solicitação original. Verifique a parte requestDetails do payload JSON, garantindo que o requestPackageName e o requestHash correspondam ao que foi enviado na solicitação original, conforme mostrado no snippet de código abaixo:

Kotlin

val requestDetails = JSONObject(payload).getJSONObject("requestDetails")
val requestPackageName = requestDetails.getString("requestPackageName")
val requestHash = requestDetails.getString("requestHash")
val timestampMillis = requestDetails.getLong("timestampMillis")
val currentTimestampMillis = ...

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request
    || !requestHash.equals(expectedRequestHash)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Java

RequestDetails requestDetails =
    decodeIntegrityTokenResponse
    .getTokenPayloadExternal()
    .getRequestDetails();
String requestPackageName = requestDetails.getRequestPackageName();
String requestHash = requestDetails.getRequestHash();
long timestampMillis = requestDetails.getTimestampMillis();
long currentTimestampMillis = ...;

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request.
    || !requestHash.equals(expectedRequestHash)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Para solicitações de API clássicas:

"requestDetails": {
  // Application package name this attestation was requested for.
  // Note that this field might be spoofed in the middle of the
  // request.
  "requestPackageName": "com.package.name",
  // base64-encoded URL-safe no-wrap nonce provided by the developer.
  "nonce": "aGVsbG8gd29scmQgdGhlcmU",
  // The timestamp in milliseconds when the request was made
  // (computed on the server).
  "timestampMillis": "1617893780"
}

Esses valores precisam corresponder aos da solicitação original. Portanto, verifique a parte requestDetails do payload JSON, garantindo que requestPackageName e nonce correspondam ao que foi enviado na solicitação original, conforme mostrado no snippet de código abaixo:

Kotlin

val requestDetails = JSONObject(payload).getJSONObject("requestDetails")
val requestPackageName = requestDetails.getString("requestPackageName")
val nonce = requestDetails.getString("nonce")
val timestampMillis = requestDetails.getLong("timestampMillis")
val currentTimestampMillis = ...

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request. See 'Generate a nonce'
        // section of the doc on how to store/compute the expected nonce.
    || !nonce.equals(expectedNonce)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Java

JSONObject requestDetails =
    new JSONObject(payload).getJSONObject("requestDetails");
String requestPackageName = requestDetails.getString("requestPackageName");
String nonce = requestDetails.getString("nonce");
long timestampMillis = requestDetails.getLong("timestampMillis");
long currentTimestampMillis = ...;

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request. See 'Generate a nonce'
        // section of the doc on how to store/compute the expected nonce.
    || !nonce.equals(expectedNonce)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Campo de integridade do aplicativo

O campo appIntegrity contém informações relacionadas ao pacote.

"appIntegrity": {
  // PLAY_RECOGNIZED, UNRECOGNIZED_VERSION, or UNEVALUATED.
  "appRecognitionVerdict": "PLAY_RECOGNIZED",
  // The package name of the app.
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  "packageName": "com.package.name",
  // The sha256 digest of app certificates (base64-encoded URL-safe).
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  "certificateSha256Digest": ["6a6a1474b5cbbb2b1aa57e0bc3"],
  // The version of the app.
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  "versionCode": "42"
}

appRecognitionVerdict pode ter estes valores:

PLAY_RECOGNIZED
O app e o certificado correspondem às versões distribuídas pelo Google Play.
UNRECOGNIZED_VERSION
O nome do certificado ou do pacote não corresponde aos registros do Google Play.
UNEVALUATED
A integridade do aplicativo não foi avaliada. Um requisito necessário está ausente, por exemplo, o dispositivo não é confiável o suficiente.

Para garantir que o token tenha sido gerado por um app criado por você, confira se a integridade do aplicativo está de acordo com o esperado, conforme mostrado no snippet de código abaixo:

Kotlin

val appIntegrity = JSONObject(payload).getJSONObject("appIntegrity")
val appRecognitionVerdict = appIntegrity.getString("appRecognitionVerdict")

if (appRecognitionVerdict == "PLAY_RECOGNIZED") {
    // Looks good!
}

Java

JSONObject appIntegrity =
    new JSONObject(payload).getJSONObject("appIntegrity");
String appRecognitionVerdict =
    appIntegrity.getString("appRecognitionVerdict");

if (appRecognitionVerdict.equals("PLAY_RECOGNIZED")) {
    // Looks good!
}

Também é possível conferir manualmente o nome do pacote, a versão e os certificados do app.

Campo de integridade do dispositivo

O campo deviceIntegrity pode conter um único valor, deviceRecognitionVerdict, que tem um ou mais identificadores que representam a capacidade de um dispositivo de garantir a integridade do app. Se um dispositivo não atender aos critérios de algum identificador, o campo deviceIntegrity vai omitir deviceRecognitionVerdict.

"deviceIntegrity": {
  // "MEETS_DEVICE_INTEGRITY" is one of several possible values.
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"]
}

Por padrão, deviceRecognitionVerdict pode conter o seguinte:

MEETS_DEVICE_INTEGRITY
O app está sendo executado em um dispositivo Android genuíno e certificado. No Android 13 e versões mais recentes, há uma prova protegida por hardware de que o carregador de inicialização do dispositivo está bloqueado e o SO Android carregado é uma imagem certificada do fabricante do dispositivo.
Vazio (um valor em branco)
O app está sendo executado em um dispositivo que tem sinais de ataque, como hooks de API, ou comprometimentos do sistema, como acesso root. Ou, então, o app não está sendo executado em um dispositivo físico, mas sim, por exemplo, em um emulador que falha nas verificações de integridade do Google Play.

Para garantir que o token veio de um dispositivo confiável, verifique se o deviceRecognitionVerdict está de acordo com o esperado, conforme mostrado no snippet de código abaixo:

Kotlin

val deviceIntegrity =
    JSONObject(payload).getJSONObject("deviceIntegrity")
val deviceRecognitionVerdict =
    if (deviceIntegrity.has("deviceRecognitionVerdict")) {
        deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString()
    } else {
        ""
    }

if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) {
    // Looks good!
}

Java

JSONObject deviceIntegrity =
    new JSONObject(payload).getJSONObject("deviceIntegrity");
String deviceRecognitionVerdict =
    deviceIntegrity.has("deviceRecognitionVerdict")
    ? deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString()
    : "";

if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) {
    // Looks good!
}

Se você tiver problemas em atender aos requisitos de integridade com o dispositivo de teste, confira se a ROM de fábrica está instalada, por exemplo, redefinindo o dispositivo para as configurações originais, e se o carregador de inicialização está bloqueado. Você também pode criar testes da Play Integrity no Play Console.

Identificadores de dispositivos condicionais

Se o app estiver sendo lançado no Google Play Games para PC, o deviceRecognitionVerdict também pode conter o seguinte identificador:

MEETS_VIRTUAL_INTEGRITY
O app está em execução em um dispositivo Android com o Google Play Services. O emulador foi aprovado nas verificações de integridade do sistema e atende aos principais requisitos de compatibilidade do Android.

Informações opcionais do dispositivo e reconhecimento do dispositivo

Se você aceitar receber outros identificadores no veredito de integridade, o campo deviceRecognitionVerdict poderá ter os indicadores abaixo:

MEETS_BASIC_INTEGRITY
O app está sendo executado em um dispositivo que é aprovado nas verificações básicas de integridade do sistema. O carregador de inicialização do dispositivo pode estar bloqueado ou desbloqueado, e o estado de inicialização pode ser verificado ou não. O dispositivo pode não ser certificado, e, nesse caso, o Google não pode oferecer garantias de segurança, privacidade ou compatibilidade de apps. No Android 13 e versões mais recentes, o veredito MEETS_BASIC_INTEGRITY exige apenas que a raiz de confiança da declaração seja fornecida pelo Google.
MEETS_STRONG_INTEGRITY
O app está sendo executado em um dispositivo Android genuíno e certificado com uma atualização de segurança recente.
  • No Android 13 e versões mais recentes, o veredito MEETS_STRONG_INTEGRITY exige MEETS_DEVICE_INTEGRITY e atualizações de segurança no último ano para todas as partições do dispositivo, incluindo um patch de partição do SO Android e um patch de partição do fornecedor.
  • No Android 12 e versões anteriores, o veredito MEETS_STRONG_INTEGRITY só exige uma prova de integridade de inicialização protegida por hardware e não exige que o dispositivo tenha uma atualização de segurança recente. Portanto, ao usar o MEETS_STRONG_INTEGRITY, é recomendável considerar também a versão do SDK do Android no campo deviceAttributes.

Um único dispositivo vai retornar vários identificadores de dispositivo no veredito de integridade se cada um dos critérios do identificador for atendido.

Atributos do dispositivo

Você também pode ativar os atributos do dispositivo, que informam a versão do SDK do Android do sistema operacional Android em execução no dispositivo. No futuro, ele poderá ser estendido com outros atributos de dispositivo.

O valor da versão do SDK é o número da versão do SDK do Android definido em Build.VERSION_CODES. A versão do SDK não é avaliada se um requisito necessário estiver ausente. Nesse caso, o campo sdkVersion não está definido. Portanto, o campo deviceAttributes está vazio. Isso pode acontecer porque:

  • O dispositivo não é confiável o suficiente.
  • Havia problemas técnicos no dispositivo.

Se você ativar o recebimento de deviceAttributes, o campo deviceIntegrity terá o seguinte campo extra:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceAttributes": {
    // 33 is one possible value, which represents Android 13 (Tiramisu).
    "sdkVersion": 33
  }
}

Caso a versão do SDK não seja avaliada, o campo deviceAttributes será definido como:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceAttributes": {}  // sdkVersion field is not set.
}

Atividade recente do dispositivo

Você também pode ativar a atividade recente do dispositivo, que informa quantas vezes seu app solicitou um token de integridade em um dispositivo específico na última hora. É possível usar a atividade recente do dispositivo para proteger seu app contra dispositivos hiperativos inesperados que podem indicar um ataque ativo. Também é possível decidir o quanto confiar em cada nível de atividade recente do dispositivo com base em quantas vezes você espera que o app instalado em um dispositivo comum solicite um token de integridade a cada hora.

Se você ativar o recebimento de recentDeviceActivity, o campo deviceIntegrity terá dois valores:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "recentDeviceActivity": {
    // "LEVEL_2" is one of several possible values.
    "deviceActivityLevel": "LEVEL_2"
  }
}

As definições de deviceActivityLevel variam entre os modos e podem ter um dos seguintes valores:

Nível de atividade recente do dispositivo Solicitações padrão de token de integridade da API neste dispositivo na última hora por app Solicitações de token de integridade da API clássica neste dispositivo na última hora por app
LEVEL_1 (mínimo) 10 ou menos 5 ou menos
LEVEL_2 Entre 11 e 25 Entre 6 e 10
LEVEL_3 Entre 26 e 50 Entre 11 e 15
LEVEL_4 (mais alto) Mais de 50 Mais de 15
UNEVALUATED A atividade recente do dispositivo não foi avaliada. Isso pode acontecer porque:
  • O dispositivo não é confiável o suficiente.
  • A versão do app instalada no dispositivo é desconhecida para o Google Play.
  • Problemas técnicos no dispositivo.

Reconhecimento do dispositivo (Beta)

Você também pode ativar a recuperação de dispositivos, que permite armazenar alguns dados personalizados por dispositivo com dispositivos específicos que você pode recuperar de forma confiável quando o app for instalado novamente no mesmo dispositivo. Depois de solicitar um token de integridade, faça uma chamada separada de servidor para servidor para modificar os valores de recall do dispositivo em um dispositivo específico.

Se você ativar o deviceRecall, o campo deviceIntegrity vai conter as informações de recall do dispositivo definidas para ele:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceRecall": {
    "values": {
      "bitFirst": true,
      "bitSecond": false,
      "bitThird": true
    },
    "writeDates": {
      // Write time in YYYYMM format in UTC.
      "yyyymmFirst": 202401,
      // Note that yyyymmSecond is not set because bitSecond is false.
      "yyyymmThird": 202310
    }
  }
}

O deviceRecall é dividido em dois campos:

  • values: lembre-se dos valores de bits que você definiu anteriormente para este dispositivo.
  • writeDates: lembre-se das datas de gravação de bits em UTC com precisão de ano e mês. A data de gravação de um bit de recall será atualizada sempre que o bit for definido como true e será removida quando o bit for definido como false.

Quando as informações de recall do dispositivo não estão disponíveis, o valor de recall do dispositivo fica vazio:

"deviceIntegrity": {
  "deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"],
  "deviceRecall": {
    "values": {},
    "writeDates": {}
  }
}

Campo de detalhes da conta

O campo accountDetails contém um único valor, appLicensingVerdict, que representa o status de licenciamento do Google Play do app para a conta de usuário conectada no dispositivo. Se a conta de usuário tiver a licença do app no Google Play, isso significa que ele foi baixado ou comprado na plataforma.

"accountDetails": {
  // This field can be LICENSED, UNLICENSED, or UNEVALUATED.
  "appLicensingVerdict": "LICENSED"
}

O appLicensingVerdict pode ter um destes valores:

LICENSED
O usuário tem direito de acesso ao app. Em outras palavras, o usuário instalou ou atualizou seu app no Google Play pelo dispositivo.
UNLICENSED
O usuário não tem a titularidade do app. Isso acontece quando, por exemplo, o usuário transfere o app por sideload ou não o adquire pelo Google Play. Você pode mostrar a caixa de diálogo GET_LICENSED aos usuários para resolver isso.
UNEVALUATED

Os detalhes de licenciamento não foram avaliados porque um requisito necessário está ausente.

Isso pode acontecer por vários motivos, incluindo:

  • O dispositivo não é confiável o suficiente.
  • A versão do app instalada no dispositivo não é reconhecida pelo Google Play.
  • O usuário não está conectado ao Google Play.

Para conferir se o usuário tem direito de acesso ao app, confira se o appLicensingVerdict está de acordo com o esperado, conforme mostrado no snippet de código abaixo.

Kotlin

val accountDetails = JSONObject(payload).getJSONObject("accountDetails")
val appLicensingVerdict = accountDetails.getString("appLicensingVerdict")

if (appLicensingVerdict == "LICENSED") {
    // Looks good!
}

Java

JSONObject accountDetails =
    new JSONObject(payload).getJSONObject("accountDetails");
String appLicensingVerdict = accountDetails.getString("appLicensingVerdict");

if (appLicensingVerdict.equals("LICENSED")) {
    // Looks good!
}

Campo de detalhes do ambiente

Você também pode ativar outros indicadores sobre o ambiente. O risco de acesso a apps avisa quando outro app em execução pode ser usado para capturar a tela, mostrar sobreposições ou controlar o dispositivo. O veredito do Play Protect informa se o Google Play Protect está ativado no dispositivo e se ele detectou malware conhecido.

Se você tiver ativado o veredito de risco de acesso a apps ou do Play Protect no Google Play Console, a resposta da API vai incluir o campo environmentDetails. O campo environmentDetails pode conter dois valores: appAccessRiskVerdict e playProtectVerdict.

Veredito de risco de acesso ao app

Depois da ativação, o campo environmentDetails no payload da API Play Integrity vai conter o novo veredito do indicador de risco de acesso a apps.

{
  "requestDetails": { ... },
  "appIntegrity": { ... },
  "deviceIntegrity": { ... },
  "accountDetails": { ... },
  "environmentDetails": {
      "appAccessRiskVerdict": {
          // This field contains one or more responses, for example the following.
          "appsDetected": ["KNOWN_INSTALLED", "UNKNOWN_INSTALLED", "UNKNOWN_CAPTURING"]
      }
 }
}

Se o risco de acesso ao app foi avaliado, appAccessRiskVerdict contém o campo appsDetected com uma ou mais respostas. Essas respostas se enquadram em um dos dois grupos a seguir, dependendo da origem da instalação dos apps detectados:

  • Apps do sistema ou do Google Play: apps instalados pelo Google Play ou pré-carregados pelo fabricante do dispositivo na partição do sistema (identificados com FLAG_SYSTEM). As respostas para esses apps são prefixadas com KNOWN_.

  • Outros apps: são apps que não são instalados pelo Google Play. Isso exclui apps pré-carregados na partição do sistema pelo fabricante do dispositivo. As respostas para esses apps têm o prefixo UNKNOWN_.

As seguintes respostas podem ser retornadas:

KNOWN_INSTALLED, UNKNOWN_INSTALLED
Alguns apps instalados correspondem à fonte de instalação correspondente.
KNOWN_CAPTURING, UNKNOWN_CAPTURING
Há apps em execução com permissões ativadas que podem ser usados para visualizar a tela enquanto seu app está em execução. Isso exclui todos os serviços de acessibilidade verificados conhecidos pelo Google Play em execução no dispositivo.
KNOWN_CONTROLLING, UNKNOWN_CONTROLLING
Há apps em execução com permissões ativadas que podem ser usadas para controlar o dispositivo e controlar diretamente as entradas feitas no seu app para capturar entradas e saídas do app. Isso exclui qualquer serviço de acessibilidade verificado conhecido pelo Google Play em execução no dispositivo.
KNOWN_OVERLAYS, UNKNOWN_OVERLAYS
Há apps em execução com permissões ativadas que podem ser usadas para mostrar sobreposições no seu app. Isso exclui qualquer serviço de acessibilidade verificado conhecido pelo Google Play em execução no dispositivo.
Vazio (um valor em branco)

O risco de acesso a apps não é avaliado se um requisito necessário estiver ausente. Nesse caso, o campo appAccessRiskVerdict está vazio. Isso pode acontecer por vários motivos, incluindo:

  • O dispositivo não é confiável o suficiente.
  • O formato do dispositivo não é um smartphone, tablet ou dobrável.
  • O dispositivo não está executando o Android 6 (nível 23 da API) ou mais recente.
  • A versão do app instalada no dispositivo é desconhecida para o Google Play.
  • A versão da Google Play Store no dispositivo está desatualizada.
  • A conta de usuário não tem uma licença do Google Play.
  • Uma solicitação padrão foi usada com o parâmetro verdictOptOut.
  • Uma solicitação padrão foi usada com uma versão da biblioteca da API Play Integrity que ainda não oferece suporte ao risco de acesso a apps para solicitações padrão.

Ele exclui automaticamente os serviços de acessibilidade verificados que passaram por uma análise aprimorada de acessibilidade do Google Play (instalados por qualquer loja de apps no dispositivo). Essa exclusão significa que os serviços de acessibilidade verificados em execução no dispositivo não vão gerar uma resposta de captura, controle ou sobreposição no veredito de risco de acesso a apps. Para solicitar uma análise aprimorada de acessibilidade do Google Play para seu app de acessibilidade, publique-o no Google Play. Verifique se o app tem a flag isAccessibilityTool definida como "true" no manifesto do app ou solicite uma análise.

Exemplos de vereditos de risco de acesso a apps

A tabela a seguir fornece alguns exemplos de vereditos de risco de acesso a apps e o que eles significam, sem listar todos os resultados possíveis:

Exemplo de resposta para o veredito de risco de acesso a apps Interpretação
appsDetected:
["KNOWN_INSTALLED"]
Os únicos apps instalados são reconhecidos pelo Google Play ou foram pré-carregados na partição do sistema pelo fabricante do dispositivo.
Não há apps em execução que possam resultar nos vereditos de captura, controle ou sobreposição.
appsDetected:
["KNOWN_INSTALLED",
"UNKNOWN_INSTALLED",
"UNKNOWN_CAPTURING"]
Há apps instalados pelo Google Play ou pré-carregados na partição do sistema pelo fabricante do dispositivo.
Além disso, há outros apps em execução com permissões ativadas que podem ser usadas para visualizar a tela ou capturar outras entradas e saídas.
appsDetected:
["KNOWN_INSTALLED",
"KNOWN_CAPTURING",
"UNKNOWN_INSTALLED",
"UNKNOWN_CONTROLLING"]
Há apps do sistema ou do Google Play em execução com permissões ativadas que podem ser usadas para visualizar a tela ou capturar outras entradas e saídas.
Há também outros apps em execução com permissões ativadas que podem ser usadas para controlar o dispositivo e controlar diretamente as entradas no seu app.
appAccessRiskVerdict: {} O indicador de risco de acesso a apps não foi avaliado porque um requisito necessário está ausente. Por exemplo, o dispositivo não era confiável o suficiente.

Dependendo do seu nível de risco, é possível decidir qual combinação de vereditos é aceitável para prosseguir e para quais vereditos você quer tomar medidas. O snippet de código a seguir ilustra um exemplo de verificação de que não há apps em execução que possam capturar a tela ou controlar seu app:

Kotlin

val environmentDetails =
    JSONObject(payload).getJSONObject("environmentDetails")
val appAccessRiskVerdict =
    environmentDetails.getJSONObject("appAccessRiskVerdict")

if (appAccessRiskVerdict.has("appsDetected")) {
    val appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString()
    if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) {
        // Looks good!
    }
}

Java

JSONObject environmentDetails =
    new JSONObject(payload).getJSONObject("environmentDetails");
JSONObject appAccessRiskVerdict =
    environmentDetails.getJSONObject("appAccessRiskVerdict");

if (appAccessRiskVerdict.has("appsDetected")) {
    String appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString()
    if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) {
        // Looks good!
    }
}
Corrigir vereditos de risco de acesso a apps

Dependendo do seu nível de risco, é possível decidir quais vereditos de risco de acesso ao app você quer resolver antes de permitir que o usuário conclua uma solicitação ou ação. Há solicitações opcionais do Google Play que você pode mostrar ao usuário depois de verificar o veredito de risco de acesso ao app. Você pode mostrar CLOSE_UNKNOWN_ACCESS_RISK para pedir que o usuário feche apps desconhecidos que causam o veredito de risco de acesso ao app ou CLOSE_ALL_ACCESS_RISK para pedir que ele feche todos os apps (conhecidos e desconhecidos) que causam o veredito de risco de acesso ao app.

Veredito do Play Protect

Depois da ativação, o campo environmentDetails no payload da API Play Integrity vai conter o veredito do Play Protect:

"environmentDetails": {
  "playProtectVerdict": "NO_ISSUES"
}

O playProtectVerdict pode ter um destes valores:

NO_ISSUES
O Play Protect está ativado e não encontrou problemas de apps no dispositivo.
NO_DATA
O Play Protect está ativado, mas nenhuma verificação foi realizada ainda. O dispositivo ou o app Play Store pode ter sido redefinido recentemente.
POSSIBLE_RISK
O Play Protect está desativado.
MEDIUM_RISK
O Play Protect está ativado e encontrou apps potencialmente nocivos instalados no dispositivo.
HIGH_RISK
O Play Protect está ativado e encontrou apps perigosos instalados no dispositivo.
UNEVALUATED

O veredito do Play Protect não foi avaliado.

Isso pode acontecer por vários motivos, incluindo:

  • O dispositivo não é confiável o suficiente.
  • A conta de usuário não tem uma licença do Google Play.

Orientações sobre como usar o veredito do Play Protect

O servidor de back-end do app pode decidir o que fazer com base no veredito considerando sua tolerância a riscos. Aqui estão algumas sugestões e possíveis ações do usuário:

NO_ISSUES
O Play Protect está ativado e não encontrou problemas. Por isso, nenhuma ação do usuário é necessária.
POSSIBLE_RISK e NO_DATA
Ao receber esses vereditos, peça ao usuário para conferir se o Play Protect está ativado e se realizou uma verificação. NO_DATA pode aparecer apenas em raras circunstâncias.
MEDIUM_RISK e HIGH_RISK
Dependendo da sua tolerância a riscos, você pode pedir que o usuário abra o Play Protect e tome medidas em relação aos avisos mostrados. Se o usuário não conseguir cumprir esses requisitos, você poderá bloqueá-lo da ação do servidor.