Migration Guide: MRZScanner SDK to to barKoder SDK (Android)
This guide explains how to replace the MRZScanner SDK with the barKoder SDK in an existing Android app.
It assumes MRZScanner is already integrated and you’re now migrating to barKoder while preserving as much of your current app structure and UI as possible.
The goal is to show you:
- The key conceptual differences between MRZScanner and barKoder
- How the MRZ result model changes
- Which parts of your code you need to update
Difference overview between the two SDKs #
| MRZ Scanner SDK | barKoder SDK | |
|---|---|---|
Uses a Fragment (MRZScanner) in XML | Gives you a View (BarkoderView) that you embed. | |
You implement MRZScannerListener with successfulScan(withResult:). | You implement BarkoderResultCallback with scanningFinished(decoderResults:thumbnails:image:). | |
You get a strongly typed MRZResultModel with properties like first_name, date_of_birth_readable, etc. | The MRZ data comes as a JSON-like dictionary in decoderResult.extra. | |
SDK configuration (vibration, session closing, duplicate threshold, etc.) lives in BarkoderConfig. |
#
1. Migration checklist #
1.1. Remove MRZScanner SDK aar or dependency and imports. #
For this step please remove all reference to the old MRZScanner SDK
1.2. Integrate barKoder SDK (Using Official Documentation) #
For detailed instructions on integrating barKoder into your Android project, please refer to the barKoder Android SDK installation guide.
1.3. Replace fragment with a BarkoderView property in your xml file #
MRZScanner used framgent which needs to be replaced with the BarkoderView Property
<fragment
android:id="@+id/scannerFragment"
android:name="com.scansolutions.mrzscannerlib.MRZScanner"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.barkoder.BarkoderView
android:id="@+id/barkoderView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
1.4. Configure BarkoderView with: #
BarkoderConfig(applicationContext , licenseKey)
decoderConfig.IDDocument.enabled = true
//for MRZ/ID documents.
config.setVibrateOnSuccessEnabled, config.setImageResultEnabled
1.5. Update your listener in activity class to conform to BarkoderResultCallback and implement scanningFinished(decoderResults:thumbnails:image:).
#
Update your existing listener to implement BarkoderResultCallback so that all scan results, generated thumbnails, and the captured image are returned through the scanningFinished callback.
1.6. Start scanning with try barkoderView.startScanning(this).
#
Start the scanning process by calling startScanning on your barkoderView, passing the current context and handling any thrown errors to ensure the scanner is initialized correctly.
1.7. Update all places that used MRZResultModel to now read MRZ fields from DecoderResult.extra ([AnyHashable:Any]).
#
Replace all usages of MRZResultModel with lookups on the extra dictionary in DecoderResult, reading the MRZ-related fields directly from there.
2. Initialization & licensing #
Before – MRZScannerSDK #
import com.scansolutions.mrzscannerlib.MRZResultModel
import com.scansolutions.mrzscannerlib.MRZScanner
import com.scansolutions.mrzscannerlib.MRZScannerListener
import com.scansolutions.mrzscannerlib.ScannerType
class ScannerActivity : BaseActivity<ScannerContract.View, ScannerPresenter>(), MRZScannerListener, {
private fun setupScanner() {
scanner = supportFragmentManager.findFragmentById(R.id.scannerFragment) as MRZScanner
MRZScanner.setIDActive(sharedPreferencesHelper.getIDActiveSetting()) MRZScanner.setPassportActive(sharedPreferencesHelper.getPassportActiveSetting()) MRZScanner.setVisaActive(sharedPreferencesHelper.getVisaActiveSetting()) MRZScanner.setMaxThreads(sharedPreferencesHelper.getMaxCPUCoresSetting()) MRZScanner.registerWithLicenseKey(this, getString(R.string.*mrz_key*)) scanner?.setScanningRectangle(SCANNING_RECT_X,SCANNING_RECT_Y,SCANNING_RECT_WIDTH, SCANNING_RECT_HEIGHT)
override fun successfulScanWithResult(resultModel: MRZResultModel) {
val resultDataModel = AMRZResultDataModel(resultModel) resultDataModel.portrait = resultModel.portrait
resultDataModel.signature = resultModel.signature
resultDataModel.fullImage = resultModel.fullImage
resultDataModel.idBack = resultModel.idBack
resultDataModel.idFront = resultModel.idFront
}
}
After – barKoder SDK #
import com.barkoder.Barkoder;
import com.barkoder.BarkoderConfig;
import com.barkoder.BarkoderHelper;
import com.barkoder.BarkoderView;
import com.barkoder.interfaces.BarkoderResultCallback;
public class MainActivity extends AppCompatActivity implements BarkoderResultCallback {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
var barkoderConfig = new BarkoderConfig(getApplicationContext(), "LICENSE_KEY",
new Barkoder.LicenseCheckListener() {
@Override
public void onLicenseCheck(Barkoder.LicenseCheckResult licenseCheckResult) {
Log.i(TAG, "license check result: " + licenseCheckResult.message);
});
bkdView.config = barkoderConfig
setBarkoderSettings()
bkdView.config.decoderConfig.IDDocument.enabled = true
bkdView.startScanning(this)
}
override fun scanningFinished(
results: Array<Barkoder.Result>,
thumbnails: Array<Bitmap>,
resultImage: Bitmap?
) {
results.forEach { result ->
result.images?.forEach { img ->
when ([img.name](http://img.name/)) {
"main" -> mainBitmap = img.image
"document" -> documentBitmap = img.image
"signature" -> signatureBitmap = img.image
"picture" -> pictureBitmap = img.image
}
}
}
}`
private fun setBarkoderSettings() {
// These are optional settings, otherwise default values will be used
bkdView.config.let{ config ->
// Optional: image results (thumbnail & full image)
config.isImageResultEnabled = true
config.setThumbnailOnResultEnabled(true)
// Behaviour similar to "single scan then stop"
config.isCloseSessionOnResultEnabled = true
// Your MRZ → barKoder “vibration” mapping:
config.isVibrateOnSuccessEnabled = true
config.decoderConfig.decodingSpeed = Barkoder.DecodingSpeed.*Slow*
config.barkoderResolution = BarkoderResolution.*FHD*
config.isBeepOnSuccessEnabled = true
config.setRegionOfInterest(0f, 30f, 100f, 40f)
}
}
3.MRZ result data: what changes and how to adapt #
3.1 What you used to get (MRZResultModel) #
From successfulScan(withResult:):
override fun successfulScanWithResult(resultModel: MRZResultModel) {
// MRZScanner properties:
result.document_type
result.document_number
result.given_names
result.surnames
result.nationality
result.issuing_country
result.sex
result.date_of_birth_readable
result.date_of_birth_raw
result.expiration_date_readable
result.expiration_date_raw
result.estimated_issuing_date_readable
result.estimated_issuing_date_raw
result.optional_value
result.personal_number_raw
}
3.2 What you now get (barKoder) #
In the extra field, the JSON contains three variants of the data:
| Key | Description | Example value |
|---|---|---|
normal | Normalized MRZ value | "P" |
formatted | Human readable value | "Passport" |
raw | Full MRZ string from the document | "P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<" |
From scanningFinished:
override fun scanningFinished(
results: Array<Barkoder.Result>?,
thumbnails: Array<Bitmap>?,
resultImage: Bitmap?)
{
// 1. Check if we have any results
if (results.isNullOrEmpty()) return
// 2. Take the first scanned result
val result = results[0]
// 3. Find the JSON string in extra fields
var jsonStr = ""
result.extra?.forEach { kv ->
if (kv.key.equals("JSON", ignoreCase = true)) {
jsonStr = kv.value?.trim() ?: ""
return@forEach
}
}
// 4. Parse the JSON if available
if (jsonStr.isNotEmpty()) {
try {
// Clean up string
jsonStr = jsonStr.replace("\n", "")
.replace("\r", "")
.replace("\t", "")
// Convert to JSON object
val mrzObject = JSONObject(jsonStr)
val fields = mrzObject.getJSONObject("normal")// "normal" = formatted
// 5. Extract MRZ fields
val documentType = fields.optString("document_type")
val firstName = fields.optString("first_name")
val lastName = fields.optString("last_name")
val nationality = fields.optString("nationality")
val gender = fields.optString("gender")
val documentNumber = fields.optString("document_number")
val dateOfBirth = fields.optString("date_of_birth")
val dateOfExpiry = fields.optString("date_of_expiry")
val rawMRZ = mrzObject.optString("raw") // full MRZ string
} catch (e: JSONException) {
Log.e("Barkoder", "JSON parsing error", e)
}
} else {
Log.d("Barkoder", "No JSON data found in result")
}
}
3.3 Side-by-side property differences #
| Old | New |
| document_type | document_type |
| document_number | document_number |
| given_names | first_name |
| surnames | last_name |
| nationality | nationality |
| issuing_country | issuing_country |
| sex | gender |
| date_of_birth_raw | date_of_birth |
| expiration_date_raw | date_of_expiry |
| estimated_issuing_date_raw | date_of_issuance_estimated |
| personal_number_raw | personal_number |
| optional_value | optional_data |
4.Behavioral features: continuous scanning, duplicates, vibration #
4.1 Vibration #
MRZScanner.setEnableVibrationOnSuccess(true)
bkdView.config.isVibrateOnSuccessEnabled = true
4.2 Beep #
barKoder #
bkdView.config.isBeepOnSuccessEnabled = true
4.3 Scan once then stop vs continuous scanning #
With MRZScanner you had:
mrzScanner.setContinuousScanningEnabled(false)
With barKoder, the equivalent behavior is to close the session after the first result:
// SINGLE-SCAN MODE
bkdView.config.isCloseSessionOnResultEnabled = true
For continuous scanning, keep the session open and tweak the duplicate threshold:
// keep session open
bkdView.config.isCloseSessionOnResultEnabled = false
bkdView.config.thresholdBetweenDuplicatesScans = 5
closeSessionOnResultEnabled controls whether scanning stops after the first result, and thresholdBetweenDuplicatesScans controls how often the same code is scanned.
If you previously used setIgnoreDuplicates(true) in MRZScanner,set:
bkdView.config.thresholdBetweenDuplicatesScans = -1
// scan it only once, no duplicates
5.Quick “Old → New” Cheat Sheet #
5.1 Callbacks #
class ScannerActivity : AppCompatActivity(), MRZScannerListener,{
override fun successfulScanWithResult(resultModel: MRZResultModel) {
}
}
class MainActivity : AppCompatActivity(), BarkoderResultCallback {
override fun scanningFinished(results: Array<Barkoder.Result>?, thumbnails: Array<Bitmap>?, resultImage: Bitmap?) {
}
}
5.2 MRZ Mode #
mrzSanner?.setScannerType(scannerType)
MRZScanner.setIDActive(true)
MRZScanner.setPassportActive(true)
MRZScanner.setVisaActive(true)
bkdView.config.decoderConfig.IDDocument.enabled = true
5.3 Document Image Mode #
scanner?.setScannerType(SCANNER_TYPE_DOC_IMAGE_ID)
bkdView.config.decoderConfig.IDDocument.enabled = true
Barkoder.SetCustomOption(bkdView.config.decoderConfig, "decode_document_image_only" , 1)
5.4 Image Scan #
scanner.enableScanFromGallery(true)
You can add a custom button that presents a photo picker; once the user selects an image, pass it to barkoderView like this, and you will receive the results in scanningFinished:
val configScanimage = bkdview.config.decoderConfig
configScanimage.decoderConfig.decodingSpeed = Barkoder.DecodingSpeed.Rigorous
BarkoderHelper.scanImage(
bitmap,
configScanimage,
object : BarkoderResultCallback {
override fun scanningFinished(
results: Array<Barkoder.Result>,
thumbnails: Array<Bitmap>,
resultImage: Bitmap
) {
// Forward to MainActivity method
this@MainActivity.scanningFinished(results, thumbnails, resultImage)
}
},
this
)