Android Quick Start
From zero to a YES verdict on an Android device in ten minutes.
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 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. 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 withHIGHconfidence indoors on Android. Finer-grained predicates (city, polygon) may need a GPS fix. See Concepts: Verdicts.
7. From here
- The Android sample app is a single-button activity that exercises this whole flow.
- Concepts: Proof of Location explains what a verdict actually proves.
- API Reference Overview maps the public surface.