https://kotlinlang.org logo
s

Sreeramktm 27

07/28/2023, 7:32 AM
Hello all, working on a project to scan QR using compose multiplatform in iOS. The scanner works fine, but for some reason I am not receiving any callbacks from captureOutput even though i point the scanner right at the QR. Like the callbacks are received and suddenly it stops. Any idea why this issue is happening? Thread in Slack Conversation
👀 1
👍 1
Code:
Copy code
@Composable
private fun RealDeviceCamera(
    camera: AVCaptureDevice,
    onQrCodeScanned: (String) -> Boolean
) {
    val capturePhotoOutput = remember { AVCapturePhotoOutput() }
    var actualOrientation by remember {
        mutableStateOf(
            AVCaptureVideoOrientationPortrait
        )
    }

    val captureSession: AVCaptureSession = remember {
        AVCaptureSession().also { captureSession ->
            captureSession.sessionPreset = AVCaptureSessionPresetPhoto
            val captureDeviceInput: AVCaptureDeviceInput =
                deviceInputWithDevice(device = camera, error = null)!!
            captureSession.addInput(captureDeviceInput)
            captureSession.addOutput(capturePhotoOutput)

            //Initialize an AVCaptureMetadataOutput object and set it as the output device to the capture session.
            val metadataOutput = AVCaptureMetadataOutput()
            if (captureSession.canAddOutput(metadataOutput)) {
                captureSession.addOutput(metadataOutput)
                metadataOutput.setMetadataObjectsDelegate(objectsDelegate = object : NSObject(),
                    AVCaptureMetadataOutputObjectsDelegateProtocol {
                    override fun captureOutput(
                        output: AVCaptureOutput,
                        didOutputMetadataObjects: List<*>,
                        fromConnection: AVCaptureConnection
                    ) {
                        didOutputMetadataObjects.firstOrNull()?.let { metadataObject ->
                            val readableObject =
                                metadataObject as? AVMetadataMachineReadableCodeObject
                            if (readableObject?.type == AVMetadataObjectTypeQRCode) {
                                val code = readableObject?.stringValue ?: ""
                                if (onQrCodeScanned.invoke(code)) {
                                    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
                                    captureSession.stopRunning()
                                }
                            }
                        }
                    }
                }, queue = dispatch_get_main_queue())

                metadataOutput.metadataObjectTypes = listOf(AVMetadataObjectTypeQRCode)
                /*
                Commenting this line as this provides support for many ISO Image formats.
                Later if needed to extend QR scanner to support other formats comment this line and uncomment the above line.
                 */
//                metadataOutput.metadataObjectTypes = metadataOutput.availableMetadataObjectTypes()
            }
        }
    }
    val cameraPreviewLayer = remember {
        AVCaptureVideoPreviewLayer(session = captureSession)
    }

    DisposableEffect(Unit) {
        class OrientationListener : NSObject() {
            @Suppress("UNUSED_PARAMETER")
            @ObjCAction
            fun orientationDidChange(arg: NSNotification) {
                val cameraConnection = cameraPreviewLayer.connection
                if (cameraConnection != null) {
                    actualOrientation = when (UIDevice.currentDevice.orientation) {
                        UIDeviceOrientation.UIDeviceOrientationPortrait ->
                            AVCaptureVideoOrientationPortrait

                        UIDeviceOrientation.UIDeviceOrientationLandscapeLeft ->
                            AVCaptureVideoOrientationLandscapeRight

                        UIDeviceOrientation.UIDeviceOrientationLandscapeRight ->
                            AVCaptureVideoOrientationLandscapeLeft

                        UIDeviceOrientation.UIDeviceOrientationPortraitUpsideDown ->
                            AVCaptureVideoOrientationPortrait

                        else -> cameraConnection.videoOrientation
                    }
                    cameraConnection.videoOrientation = actualOrientation
                }
                capturePhotoOutput.connectionWithMediaType(AVMediaTypeVideo)
                    ?.videoOrientation = actualOrientation
            }
        }

        val listener = OrientationListener()
        val notificationName = UIDeviceOrientationDidChangeNotification
        NSNotificationCenter.defaultCenter.addObserver(
            observer = listener,
            selector = NSSelectorFromString(
                OrientationListener::orientationDidChange.name + ":"
            ),
            name = notificationName,
            `object` = null
        )
        onDispose {
            NSNotificationCenter.defaultCenter.removeObserver(
                observer = listener,
                name = notificationName,
                `object` = null
            )
        }
    }

    Box(modifier = Modifier.fillMaxSize()) {
        UIKitView(
            modifier = Modifier.fillMaxSize(),
            factory = {
                val cameraContainer = UIView()
                cameraContainer.layer.addSublayer(cameraPreviewLayer)
                cameraPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
                captureSession.startRunning()
                cameraContainer
            },
            onResize = { view: UIView, rect: CValue<CGRect> ->
                CATransaction.begin()
                CATransaction.setValue(true, kCATransactionDisableActions)
                view.layer.setFrame(rect)
                cameraPreviewLayer.setFrame(rect)
                CATransaction.commit()
            },
        )
    }
}
3 Views