Esito dell'integrità

Questa pagina descrive come interpretare e utilizzare il verdetto di integrità restituito. Indipendentemente dal fatto che tu effettui una richiesta API standard o classica, l'esito dell'integrità viene restituito nello stesso formato con contenuti simili. L'esito dell'integrità comunica informazioni sulla validità di dispositivi, app e account. Il server della tua app può utilizzare il payload risultante in un verdetto decriptato e verificato per determinare il modo migliore per procedere con una determinata azione o richiesta nella tua app.

Formato dell'esito relativo all'integrità restituito

Il payload è JSON in formato testo normale e contiene indicatori di integrità insieme alle informazioni fornite dallo sviluppatore.

La struttura generale del payload è la seguente:

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

Prima di controllare ogni verdetto di integrità, devi verificare che i valori nel campo requestDetails corrispondano a quelli della richiesta originale. Le sezioni seguenti descrivono in dettaglio ogni campo.

Campo Dettagli della richiesta

Il campo requestDetails contiene informazioni sulla richiesta, tra cui le informazioni fornite dallo sviluppatore nel campo requestHash per le richieste standard e nel campo nonce per le richieste classiche.

Per le richieste API standard:

"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"
}

Questi valori devono corrispondere a quelli della richiesta originale. Pertanto, verifica la parte requestDetails del payload JSON assicurandoti che requestPackageName e requestHash corrispondano a quanto inviato nella richiesta originale, come mostrato nel seguente snippet di codice:

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.
        ...
}

Per le richieste API classiche:

"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"
}

Questi valori devono corrispondere a quelli della richiesta originale. Pertanto, verifica la parte requestDetails del payload JSON assicurandoti che requestPackageName e nonce corrispondano a quanto inviato nella richiesta originale, come mostrato nel seguente snippet di codice:

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 Integrità dell'applicazione

Il campo appIntegrity contiene informazioni relative al pacchetto.

"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 può avere i seguenti valori:

PLAY_RECOGNIZED
L'app e il certificato corrispondono alle versioni distribuite da Google Play.
UNRECOGNIZED_VERSION
Il nome del certificato o del pacchetto non corrisponde ai record di Google Play.
UNEVALUATED
L'integrità dell'applicazione non è stata valutata. Mancava un requisito necessario, ad esempio il dispositivo non era abbastanza attendibile.

Per assicurarti che il token sia stato generato da un'app creata da te, verifica che l'integrità dell'applicazione sia quella prevista, come mostrato nel seguente snippet di codice:

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!
}

Puoi anche controllare manualmente il nome del pacchetto dell'app, la versione dell'app e i certificati dell'app.

Campo Integrità del dispositivo

Il campo deviceIntegrity può contenere un singolo valore, deviceRecognitionVerdict, che ha una o più etichette che rappresentano la capacità di un dispositivo di applicare l'integrità dell'app. Se un dispositivo non soddisfa i criteri di nessuna etichetta, il campo deviceIntegrity omette deviceRecognitionVerdict.

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

Per impostazione predefinita, deviceRecognitionVerdict può contenere:

MEETS_DEVICE_INTEGRITY
L'app è in esecuzione su un dispositivo Android originale e certificato. Su Android 13 e versioni successive, esiste una prova supportata dall'hardware che il bootloader del dispositivo è bloccato e il sistema operativo Android caricato è un'immagine certificata del produttore del dispositivo.
Vuoto (valore vuoto)
L'app è in esecuzione su un dispositivo per cui sono stati rilevati segnali di attacco (come l'hook delle API) o una compromissione del sistema (ad esempio il rooting) oppure l'app non è in esecuzione su un dispositivo fisico (ad esempio un emulatore che non supera i controlli relativi all'integrità di Google Play).

Per assicurarti che il token provenga da un dispositivo attendibile, verifica che deviceRecognitionVerdict sia come previsto, come mostrato nel seguente snippet di codice:

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 hai problemi con il tuo dispositivo di test che soddisfa l'integrità del dispositivo, assicurati che sia installata la ROM di fabbrica (ad esempio ripristinando il dispositivo) e che il bootloader sia bloccato. Puoi anche creare test dell'API Play Integrity in Play Console.

