Skip to main content

Android - Camera Module Interface

The CameraModule interface is used when you want to override the default camera capture functionality with your own custom native flow. By implementing this interface, you can integrate third-party camera SDKs, custom capture experiences, or specialized document scanning solutions directly into the mobile application.

The module utilizes Android's ActivityResultContract to seamlessly connect your custom camera flow with the main application. When a camera capture is requested, your custom activity is launched, and the results are parsed back into the application using the CameraModuleResult type through the contract's parseResult callback.

Implementation

Create a class that implements the CameraModule interface. Once implemented, override the required methods and implement your custom camera logic.

/**
* Example CameraModule implementation.
*
* A CameraModule allows you to override the default camera capture flow with custom
* camera functionality. This enables integration of third-party camera SDKs,
* specialized document capture, or custom image processing workflows.
*/
class CameraModuleExample(private val sdkUtils: SdkUtils): CameraModule {

override val contract =
object : ActivityResultContract<CameraModuleConfiguration, CameraModuleResult?>() {
override fun createIntent(context: Context, input: CameraModuleConfiguration): Intent {
return MyActivity.newIntent(context, params)
}

override fun parseResult(resultCode: Int, intent: Intent?): CameraModuleResult? {
return parseResults(resultCode, intent)
}
}

/**
* Called when user submits captured images. Return true to handle submission yourself,
* or false to let the default flow continue. If returning true, you must call the
* appropriate callback method (onSubmissionSuccess/onSubmissionError) when finished.
*/
override fun submitCapturedImages(
captureResult: CameraModuleResult.Success,
callback: CameraModuleSubmissionCallback
): Boolean {
// Handle custom submission logic here
callback.onSubmissionSuccess()
return true
}

/**
* Converts the activity result from your camera flow into a CameraModuleResult.
* Uses standard Android activity result codes to determine success or failure.
*/
private fun parseResults(resultCode: Int, intent: Intent?): CameraModuleResult? {
return when {
resultCode == Activity.RESULT_CANCELED -> {
CameraModuleResult.Failed(
CameraModuleConstants.ErrorCodes.USER_CANCELLED,
"User cancelled camera capture"
)
}

resultCode != Activity.RESULT_OK -> {
CameraModuleResult.Failed(
CameraModuleConstants.ErrorCodes.ACTIVITY_FAILED,
"Camera failed with code: $resultCode"
)
}

intent == null -> {
CameraModuleResult.Failed(
CameraModuleConstants.ErrorCodes.NO_DATA,
"No data returned from camera"
)
}

else -> parseSuccessfulResult(intent)
}
}

/**
* Extracts image data from a successful camera activity result.
* Parse the Intent data according to your camera implementation and return a CameraModuleResult.
*/
private fun parseSuccessfulResult(intent: Intent): CameraModuleResult {

val errorCode = intent.getStringExtra(CameraModuleConstants.ERROR_CODE_KEY)
if (errorCode != null) {
val errorMessage = intent.getStringExtra(CameraModuleConstants.ERROR_MESSAGE_KEY)
?: "Unknown camera error"
return CameraModuleResult.Failed(
CameraModuleConstants.ErrorCodes.LICENSE_ERROR,
errorMessage
)
}

// Parse image file paths. Depending on the flow, one or both may be returned.
val frontImagePath = intent.getStringExtra(CameraModuleConstants.FRONT_IMAGE_RESULT_KEY)
val backImagePath = intent.getStringExtra(CameraModuleConstants.BACK_IMAGE_RESULT_KEY)

// Create result based on which images were captured
return when {
frontImagePath != null && backImagePath != null -> {
CameraModuleResult.Success(File(frontImagePath), File(backImagePath))
}

frontImagePath != null -> {
CameraModuleResult.Success(File(frontImagePath), null)
}

backImagePath != null -> {
CameraModuleResult.Success(null, File(backImagePath))
}

else -> {
CameraModuleResult.Failed(
CameraModuleConstants.ErrorCodes.NO_IMAGES,
"No images were captured"
)
}
}
}
}

Key Components

ActivityResultContract

The contract property defines how your custom camera activity is launched and how results are processed. The createIntent method launches your camera activity, while parseResult converts the activity result into a CameraModuleResult that the main application can understand.

submitCapturedImages Method

This callback is triggered when the user attempts to submit captured images. You can implement custom validation, processing, or submission logic here. Return true if you want to handle the entire submission flow yourself, or false to let the default flow continue.

CameraModuleResult Types

Your parseResult method must return one of these result types:

  • CameraModuleResult.Success - Contains the captured image files (front and/or back)
  • CameraModuleResult.Failed - Contains an error code and descriptive message

Update Your settings.json

Ensure your settings.json file in the root of the DevApp is updated to reflect your module changes. Learn more in Configuring settings.json.