Reputation: 41
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..
Upvotes: 4
Views: 1867