Etichette condizionali dei dispositivi

Se la tua app viene rilasciata su Google Play Giochi per PC, il deviceRecognitionVerdict può contenere anche la seguente etichetta:

MEETS_VIRTUAL_INTEGRITY
L'app viene eseguita su un emulatore basato su Android con Google Play Services. L'emulatore supera i controlli relativi all'integrità del sistema e soddisfa i requisiti fondamentali di compatibilità con Android.

Informazioni facoltative sul dispositivo e richiamo del dispositivo

Se attivi la ricezione di etichette aggiuntive nell'esito relativo all'integrità, deviceRecognitionVerdict può contenere le seguenti etichette aggiuntive:

MEETS_BASIC_INTEGRITY
L'app è in esecuzione su un dispositivo che supera i controlli di base relativi all'integrità del sistema. Il bootloader del dispositivo può essere bloccato o sbloccato e lo stato di avvio può essere verificato o non verificato. Il dispositivo potrebbe non essere certificato, nel qual caso Google non può fornire alcuna garanzia di sicurezza, privacy o compatibilità delle app. Su Android 13 e versioni successive, l'esito MEETS_BASIC_INTEGRITY richiede solo che la root of trust dell'attestazione sia fornita da Google.
MEETS_STRONG_INTEGRITY
L'app viene eseguita su un dispositivo Android originale e certificato con un aggiornamento della sicurezza recente.
  • Su Android 13 e versioni successive, il verdetto MEETS_STRONG_INTEGRITY richiede MEETS_DEVICE_INTEGRITY e aggiornamenti della sicurezza nell'ultimo anno per tutte le partizioni del dispositivo, inclusa una patch della partizione del sistema operativo Android e una patch della partizione del fornitore.
  • Su Android 12 e versioni precedenti, l'esito MEETS_STRONG_INTEGRITY richiede solo la prova dell'integrità dell'avvio supportata dall'hardware e non richiede che il dispositivo abbia un aggiornamento della sicurezza recente. Pertanto, quando utilizzi MEETS_STRONG_INTEGRITY, ti consigliamo di prendere in considerazione anche la versione dell'SDK Android nel campo deviceAttributes.

Un singolo dispositivo restituirà più etichette del dispositivo nel verdetto di integrità del dispositivo se vengono soddisfatti i criteri di ciascuna etichetta.

Attributi del dispositivo

Puoi anche attivare gli attributi del dispositivo, che indicano la versione dell'SDK Android del sistema operativo Android in esecuzione sul dispositivo. In futuro, potrebbe essere esteso con altri attributi del dispositivo.

Il valore della versione dell'SDK è il numero di versione dell'SDK Android definito in Build.VERSION_CODES. La versione dell'SDK non viene valutata se manca un requisito necessario. In questo caso, il campo sdkVersion non è impostato, pertanto il campo deviceAttributes è vuoto. Ciò può accadere perché:

  • Il dispositivo non è abbastanza attendibile.
  • Si sono verificati problemi tecnici sul dispositivo.

Se attivi la ricezione di deviceAttributes, il campo deviceIntegrity conterrà il seguente campo aggiuntivo:

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

Se la versione dell'SDK non viene valutata, il campo deviceAttributes verrà impostato come segue:

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

Attività del dispositivo recente

Puoi anche attivare l'attività del dispositivo recente, che indica quante volte la tua app ha richiesto un token di integrità su un dispositivo specifico nell'ultima ora. Puoi utilizzare l'attività recente del dispositivo per proteggere la tua app da dispositivi inaspettati e iperattivi che potrebbero indicare un attacco in corso. Puoi decidere quanto fidarti di ogni livello di attività recente del dispositivo in base a quante volte prevedi che la tua app installata su un dispositivo tipico richieda un token di integrità ogni ora.

Se scegli di ricevere recentDeviceActivity, il campo deviceIntegrity avrà due valori:

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

Le definizioni di deviceActivityLevel variano in base alle modalità e possono avere uno dei seguenti valori:

