How to Create a QR Code Scanner in Jetpack Compose

Jetpack Compose is Android’s recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. In this article, we are going to create a QR code scanner to demonstrate how to use Dynamsoft Barcode Reader and Dynamsoft Camera Enhancer in Jetpack Compose.

Here is a video of the final result:

SDKs Used

New Project

Open Android Studio and create a new project with an empty compose activity.

new project

Add Dependencies

  1. Open settings.gradle to add Dynamsoft’s maven repository.

     dependencyResolutionManagement {
         repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
         repositories {
             google()
             mavenCentral()
    +        maven {
    +            url "https://download2.dynamsoft.com/maven/aar"
    +        }
         }
     }
    
  2. Add Dynamsoft Barcode Reader and Dynamsoft Camera Enhancer to the module’s build.gradle.

    implementation 'com.dynamsoft:dynamsoftcameraenhancer:2.3.11@aar'
    implementation 'com.dynamsoft:dynamsoftbarcodereader:9.6.20@aar'
    

Add Camera View

Dynamsoft Camera Enhancer provides a CameraView class for camera preview. We can add it to the content and make it occupies the entire screen.

Here is the code to do this:

class MainActivity : ComponentActivity() {
    private lateinit var mCameraEnhancer: CameraEnhancer
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            QRCodeScannerTheme {
                // A surface container using the 'background' color from the theme
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
                    AndroidView(factory = {context ->
                        mCameraEnhancer = CameraEnhancer(context.findActivity())
                        val mCameraView: DCECameraView
                        mCameraView = DCECameraView(context)
                        mCameraView.overlayVisible = true
                        mCameraEnhancer.cameraView = mCameraView
                        mCameraView
                    })
                }
            }
        }
    }
}

It requires the activity instance for initialization. We can define a findActivity function for Context to get it.

//https://stackoverflow.com/a/74696154/17238341
fun Context.findActivity(): ComponentActivity? = when (this) {
    is ComponentActivity -> this
    is ContextWrapper -> baseContext.findActivity()
    else -> null
}

Request Camera Permission and Start the Camera

We have to request camera permission to use the camera.

  1. Define a launcher to request permission. If the permission is granted, then start the camera.

    setContent {
        QRCodeScannerTheme {
            val context = LocalContext.current
            val launcher = rememberLauncherForActivityResult(
                contract = ActivityResultContracts.RequestPermission(),
                onResult = { granted ->
                    if (granted == true) {
                        mCameraEnhancer.open()
                    }
                }
            )
        }
    }
    
  2. The launcher is called when the app starts using LaunchedEffect.

    setContent {
        QRCodeScannerTheme {
            //...
            LaunchedEffect(key1 = true){
                launcher.launch(Manifest.permission.CAMERA)
            }
        }
    }
    

Use Dynamsoft Barcode Reader to Read QR Codes

  1. Set the license. You can apply for a trial license here. If the license is not set, the result will be masked.

    private fun initLicense(){
        BarcodeReader.initLicense(
            "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="  //one-day trial
        ) { isSuccess, error ->
            if (!isSuccess) {
                error.printStackTrace()
            }else{
                Log.d("DBR","license initialized")
            }
        }
    }
    

    Call the function in LaunchedEffect:

    LaunchedEffect(key1 = true){
        initLicense()
    }
    
  2. Create an instance of Barcode Reader and bind the barcode reader with the camera enhancer.

    private lateinit var mBarcodeReader: BarcodeReader
    private fun initDBR(){
        try {
            // Create an instance of Dynamsoft Barcode Reader.
            mBarcodeReader = BarcodeReader()
            // Bind the Camera Enhancer instance to the Barcode Reader instance to get frames from the camera.
            mBarcodeReader.setCameraEnhancer(mCameraEnhancer)
        }catch (e: BarcodeReaderException){
            e.printStackTrace()
        }
    }
    

    Call the function in LaunchedEffect:

    LaunchedEffect(key1 = true){
        initDBR()
    }
    
  3. Start scanning after the camera is opened and display the QR code result on the screen in a Text control above the camera view.

    setContent {
        QRCodeScannerTheme {
            var barcodeTextResult by remember {
                mutableStateOf("")
            }
            val launcher = rememberLauncherForActivityResult(
                contract = ActivityResultContracts.RequestPermission(),
                onResult = { granted ->
                    hasCameraPermission = granted
                    if (granted == true) {
                        mCameraEnhancer.open()
                        startScanning() { result ->
                            barcodeTextResult = result.barcodeFormatString+": "+result.barcodeText
                        }
                    }
                }
            )
               
            //...
               
            Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
                AndroidView(factory = {context ->
                    mCameraEnhancer = CameraEnhancer(context.findActivity())
                    val mCameraView: DCECameraView
                    mCameraView = DCECameraView(context)
                    mCameraView.overlayVisible = true
                    mCameraEnhancer.cameraView = mCameraView
                    mCameraView
                })
                BarcodeText(text = barcodeTextResult)
            }
        }
    }
      
       
    //...
       
    @Composable
    fun BarcodeText(text:String) {
        Text(
            text = text,
            color = Color.White,
            fontSize = 20.sp
        )
    }
       
    private fun startScanning(scanned:(TextResult) -> Unit){
        try{
            mBarcodeReader.setTextResultListener { id, imageData, textResults ->
                if (textResults.size>0) {
                    scanned(textResults[0])
                }
            }
            mBarcodeReader.startScanning()
        } catch (e: BarcodeReaderException) {
            e.printStackTrace()
        }
    }
    

All right, we’ve now finished creating the QR code scanner in Jetpack Compose.

Source Code

Check out the source code of the demo to have a try: https://github.com/tony-xlh/QR-Code-Scanner-Jetpack-Compose