This page covers the Android migration from SDK 5.17.x to SDK 6.0.0-beta11.
ScanFlowConfiguration and receives a FlowOutput.ScanFragment API is CameraX-only; the legacy camera implementation and ScanFragmentLegacy were removed.Use this section if your app launches the SDK-provided document scan flow or barcode scan flow. Start with the Android requirements; they apply to every Android SDK 6 integration, including custom integrations.
minSdkVersion to 23.com.geniusscansdk:gssdk:6.0.0-beta11.android {
defaultConfig {
minSdkVersion 23
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
kotlin {
jvmToolchain(17)
}
dependencies {
implementation "com.geniusscansdk:gssdk:6.0.0-beta11"
}
SDK 5 made your app create an Intent, launch it with Android’s generic activity result contract, then parse the returned Intent. SDK 6 moves that work into ScanActivity.Contract: your app launches a configuration object and receives a typed result.
The core shape of the migration is:
| SDK 5 | SDK 6 |
|---|---|
ScanConfiguration |
ScanFlowConfiguration |
ScanFlow.createScanFlowIntent(...) with ActivityResultContracts.StartActivityForResult() |
ScanActivity.Contract |
Manual result parsing with ScanFlow.getScanResultFromActivityResult(intent) |
FlowOutput<ScanFlowResult> |
ScanResult |
ScanFlowResult |
Before:
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val intent = result.data.takeIf { result.resultCode == RESULT_OK } ?: return@registerForActivityResult
val scanResult = ScanFlow.getScanResultFromActivityResult(intent)
}
val intent = ScanFlow.createScanFlowIntent(this, configuration)
launcher.launch(intent)
After:
val launcher = registerForActivityResult(ScanActivity.Contract()) { output ->
when (output) {
is FlowOutput.Success -> handleScanResult(output.result)
is FlowOutput.Error -> handleScanFlowError(output.error)
}
}
launcher.launch(configuration)
Most types that were nested under ScanConfiguration moved with the configuration class. For example:
// SDK 5
ScanConfiguration.Source.CAMERA
// SDK 6
ScanFlowConfiguration.Source.CAMERA
Apply the same rule to configuration-specific enums and nested classes such as source, flash mode, filters, multi-page output, PDF page size, OCR configuration, and structured data options. Other SDK types keep their own owner type. For exhaustive property and nested-type details, use the ScanFlowConfiguration API reference.
In SDK 5, the activity result callback received a regular Android ActivityResult. Your app usually treated a non-RESULT_OK result as a cancellation, then parsed the result Intent. Errors raised while parsing the result were thrown as exceptions, so licensing and other failures were handled with try/catch.
Before:
val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val intent = result.data.takeIf { result.resultCode == RESULT_OK } ?: return@registerForActivityResult
try {
val scanResult = ScanFlow.getScanResultFromActivityResult(intent)
handleScanResult(scanResult)
} catch (error: LicenseException) {
handleLicensingError(error)
} catch (error: Exception) {
handleScanFlowError(error)
}
}
In SDK 6, the scan flow contract decodes the activity result for you. The callback receives a FlowOutput<ScanFlowResult> directly: success, cancellation, licensing errors, and other failures are all represented by the output value.
The Android ScanFlowErrorCode cases now follow the same error typology as the other SDK 6 platforms:
| Error code | Meaning |
|---|---|
ScanFlowErrorCode.CANCELLATION |
The user canceled the scan flow. |
ScanFlowErrorCode.CONFIGURATION |
The scan flow was launched with invalid or unsupported configuration. |
ScanFlowErrorCode.LICENSING |
The license is invalid, expired, or not initialized. |
ScanFlowErrorCode.CAPTURE |
The camera or capture flow failed. |
ScanFlowErrorCode.STORAGE_SPACE |
The device does not have enough storage space to complete the flow. |
ScanFlowErrorCode.INTERNAL |
The SDK hit an unexpected error. |
After:
val launcher = registerForActivityResult(ScanActivity.Contract()) { output ->
when (output) {
is FlowOutput.Success -> handleScanResult(output.result)
is FlowOutput.Error -> handleScanFlowError(output.error)
}
}
private fun handleScanFlowError(error: ScanFlowError) {
when (error.code) {
ScanFlowErrorCode.CANCELLATION -> return
ScanFlowErrorCode.LICENSING -> handleLicensingError(error)
else -> handleError(error)
}
}
For licensing failures, error.underlyingError may contain the original LicenseException. Use it if you need to inspect the underlying licensing failure. See ScanFlowError and ScanFlowErrorCode for the complete API.
If your app uses the standalone readable-code scanner, migrate it to the barcode flow. The package moved from com.geniusscansdk.readablecodeflow to com.geniusscansdk.barcodeflow, and the result now uses the same FlowOutput pattern as the document scan flow.
| SDK 5 | SDK 6 |
|---|---|
ReadableCodeFlow.createContract() |
BarcodeScanActivity.Contract |
ReadableCodeConfiguration |
BarcodeScanFlowConfiguration |
ReadableCodeFlowResult.Success.codes |
FlowOutput.Success<BarcodeScanFlowResult>.result.codes |
ReadableCode |
Barcode |
Example:
val launcher = registerForActivityResult(BarcodeScanActivity.Contract()) { output ->
when (output) {
is FlowOutput.Success -> showBarcodes(output.result.codes)
is FlowOutput.Error -> handleScanFlowError(output.error)
}
}
launcher.launch(
BarcodeScanFlowConfiguration(
supportedCodeTypes = listOf(Barcode.Type.QR, Barcode.Type.Code128),
isBatchModeEnabled = true
)
)
If your SDK 5 code ignored ReadableCodeFlowResult.Canceled, migrate that case to a FlowOutput.Error whose error code is ScanFlowErrorCode.CANCELLATION.
If your document scan flow extracts readable codes as structured data, update that configuration to barcode terminology as well.
Before:
configuration.structuredData = EnumSet.of(ScanConfiguration.StructuredData.READABLE_CODE)
configuration.structuredDataReadableCodeTypes = EnumSet.of(ReadableCode.Type.QR)
val codes = scan.structuredDataResult?.readableCodes
After:
configuration.structuredData = EnumSet.of(ScanFlowConfiguration.StructuredData.BARCODE)
configuration.structuredDataBarcodeTypes = EnumSet.of(Barcode.Type.QR)
val barcodes = scan.structuredDataResult?.barcodes
The Android scan result model still exposes scan.structuredDataResult; the barcode list inside that result is now barcodes. The full configuration surface is documented in ScanFlowConfiguration, and barcode result values are documented in Barcode.
Use this section if your app embeds the SDK camera or lower-level scanning components instead of launching the SDK-provided scan flow. The Android requirements from the Simple Integration section still apply.
The custom Android camera now uses CameraX only. In SDK 5, ScanFragment.createBestForDevice() selected the best implementation for the current device: CameraX when possible, or the legacy camera implementation otherwise.
SDK 6 removes that legacy path, including ScanFragmentLegacy. Because there is no fallback implementation to choose anymore, migrate ScanFragment.createBestForDevice() to direct ScanFragment instantiation.
Before:
ScanFragment scanFragment = ScanFragment.createBestForDevice();
After:
ScanFragment scanFragment = new ScanFragment();
The callback interface still exists, but callback methods now have default empty implementations. You only need to override the callbacks your app uses. See the ScanFragment API reference for the complete custom camera surface.
If your app consumes preview frames, update the onPreviewFrame signature:
// SDK 5
void onPreviewFrame(byte[] frame, int width, int height, int format);
// SDK 6
void onPreviewFrame(Image image, int rotationDegrees);
Image is android.media.Image. The SDK closes it after the callback returns, so do not close it from your callback. See ScanFragment.Callback.onPreviewFrame for details.
After applying the sections that match your integration, build your app with SDK 6 and run through the scan paths your users rely on.
For simple integrations, validate document scan launch, barcode scan launch, success results, cancellation, licensing failures, and any custom error UI built from ScanFlowError. If your app extracts barcodes as structured data or generates multi-page output, check those result fields and files against your SDK 5 behavior.
For custom integrations, validate camera permission handling, CameraX startup, lifecycle transitions, manual capture, auto-capture, callback delivery, and preview-frame processing if you use it.
Start with a free trial license to test the SDK, or contact us directly for a custom quote tailored to your needs.
© 2026 The Grizzly Labs. All rights reserved.