Livello di attività recente del dispositivo Richieste di token di integrità API standard su questo dispositivo nell'ultima ora per app Richieste di token di integrità API classici su questo dispositivo nell'ultima ora per app
LEVEL_1 (minimo) 10 o meno 5 o meno
LEVEL_2 Tra 11 e 25 Tra 6 e 10
LEVEL_3 Tra 26 e 50 Tra 11 e 15
LEVEL_4 (più alto) Più di 50 Più di 15
UNEVALUATED L'attività del dispositivo recente non è stata valutata. Ciò potrebbe accadere perché:
  • Il dispositivo non è abbastanza attendibile.
  • La versione dell'app installata sul dispositivo non è nota a Google Play.
  • Problemi tecnici sul dispositivo.

Richiamo del dispositivo (beta)

Puoi anche attivare il richiamo del dispositivo, che ti consente di memorizzare alcuni dati personalizzati per dispositivo con dispositivi specifici che puoi recuperare in modo affidabile quando la tua app viene installata di nuovo in un secondo momento sullo stesso dispositivo. Dopo aver richiesto un token di integrità, effettui una chiamata server-to-server separata per modificare i valori di richiamo del dispositivo per un dispositivo specifico.

Se attivi deviceRecall, il campo deviceIntegrity conterrà le informazioni sul ritiro del dispositivo che hai impostato per il dispositivo specifico:

"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
    }
  }
}

Il deviceRecall è suddiviso in due campi:

  • values: richiama i valori dei bit impostati in precedenza per questo dispositivo.
  • writeDates: Richiama le date di scrittura dei bit in UTC con precisione di anno e mese. La data di scrittura di un bit di ritiro verrà aggiornata ogni volta che il bit viene impostato su true e verrà rimossa quando il bit viene impostato su false.

Nel caso in cui le informazioni sul ritiro del dispositivo non siano disponibili, il valore del ritiro del dispositivo sarà vuoto:

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

Campo Dettagli account

Il campo accountDetails contiene un singolo valore, appLicensingVerdict, che rappresenta lo stato della licenza Google Play dell'app per l'account utente che ha eseguito l'accesso sul dispositivo. Se l'account utente ha la licenza Play per l'app, significa che l'ha scaricata o acquistata da Google Play.

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

appLicensingVerdict può avere uno dei seguenti valori:

LICENSED
L'utente dispone di autorizzazione per l'app. In altre parole, l'utente ha installato o aggiornato la tua app da Google Play sul proprio dispositivo.
UNLICENSED
L'utente non dispone di autorizzazione per l'app. Questo accade, ad esempio, quando l'utente installa l'app tramite sideload o non la acquisisce da Google Play. Per risolvere il problema, puoi mostrare agli utenti la finestra di dialogo GET_LICENSED.
UNEVALUATED

I dettagli relativi all'autorizzazione non sono stati valutati perché mancava un requisito necessario.

Questo potrebbe accadere per diversi motivi, tra cui:

  • Il dispositivo non è abbastanza attendibile.
  • La versione dell'app installata sul dispositivo non è nota a Google Play.
  • L'utente non ha eseguito l'accesso a Google Play.

Per verificare che l'utente disponga di un diritto per la tua app, verifica che appLicensingVerdict sia come previsto, come mostrato nel seguente snippet di codice:

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 Dettagli ambiente

Puoi anche attivare indicatori aggiuntivi sull'ambiente. Il rischio di accesso all'app indica alla tua app se sono in esecuzione altre app che potrebbero essere utilizzate per acquisire la schermata, mostrare overlay o controllare il dispositivo. L'esito di Play Protect indica se Google Play Protect è attivato sul dispositivo e se ha rilevato malware noti.

Se hai attivato l'esito Rischio di accesso all'app o l'esito Play Protect in Google Play Console, la risposta dell'API includerà il campo environmentDetails. Il campo environmentDetails può contenere due valori, appAccessRiskVerdict e playProtectVerdict.

Esito del rischio di accesso all'app

