Android Quick Start
From zero to a YES verdict on an Android device in ten minutes.
Work through Prerequisites first. You will need a registered app (or a sandbox token for local development) and a plan for runtime permissions.
1. Add the Maven repo
In your project's root settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://raw.githubusercontent.com/octetproof/octet-sdk-android/mvn-repo")
}
}
}
The OctetSDK Maven artifacts live on the mvn-repo orphan branch of the public octet-sdk-android repository.
2. Add the dependency
In your app build.gradle.kts:
dependencies {
implementation("com.octetproof:sdk:2.0.0")
}
Pin 2.0.0 or later. 2.0 is a major release. If you are on 1.x, read Migrating from 1.x first.
Sync Gradle. The SDK's foreground permissions merge into your manifest automatically. For proofs while the app is backgrounded, add ACCESS_BACKGROUND_LOCATION to your own manifest. See Prerequisites.
3. Request runtime permissions
The SDK refuses to start without ACCESS_FINE_LOCATION. Motion-classification confidence degrades without ACTIVITY_RECOGNITION. Request both before calling Octet.start(...):
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACTIVITY_RECOGNITION,
),
REQUEST_CODE
)
Wait for onRequestPermissionsResult(...) to confirm ACCESS_FINE_LOCATION was granted before continuing.
4. Start the SDK
Octet.start(...) bootstraps the license by attesting the app with Android hardware key attestation, then brings up the proof pipeline. On a real device, no key or token is needed (see Prerequisites).
import com.octetproof.sdk.api.Octet
import com.octetproof.sdk.api.OctetConfig
lifecycleScope.launch {
val config = OctetConfig(licenseKey = "") // required by the type, ignored by start
val sdk = Octet.start(context = applicationContext, config = config)
// sdk is ready
}
On an emulator or a locally built debug build, there is no hardware attestation. Mint a sandbox bypass token (see Prerequisites) and pass it:
val config = OctetConfig(licenseKey = "", sandboxBypassToken = "octet_sbx_…")
Octet.start(...) is a suspend function. Any license or bootstrap problem throws a typed LicenseError. See License Types and Attested bootstrap.
5. Ask your first question
import com.octetproof.sdk.api.OctetRegion
import com.octetproof.sdk.api.OctetVerdict
import java.time.Instant
val verdict = sdk.loc.isWithin(
region = OctetRegion.country("US"),
atTime = Instant.now()
)
when (verdict.result) {
OctetVerdict.Result.YES ->
println("YES, proof attached: ${verdict.proof != null}")
OctetVerdict.Result.NO ->
println("NO, provable negative")
OctetVerdict.Result.INDETERMINATE ->
println("INDETERMINATE, reason: ${verdict.reason}")
}
The predicate returns an OctetVerdict. Never treat INDETERMINATE as NO.
6. Close when done
When your proof flow ends, release the session and stop the location foreground service:
sdk.close()
See Session Lifecycle for why this matters.
7. What to expect
- On a real device, outdoors, with cellular and GPS available,
isWithin(country("US"))typically returnsYESwith an attached proof. - On the Android emulator the verdict will always be
INDETERMINATE / NO_FIXwith the messagerunning on emulator — location proofs are unavailable in this environment. This is by design. Run on hardware to see the full flow. - On a real device, indoors, the first proof on Android usually arrives quickly via the cell-tower MCC signal even without GPS. See Concepts: Verdicts.
8. From here
- The Android sample app exercises this whole flow.
- On-device Verification checks a proof with
Octet.verify, offline. - Proof Binding ties a proof to a login or a decision, and
forceFreshmints one on demand. - Verifying Proofs and the Verifier Quick Start show independent verification.
- What's new in 2.0 lists the full release.