Skip to main content

Android Quick Start

From zero to a YES verdict on an Android device in ten minutes.

note

Work through Prerequisites first. You will need a license key 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:0.0.1-alpha")
}

Sync Gradle. The SDK's AndroidManifest.xml permissions merge into your manifest automatically. No manual permission declarations needed.


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

import com.octetproof.sdk.api.Octet
import com.octetproof.sdk.api.OctetConfig

lifecycleScope.launch {
val sdk = Octet.start(
context = applicationContext,
config = OctetConfig(licenseKey = "octet_live_v4.public.…")
)
// sdk is ready
}

Octet.start(...) is a suspend function. Call it from a coroutine scope (lifecycleScope, viewModelScope, or your own). On first launch the SDK verifies the license key locally, exchanges it for an activation token via api.octetproof.com/v1/activate, caches the token in EncryptedSharedPreferences, and brings up the proof pipeline.

Any license problem throws a typed LicenseError. See License Types.


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. The result is a trichotomy. Never treat INDETERMINATE as NO.


6. 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 will always be INDETERMINATE / NO_FIX with the message running on emulator — location proofs are unavailable in this environment. This is by design. The emulator's mock-location flag blocks proof generation. 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. isWithin(country(...)) typically succeeds with HIGH confidence indoors on Android. Finer-grained predicates (city, polygon) may need a GPS fix. See Concepts: Verdicts.

7. From here