Una volta abilitato, il campo environmentDetails nel payload dell'API Play Integrity conterrà il nuovo esito del rischio di accesso all'app.

{
  "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 è stato valutato il rischio di accesso all'app, appAccessRiskVerdict contiene il campo appsDetected con una o più risposte. Queste risposte rientrano in uno dei due gruppi seguenti, a seconda dell'origine di installazione delle app rilevate:

  • App di Play o di sistema: app installate da Google Play o precaricate dal produttore del dispositivo nella partizione di sistema del dispositivo (identificate con FLAG_SYSTEM). Le risposte per queste app sono precedute da KNOWN_.

  • Altre app: app non installate da Google Play. Sono escluse le app precaricate nella partizione di sistema dal produttore del dispositivo. Le risposte per queste app sono precedute da UNKNOWN_.

Possono essere restituite le seguenti risposte:

KNOWN_INSTALLED, UNKNOWN_INSTALLED
Sono installate app che corrispondono all'origine di installazione corrispondente.
KNOWN_CAPTURING, UNKNOWN_CAPTURING
Sono in esecuzione app con autorizzazioni attive che potrebbero essere utilizzate per visualizzare lo schermo mentre la tua app è in esecuzione. Sono esclusi i servizi di accessibilità verificati noti a Google Play in esecuzione sul dispositivo.
KNOWN_CONTROLLING, UNKNOWN_CONTROLLING
Sono in esecuzione app con autorizzazioni attive che potrebbero essere utilizzate per controllare il dispositivo e controllare direttamente gli input nella tua app e potrebbero essere utilizzate per acquisire input e output della tua app. Sono esclusi i servizi di accessibilità verificati noti a Google Play in esecuzione sul dispositivo.
KNOWN_OVERLAYS, UNKNOWN_OVERLAYS
Sono in esecuzione app con autorizzazioni attive che potrebbero essere utilizzate per visualizzare overlay sulla tua app. Sono esclusi i servizi di accessibilità verificati noti a Google Play in esecuzione sul dispositivo.
Vuoto (valore vuoto)

Il rischio di accesso all'app non viene valutato se manca un requisito necessario. In questo caso, il campo appAccessRiskVerdict è vuoto. Questo potrebbe accadere per diversi motivi, tra cui:

  • Il dispositivo non è abbastanza attendibile.
  • Il fattore di forma del dispositivo non è uno smartphone, un tablet o un dispositivo pieghevole.
  • Sul dispositivo non è installato Android 6 (livello API 23) o versioni successive.
  • La versione dell'app installata sul dispositivo non è nota a Google Play.
  • La versione del Google Play Store sul dispositivo non è aggiornata.
  • L'account utente non dispone di una licenza Play.
  • È stata utilizzata una richiesta standard con il parametro verdictOptOut.
  • È stata utilizzata una richiesta standard con una versione della libreria API Play Integrity che non supporta ancora il rischio di accesso all'app per le richieste standard.

Il rischio di accesso alle app esclude automaticamente i servizi di accessibilità verificati che hanno superato una revisione avanzata dell'accessibilità di Google Play (installati da qualsiasi app store sul dispositivo). "Escluso" significa che i servizi di accessibilità verificati in esecuzione sul dispositivo non restituiranno una risposta di acquisizione, controllo o overlay nel verdetto sul rischio di accesso alle app. Per richiedere una revisione avanzata dell'accessibilità di Google Play per la tua app di accessibilità, pubblicala su Google Play assicurandoti che l'app abbia il flag isAccessibilityTool impostato su true nel manifest dell'app oppure richiedi una revisione.

Esempi di esiti del rischio di accesso all'app

La tabella seguente riporta alcuni esempi di verdetti sul rischio di accesso alle app e il loro significato (questa tabella non elenca tutti i risultati possibili):

Esempio di risposta dell'esito del rischio di accesso all'app Interpretazione
appsDetected:
["KNOWN_INSTALLED"]
Sono installate solo app riconosciute da Google Play o precaricate nella partizione di sistema dal produttore del dispositivo.
Non sono in esecuzione app che potrebbero comportare verdetti di acquisizione, controllo o sovrapposizioni.
appsDetected:
["KNOWN_INSTALLED",
"UNKNOWN_INSTALLED",
"UNKNOWN_CAPTURING"]
Sono installate app da Google Play o precaricate nella partizione di sistema dal produttore del dispositivo.
Sono in esecuzione altre app con autorizzazioni attive che potrebbero essere utilizzate per visualizzare lo schermo o acquisire altri input e output.
appsDetected:
["KNOWN_INSTALLED",
"KNOWN_CAPTURING",
"UNKNOWN_INSTALLED",
"UNKNOWN_CONTROLLING"]
Sono in esecuzione app di sistema o Play con autorizzazioni attive che potrebbero essere utilizzate per visualizzare lo schermo o acquisire altri input e output.
Sono in esecuzione anche altre app con autorizzazioni attive che potrebbero essere utilizzate per controllare il dispositivo e gli input direttamente nella tua app.
appAccessRiskVerdict: {} Il rischio di accesso all'app non viene valutato perché mancava un requisito necessario. Ad esempio, il dispositivo non era abbastanza attendibile.

A seconda del livello di rischio, puoi decidere quale combinazione di esiti è accettabile per procedere e per quali esiti vuoi intervenire. Lo snippet di codice seguente illustra un esempio di verifica dell'assenza di app in esecuzione che potrebbero acquisire la schermata o controllare la tua 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!
    }
}
Correggere gli esiti del rischio di accesso all'app

