4

I'm working on a Kotlin Multiplatform Mobile (KMM) application and am trying to implement unified camera functionality that allows users to take photos and save them to the device's filesystem, both on Android and iOS. While I've successfully completed the Android implementation, I'm encountering difficulties finding and implementing an equivalent approach for iOS. For the iOS implementation, I'm attempting to use UIImagePickerController to capture photos and subsequently save the captured image to the device's filesystem. My main goal is to integrate this functionality as seamlessly as possible into the shared KMM code to ensure reusability and consistency across both platforms.

I've made an attempt by creating a CameraManager class in iosMain utilizing UIImagePickerController, but I'm facing issues on how to correctly save the captured image and pass the result back to the shared code.

The CameraManager looks like this:

actual class CameraManager {
    private var onImagePicked: (ByteArray) -> Unit = {}
    @Composable
    actual fun registerCameraManager(onImagePicked: (ByteArray) -> Unit) {
        this.onImagePicked = onImagePicked
    }
    @OptIn(ExperimentalForeignApi::class)
    actual fun takeImage() {
        val picker = UIImagePickerController().apply {
            sourceType =  UIImagePickerControllerSourceType.UIImagePickerControllerSourceTypeCamera
            cameraCaptureMode = UIImagePickerControllerCameraCaptureMode.UIImagePickerControllerCameraCaptureModePhoto
            delegate = object : NSObject(), UIImagePickerControllerDelegateProtocol,
                UINavigationControllerDelegateProtocol {
                override fun imagePickerController(
                    picker: UIImagePickerController,
                    didFinishPickingMediaWithInfo: Map<Any?, *>
                ) {
                    val originalImage = didFinishPickingMediaWithInfo.getValue(
                        UIImagePickerControllerOriginalImage
                    ) as? UIImage

                    originalImage?.let { image ->
                        // Convert image to JPEG data
                        val data = UIImageJPEGRepresentation(image, 1.0)

                        // Save to documents directory
                        val path = NSSearchPathForDirectoriesInDomains(
                            NSDocumentDirectory,
                            NSUserDomainMask,
                            true
                        ).first().toString()
                        val filePath = "$path/" + NSUUID.UUID().UUIDString + ".jpg"
                        data?.writeToFile(filePath, atomically = true)

                        // Convert to bytes
                        val bytes = ByteArray(data!!.length.toInt())
                        //data?.copyBytes(to: bytes)
                        memcpy(bytes.refTo(0), data!!.bytes, data!!.length)

                        // Return image bytes
                        onImagePicked(bytes)
                    }
                    picker.dismissViewControllerAnimated(true, null)
                }
            }
        }
        UIApplication.sharedApplication.keyWindow?.rootViewController?.presentViewController(
            picker, true, null
        )
    }
}

An object of this class is only created shortly before usage in my UI-Component. There it is created with

cameraManager.registerCameraManager { imageBytes ->
    onEvent(NoteListEvent.OnPhotoPicked(imageBytes))
} 

which is a little helper function

actual fun createCameraManager(): CameraManager {
    return remember{
        CameraManagerOld(rootController)
    }
}

Can anyone assist me in implementing such a mechanism or share best practices for handling camera operations and image saving in a KMM application? Handling and implementing the Photo-Library on iOS was way easier then this..

5
  • I wish I could help as I too am writing a KMP app which will use the camera and will also need an image picker, but I'm a few weeks away from getting to that stage yet as I've only just got the mapping sorted out (got side-tracked for a week trying to get GoogleMaps to function in iOS - it works but you can't get marker taps). So I'll be keeping an eye on this and hope you get help - or if not in the meantime, I'll be looking at it myself and perhaps we can work it out. Commented Mar 10, 2024 at 21:49
  • Does this answer your question? Why does iOS delegate not work properly in KMM? Commented Mar 14, 2024 at 7:35
  • not exactly, the answer only points out what i already know. But thank you anyway because location saving is another topic on my list. Commented Mar 16, 2024 at 12:31
  • Does the delegate didFinishPickingMediaWithInfo ever gets called? I've implemented the same way but after taking the picture I never get the UIImage Commented Apr 7, 2024 at 18:24
  • I'd love to know how you handled the file once you've received it, was there any gotchas, mind sharing the code? Commented Jan 29 at 3:06

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.