Docs/Mobile SDK/Getting Started

Android Quick Start

Install the SDK, start it, and get a first verdict on an Android device.

Note

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:3.1.2")
}

Pin 3.1.2 or later. If you are on 3.0, read What's new in 3.1. If you are on 2.x, read Upgrading from 2.x first. If you are on 1.x, read Migrating from 1.x as well.

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 needs a location permission to start, precise or approximate. Request ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION together, so the user can choose. With approximate location only, country proofs work, finer levels return INSUFFICIENT_PRECISION, and a proof is at most PLAUSIBLE. Motion-classification confidence degrades without ACTIVITY_RECOGNITION. Request these before calling Octet.start(...):

ActivityCompat.requestPermissions(
    this,
    arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_COARSE_LOCATION,
        Manifest.permission.ACTIVITY_RECOGNITION,
    ),
    REQUEST_CODE
)

Wait for onRequestPermissionsResult(...) to confirm that a location permission, precise or approximate, 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 sdk = Octet.start(context = applicationContext, config = OctetConfig())
    // 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(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. Query a region

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 returns YES with an attached proof.
  • On the Android emulator the verdict is always INDETERMINATE / NO_FIX with the message running on emulator — location proofs are unavailable in this environment. Run on hardware to see the full flow.
  • On a real device, indoors, a country query can often answer. See Concepts: Verdicts.

8. Next steps

TermsPrivacy© 2026 Understone, Inc. d/b/a Octet