A seconda del tuo livello di rischio, puoi decidere su quali esiti di rischio di accesso alle app vuoi intervenire prima di consentire all'utente di completare una richiesta o un'azione. Esistono prompt di Google Play facoltativi che puoi mostrare all'utente dopo aver controllato l'esito del rischio di accesso all'app. Puoi mostrare CLOSE_UNKNOWN_ACCESS_RISK per chiedere all'utente di chiudere le app sconosciute che causano l'esito del rischio di accesso all'app oppure puoi mostrare CLOSE_ALL_ACCESS_RISK per chiedere all'utente di chiudere tutte le app (note e sconosciute) che causano l'esito del rischio di accesso all'app.

Verdetto di Play Protect

Una volta abilitato, il campo environmentDetails nel payload dell'API Play Integrity conterrà l'esito di Play Protect:

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

playProtectVerdict può avere uno dei seguenti valori:

NO_ISSUES
Play Protect è attivo e non ha rilevato problemi con le app sul dispositivo.
NO_DATA
Play Protect è attivo, ma non è ancora stata eseguita alcuna scansione. Il dispositivo o l'app Play Store potrebbero essere stati reimpostati di recente.
POSSIBLE_RISK
Play Protect è disattivato.
MEDIUM_RISK
Play Protect è attivo e ha trovato app potenzialmente dannose installate sul dispositivo.
HIGH_RISK
Play Protect è attivo e ha trovato app pericolose installate sul dispositivo.
UNEVALUATED

L'esito di Play Protect non è stato valutato.

Questo potrebbe accadere per diversi motivi, tra cui:

  • Il dispositivo non è abbastanza attendibile.
  • L'account utente non dispone di una licenza Play.

Indicazioni sull'utilizzo dell'esito di Play Protect

Il server di backend della tua app può decidere come agire in base all'esito in base alla tua tolleranza al rischio. Ecco alcuni suggerimenti e potenziali azioni degli utenti:

NO_ISSUES
Play Protect è attivo e non ha rilevato problemi, quindi non è richiesta alcuna azione da parte dell'utente.
POSSIBLE_RISK e NO_DATA
Quando ricevi questi verdetti, chiedi all'utente di verificare che Play Protect sia attivo e abbia eseguito una scansione. NO_DATA dovrebbe essere visualizzato solo in rare circostanze.
MEDIUM_RISK e HIGH_RISK
A seconda della tua propensione al rischio, puoi chiedere all'utente di avviare Play Protect e intervenire sugli avvisi di Play Protect. Se l'utente non è in grado di soddisfare questi requisiti, puoi bloccarlo dall'azione del server.