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
MRZScanner SDK #
• Uses a Fragment (MRZScanner) in XML
• You implement MRZScannerListener with successfulScan(withResult:).
• You get a strongly typed MRZResultModel with properties like first_name, date_of_birth_readable, etc.
barKoder SDK #
• Gives you a View (BarkoderView) that you embed.
• You implement BarkoderResultCallback with scanningFinished(decoderResults:thumbnails:image:).
• 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. Remove MRZScanner SDK aar or depndency and imports.
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
barKoder Android SDK installation guide
3.Replace fragment with a BarkoderView property
in your xml file .
4.Configure BarkoderView with:
BarkoderConfig(applicationContext , licenseKey)
decoderConfig.IDDocument.enabled = true for MRZ/ID
documents.• Optional: config.setVibrateOnSuccessEnabled, config.setImageResultEnabled, etc.
6.Update your listener in activity class to conform to
BarkoderResultCallback and
implement
scanningFinished(decoderResults:thumbnails:image:).
7.Start scanning with try barkoderView.startScanning(this).
8.Update all places that used MRZResultModel to now
read MRZ fields from DecoderResult.extra ([AnyHashable:
Any]).
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)
}
}
Note: You must have a valid license with IDDocument enabled. If you start the scanner with IDDocument enabled but your license doesn’t include it, the scanner will return the result: “ID Document decoder type is not licensed!”.In barKoder there are no separate settings for (ID, Visa,Passport). Enabling idDocument automatically:Enables all ID types (ID, Passport, Visa) Validates country codes Supports upside-down (rotated) scanning by default.To stop the scanner you can call stopScanning()
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:
• “normal” – normalized values (for example, the document type for a passport is “P”)
• “formatted” – human-readable values (for example, the document type is “Passport”)
• “raw” – the full MRZ string
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 #
MRZScanner.setEnableVibrationOnSuccess(true)
barKoder #
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 behaviour 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 #
OLD #
class ScannerActivity : AppCompatActivity(), MRZScannerListener,{
override fun successfulScanWithResult(resultModel: MRZResultModel) {
}
}
NEW #
class MainActivity : AppCompatActivity(), BarkoderResultCallback {
override fun scanningFinished(results: Array<Barkoder.Result>?, thumbnails: Array<Bitmap>?, resultImage: Bitmap?) {
}
}
5.2 MRZ Mode #
OLD #
mrzSanner?.setScannerType(scannerType)
MRZScanner.setIDActive(true)
MRZScanner.setPassportActive(true)
MRZScanner.setVisaActive(true)
NEW #
bkdView.config.decoderConfig.IDDocument.enabled = true