Contracts for integrating Eitri Android modules with the Eitri Machine runtime. The package defines lightweight Kotlin interfaces and data classes that standardize how native modules report their capabilities, expose callable methods, and gain access to runtime context supplied by the Eitri SDK.
- Kotlin 1.8.10 or later
- Java 11 or later
- Android 5.0 (API level 21) minimum deployment target
-
EitriModule: Implement this interface in every native module exposed to the Eitri runtime. The runtime callsstart(contextProvider:), and the module must synchronously finish registering the methods it intends to expose. Defer long-running work, as blockingstartwill stall the host application's bootstrapping process. -
EitriContextProvider: A runtime bridge returned to modules duringstart. Use it to read the immutableAppContextand to register suspending functions viaexposeMethod(methodName:method:). -
AppContext: Immutable metadata about the host environment (Eitri SDK version, debug flag, package name, and the AndroidContext). Treat it as read-only state that describes the runtime. -
ModuleExposedMethod: Atypealiasfor suspending functions that modules expose. These functions receiveModuleMethodParamsand may return any result, which will be serialized and sent back to the caller. Throwing an exception will propagate a failure. -
ModuleMethodParams: The invocation payload containing a structureddatapayload (JSONObject), theEitriAppInvokingMethoddescriptor for the requesting eitri-app, and theandroidUIContextavailable to present UI. -
ActivityResultHandler: A contract interface for modules to dynamically register handlers for activity results fromstartActivityForResultoperations. Modules can castandroidUIContextto this interface and register callbacks without requiring tight coupling to specific activity implementations. Handlers are automatically removed after invocation to prevent memory leaks and allow request code reuse. -
PermissionRequesterActivity: A contract interface for requesting Android runtime permissions. Modules can castandroidUIContextto this interface to check and request permissions asynchronously.
The runtime also exposes an EitriModuleRegistry interface that host applications implement to accept modules. Modules should not retain the registry; it should only be used at the initial registration time.
The ActivityResultHandler contract allows modules to handle activity results without tight coupling to the host activity implementation.
- Request codes must be in the range 0-65535 (16-bit values)
- The following request codes are reserved for internal SDK use and cannot be registered:
2019: Document picker operations2026: Web flow operations3020: Camera operations
- Request codes are automatically released after the handler is invoked, allowing reuse
// In your module's exposed method
suspend fun openCustomActivity(params: ModuleMethodParams): String {
val activityResultHandler = params.androidUIContext as? ActivityResultHandler
?: throw Exception("Activity must implement ActivityResultHandler")
return suspendCancellableCoroutine { continuation ->
val requestCode = 5000 // Use a unique code not in the reserved range
// Register handler before launching activity
activityResultHandler.registerActivityResultHandler(requestCode) { resultCode, data ->
when (resultCode) {
Activity.RESULT_OK -> {
val result = data?.getStringExtra("result") ?: "success"
continuation.resume(result)
}
Activity.RESULT_CANCELED -> {
continuation.resumeWithException(Exception("User cancelled"))
}
else -> {
continuation.resumeWithException(Exception("Unexpected result code: $resultCode"))
}
}
}
// Clean up handler if continuation is cancelled before result arrives
continuation.invokeOnCancellation {
activityResultHandler.unregisterActivityResultHandler(requestCode)
}
// Launch the activity
val intent = Intent(params.androidUIContext, CustomActivity::class.java)
params.androidUIContext.startActivityForResult(intent, requestCode)
}
}- Always register handlers before calling
startActivityForResult - Use
invokeOnCancellationto clean up handlers if the coroutine is cancelled - Choose request codes outside the reserved range (avoid 2019, 2026, 3020)
- Validate and sanitize any data received from external activities to prevent injection attacks
- Handlers are automatically removed after invocation, so you don't need to manually unregister them in the success path
eitri-android-contracts/src/main/java/tech/eitri/android/contracts: Contains the Kotlin interfaces and data classes that define the native contract surface.eitri-android-contracts/src/test: Unit tests for the contracts module.