DEV Community

Cover image for QRKit — QRCode Scanning in Compose Multiplatform for Android and iOS
Mobile innovation Network
Mobile innovation Network

Posted on

QRKit — QRCode Scanning in Compose Multiplatform for Android and iOS

QRKit is a Kotlin Multiplatform library for Qr Scan in your Android or iOS App.

Installation

Add the dependency to your build.gradle.kts file:

commonMain.dependencies { implementation("network.chaintech:qr-kit:1.0.2") } 
Enter fullscreen mode Exit fullscreen mode

QrScanner :- Add Permissions in Android and iOS

  • Android : Include this at root level in your AndroidManifest.xml:
<uses-feature android:name="android.hardware.camera"/> <uses-feature android:name="android.hardware.camera.autofocus"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.FLASHLIGHT"/> 
Enter fullscreen mode Exit fullscreen mode
  • iOS : Add below key to the Info.plist in your xcode project:
<key>NSCameraUsageDescription</key><string>$(PRODUCT_NAME) camera description.</string> <key>NSPhotoLibraryUsageDescription</key><string>$(PRODUCT_NAME)photos description.</string> 
Enter fullscreen mode Exit fullscreen mode

Example

QrScanner( modifier: Modifier, flashlightOn: Boolean, launchGallery: Boolean, onCompletion: (String) -> Unit, onGalleryCallBackHandler: (Boolean) -> Unit, onFailure: (String) -> Unit ) 
Enter fullscreen mode Exit fullscreen mode
  • modifier: Modifier for modifying the layout of the QR scanner.
  • flashlightOn: Boolean indicating whether the flashlight is turned on.
  • launchGallery: Boolean indicating whether to launch the gallery for selecting images.
  • onCompletion: Callback invoked when a QR code is successfully scanned.
  • onGalleryCallBackHandler: Callback invoked to indicate the status of the gallery, whether it's open or closed.
  • onFailure: Callback invoked when there's a failure during QR code scanning.

Usage

@Composable fun QrScannerCompose() { var qrCodeURL by remember { mutableStateOf("") } var startBarCodeScan by remember { mutableStateOf(false) } var flashlightOn by remember { mutableStateOf(false) } var launchGallery by remember { mutableStateOf(value = false) } val snackBarHostState = LocalSnackBarHostState.current val coroutineScope = rememberCoroutineScope() Box(modifier = Modifier.fillMaxSize().statusBarsPadding()) { Column( modifier = Modifier .background(color = Color.White) .windowInsetsPadding(WindowInsets.safeDrawing) .fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { if (qrCodeURL.isEmpty() && startBarCodeScan) { Column( modifier = Modifier .background(color = Color.Black) .fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Box( modifier = Modifier .size(250.dp) .clip(shape = RoundedCornerShape(size = 14.dp)) .clipToBounds() .border(2.dp, Color.Gray, RoundedCornerShape(size = 14.dp)), contentAlignment = Alignment.Center ) { QrScanner( modifier = Modifier .clipToBounds() .clip(shape = RoundedCornerShape(size = 14.dp)), flashlightOn = flashlightOn, launchGallery = launchGallery, onCompletion = { qrCodeURL = it startBarCodeScan = false }, onGalleryCallBackHandler = { launchGallery = it }, onFailure = { coroutineScope.launch { if (it.isEmpty()) { snackBarHostState.showSnackbar("Invalid qr code") } else { snackBarHostState.showSnackbar(it) } } } ) } Box( modifier = Modifier .padding(start = 20.dp, end = 20.dp, top = 30.dp) .background( color = Color(0xFFF9F9F9), shape = RoundedCornerShape(25.dp) ) .height(35.dp), contentAlignment = Alignment.Center ) { Row( modifier = Modifier .padding(vertical = 5.dp, horizontal = 18.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(11.dp) ) { Icon(imageVector = if (flashlightOn) Icons.Filled.FlashOn else Icons.Filled.FlashOff, "flash", modifier = Modifier .size(24.dp) .clickable { flashlightOn = !flashlightOn }) VerticalDivider( modifier = Modifier, thickness = 1.dp, color = Color(0xFFD8D8D8) ) Image( painter = painterResource(Res.drawable.ic_gallery_icon), contentDescription = "gallery", contentScale = ContentScale.Fit, modifier = Modifier .size(24.dp) .clickable { launchGallery = true } ) } } } } else { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Button( onClick = { startBarCodeScan = true qrCodeURL = "" }, colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF007AFF)), ) { Text( text = "Scan Qr", modifier = Modifier.background(Color.Transparent) .padding(horizontal = 12.dp, vertical = 12.dp), fontSize = 16.sp ) } Text( text = qrCodeURL, color = Color.Black, modifier = Modifier.padding(top = 12.dp) ) } } } if (startBarCodeScan) { Icon( imageVector = Icons.Filled.Close, "Close", modifier = Modifier .padding(top = 12.dp, end = 12.dp) .size(24.dp) .clickable { startBarCodeScan = false }.align(Alignment.TopEnd), tint = Color.White ) } } } 
Enter fullscreen mode Exit fullscreen mode

Tech Stack

  • Compose Multiplatform
  • CameraX Jetpack library
  • ML Kit

Conclusion

Integrating a QR code scanner library enhances functionality, streamlines processes, and improves user experience in your application.

https://github.com/ChainTechNetwork/QRKitComposeMultiplatform.git

Happy coding ❤

Connect with us 👇

Top comments (0)