Scope: attestation only
Requirements
- minSdk 23 —
EncryptedSharedPreferencesrequires API 23+ - compileSdk 34, JDK 17
- Google Play Services on the device for a real Play Integrity verdict
Install
Initialize
Register your Android package name in the dashboard first — it identifies your tenant the same way Bundle ID + Team ID does on iOS.Activity is safe.
The constructor is annotated
@JvmOverloads, so Java callers get the same defaults.
Point at the development environment during integration testing:
Attest
Coroutines
attest() is a suspending function and dispatches its I/O internally, so it is safe to call from any coroutine context. It throws GrantivaError on failure.
Callback overload
For Java and React Native interop, where suspending functions are inconvenient:AttestationResult
DeviceIntelligence carries:
The score derives from the Play Integrity verdict:
STRONG → 5, DEVICE → 15, BASIC or emulator → 57–60, no verdict → 80. See risk scoring.
Other members
Errors are a sealed
GrantivaError: AttestationNotAvailable, NetworkError, ServerError, InvalidConfiguration, TokenExpired, VerificationFailed.
Token caching
Tokens are stored inEncryptedSharedPreferences and reused until 60 seconds before expiry. Call attest() whenever you need a token — it returns the cached copy when one is still valid and only runs a full Play Integrity flow when it has to. There is no need to cache the token yourself.
Emulators and CI
Play Integrity needs real Google Play Services, so it cannot succeed on a bare emulator. Pass an API key to fall back to key auth — the same escape hatch the iOS SDK uses for the Simulator:The device ID is not hardware-bound
This is the one place Android differs materially from iOS, and it affects billing. On iOS the device identity derives from a Secure Enclave key, so it survives app reinstalls. On Android the device ID is a UUID stored inEncryptedSharedPreferences. It is not hardware-bound, so:
- A fresh install produces a new device ID
- The new ID counts as a new device against your Monthly Active Devices quota
clearStoredData()has the same effect — use it only for sign-out or testing
deviceId claim reflects this, so your backend can account for it rather than assuming an ID is stable across installs.