My sample project source code in GitHub

Using Google MLKit

Add dependencies

1
2
3
4
5
6
7
8
9
10
dependencies {
...
implementation 'androidx.camera:camera-lifecycle:1.2.1'
implementation 'com.google.mlkit:barcode-scanning:17.0.3'

def camerax_version = "1.2.1"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"
}

Request camera permission

1
<uses-permission android:name="android.permission.CAMERA" />
1
2
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
// Request camera permissions
if (allPermissionsGranted()) {
startPreview()
} else {
ActivityCompat.requestPermissions(
this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
}
}

override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
startPreview()
} else {
Toast.makeText(this,
"Permissions not granted by the user.",
Toast.LENGTH_SHORT).show()
finish()
}
}
}

private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
baseContext, it) == PackageManager.PERMISSION_GRANTED
}

Bind preview and image analyzer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private fun startPreview(){
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
bindPreview()
}, ContextCompat.getMainExecutor(this))
}

private fun bindPreview() {
var preview = Preview.Builder()
.build()

var cameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()

preview.setSurfaceProvider(previewView.surfaceProvider)

val analyzer = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()

cameraExecutor = Executors.newSingleThreadExecutor()
analyzer?.let {
it.setAnalyzer(cameraExecutor) { imageProxy ->
handleImage(imageProxy)
imageProxy.close()
}
}

try {
val cameraProvider = cameraProviderFuture.get()
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, cameraSelector, preview, analyzer)
} catch (e: Exception) {
Log.e("ScanQRCode Test APP", "cameraProvider binding failed!", e)
}
}

Handle QRCode image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private fun handleImage(imageProxy: ImageProxy){
val mediaImage = imageProxy.image
if (mediaImage != null) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)

// Pass image to an ML Kit Vision API
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_AZTEC)
.build()

val scanner = BarcodeScanning.getClient(options)
scanner.process(image).addOnSuccessListener { barcodes ->
for (barcode in barcodes) {
// Handle received barcodes...
println("Scan result: ${barcode.rawValue}")

Toast.makeText(
this,
"Scan result: ${barcode.rawValue}",
Toast.LENGTH_SHORT
).show()

cameraExecutor.shutdown()
finish()
}
}
}
}

Reference

Other methods

Zxing

com.google.android.gms.vision.barcode