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
- Download
assayra-android-sdk-1.0.0.tar.gz. - Verify it against
SHA256SUMS. - 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.