Skip to main content

Android SDK

Release: assayra-android 1.0.0
Minimum Android API: 26
Build requirements: Android Gradle Plugin 8.7+, Kotlin 2.1 and Java 17

1. Download and verify

  1. Download assayra-android-sdk-1.0.0.tar.gz.
  2. Verify it against SHA256SUMS.
  3. Extract it into your Android repository:
mkdir -p vendor/assayra-android-sdk-1.0.0
tar -xzf assayra-android-sdk-1.0.0.tar.gz \
-C vendor/assayra-android-sdk-1.0.0

The public Maven coordinate is not live yet; use this versioned local module for the current trial.

2. Add the local Gradle module

Add the extracted folder to your project’s settings.gradle.kts:

include(":assayra-sdk")
project(":assayra-sdk").projectDir =
file("vendor/assayra-android-sdk-1.0.0")

Add the dependency in app/build.gradle.kts:

dependencies {
implementation(project(":assayra-sdk"))
}

Sync Gradle and confirm the module compiles:

./gradlew :app:assembleDebug

The SDK declares INTERNET, CAMERA and optional NFC capability in its manifest. Your app must still request camera permission at runtime.

3. Receive a scoped token

Your backend creates the application and returns the opaque token from the issued applicant URL to the signed-in app. Never put a Sandbox or Live tenant API key in BuildConfig, resources, the APK/AAB or remote logging.

import com.assayra.sdk.Assayra
import com.assayra.sdk.AssayraConfiguration

val configuration = AssayraConfiguration(
webOrigin = "https://your-assayra-origin.example",
verificationToken = invitationToken,
)

val assayra = Assayra.create(configuration)

Option A — hosted Custom Tab

verifyButton.setOnClickListener {
assayra.launchHostedVerification(this)
}

This is the lowest-maintenance Android option. It uses the user’s updated browser security, camera and accessibility behavior. Reconcile completion through your backend webhook rather than assuming the tab return is a result.

Option B — embedded hosted View

val verificationView = assayra.createVerificationView(this) { event ->
when (event) {
is AssayraEvent.Complete -> showPendingResult(event.reference)
is AssayraEvent.Error -> showSafeError(event.code)
else -> Unit
}
}

container.addView(verificationView)

The View disables mixed/file/content access, constrains navigation to the configured origin and passes only validated versioned events. Remove/destroy the View with its host lifecycle and do not retain applicant URLs in saved analytics state.

Option C — headless Kotlin client

Call SDK methods from a lifecycle-aware coroutine:

import androidx.lifecycle.lifecycleScope
import com.assayra.sdk.AssayraClient
import com.assayra.sdk.AssayraIdentity
import kotlinx.coroutines.launch

val client = AssayraClient(configuration)

lifecycleScope.launch {
val session = client.sessionStatus()
if (session.currentStep == "identity") {
client.submitIdentity(
AssayraIdentity(
givenName = "Amara",
familyName = "Vale",
dateOfBirth = "1992-06-14",
nationality = "SG",
email = "person@example.com",
address = "Applicant supplied address",
)
)
}
}

Re-read sessionStatus() after resume or failure. Do not hard-code one step sequence or store protected byte arrays longer than the scoped upload.

4. Request camera permission

private val cameraPermission = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) capture.start() else showCameraAlternative()
}

cameraPermission.launch(Manifest.permission.CAMERA)

Explain why the camera is needed before triggering the system prompt. Provide a policy-approved alternative when permission is permanently denied.

5. Automatic face capture

Use the SDK capture View when possible:

val capture = assayra.createLivenessCaptureView(
context = this,
integrityProvider = playIntegrityProvider,
) { state ->
when (state) {
is AssayraNativeCaptureState.Completed -> continueJourney(state.response)
is AssayraNativeCaptureState.Failed -> showCaptureError(state.message)
else -> Unit
}
}

container.addView(capture)

After permission is granted, call capture.start() from onStart; call capture.stop() before super.onStop(). A backgrounded, disconnected or cancelled capture does not submit a partial evidence set.

For a custom CameraX UI, request livenessChallenge(), send reduced JPEGs through observeLiveness, show server guidance, auto-capture only after stable challenge-correct observations, then send exactly three fresh full-quality frames through submitLiveness.

6. Play Integrity and NFC

  • Generate the Play Integrity token against the current server challenge; never reuse it.
  • Enable NFC only for workflows and documents that require it.
  • Request the NFC interaction when the app is foregrounded.
  • Upload DG1, DG2, SOD, portrait and signed reader evidence through the SDK completion method.
  • Clear document byte arrays after upload.

Assayra performs server-side device/evidence validation. A local boolean must never become an application approval.

7. Test the SDK module

Run the included unit tests from the extracted SDK folder:

./gradlew test

In your application, test current supported devices for permission denial, lifecycle background/resume, no NFC, failed/aborted chip reads, offline retry, expired tokens and verified webhook completion.

Upgrade or remove

To upgrade, download and verify the new version, extract it into a new versioned folder, update projectDir, sync Gradle and test in Sandbox before deleting the previous version.

To remove, delete implementation(project(":assayra-sdk")), remove the module mapping from settings.gradle.kts, remove permissions used only by Assayra, then remove the vendor folder.