I have integrated the Camera Scanner from AVFoundation into a Compose Multiplatform project. The scanner scans a few times (randomly 5-6 times) before ceasing to scan further, although the live preview remains active. How can I address this issue? I’ll provide the CameraScanner code.
@OptIn(ExperimentalForeignApi::class)
@Composable
actual fun QRCameraView(
modifier: Modifier,
onScanResult: (String) -> Unit
) {
val captureSession = AVCaptureSession()
val captureDevice = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo).firstOrNull { device ->
(device as AVCaptureDevice).position == AVCaptureDevicePositionBack
}!! as AVCaptureDevice
val input = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, null) as AVCaptureDeviceInput
captureSession.addInput(input)
//Initialize an AVCaptureMetadataOutput object and set it as the output device to the capture session.
val metadataOutput = AVCaptureMetadataOutput()
if (captureSession.canAddOutput(metadataOutput)) {
//Set delegate and use default dispatch queue to execute the call back
// fixed with https://youtrack.jetbrains.com/issue/KT-45755/iOS-delegate-protocol-is-empty
captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(objectsDelegate = object : NSObject(),
AVCaptureMetadataOutputObjectsDelegateProtocol {
override fun captureOutput(
output: AVCaptureOutput,
didOutputMetadataObjects: List<*>,
fromConnection: AVCaptureConnection
) {
if (didOutputMetadataObjects.isNotEmpty()) {
val readableObject =
didOutputMetadataObjects[0] as? AVMetadataMachineReadableCodeObject
if (readableObject?.type == AVMetadataObjectTypeQRCode) {
val code = readableObject?.stringValue
onScanResult(code?:"")
}
return
}
}
}, queue = dispatch_get_main_queue())
metadataOutput.metadataObjectTypes = listOf(AVMetadataObjectTypeQRCode)
}
val cameraPreviewLayer = remember { AVCaptureVideoPreviewLayer(session =
captureSession) }
UIKitView(
modifier = modifier,
background = Color.Black,
factory = {
val container = UIView()
container.layer.addSublayer(cameraPreviewLayer)
cameraPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
CoroutineScope(Dispatchers.IO).launch {
captureSession.startRunning()
}
container
},
onResize = { container: UIView, rect: CValue<CGRect> ->
CATransaction.begin()
CATransaction.setValue(true, kCATransactionDisableActions)
container.layer.setFrame(rect)
cameraPreviewLayer.setFrame(rect)
CATransaction.commit()
})
}