Skip to content

Instantly share code, notes, and snippets.

@arulwastaken
Created July 18, 2025 10:26
Show Gist options
  • Save arulwastaken/168aa1941062648b86b212583a05d550 to your computer and use it in GitHub Desktop.
Save arulwastaken/168aa1941062648b86b212583a05d550 to your computer and use it in GitHub Desktop.
/iosMain/Camera.ios.kt
@OptIn(ExperimentalForeignApi::class)
@Composable
actual fun CameraView(callback: CameraCallback) {
val session = AVCaptureSession()
session.sessionPreset = AVCaptureSessionPresetPhoto
val output = AVCaptureStillImageOutput().apply {
outputSettings = mapOf(AVVideoCodecKey to platform.AVFoundation.AVVideoCodecJPEG)
}
session.addOutput(output)
val cameraPreviewLayer = AVCaptureVideoPreviewLayer(session = session)
LaunchedEffect(Unit) {
val backCamera =
AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo).firstOrNull { device ->
(device as AVCaptureDevice).position == AVCaptureDevicePositionBack
} as? AVCaptureDevice ?: return@LaunchedEffect
val frontCamera =
AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo).firstOrNull { device ->
(device as AVCaptureDevice).position == AVCaptureDevicePositionFront
} as? AVCaptureDevice ?: return@LaunchedEffect
var currentCamera = backCamera
var currentInput =
AVCaptureDeviceInput.deviceInputWithDevice(currentCamera, null) as AVCaptureDeviceInput
session.addInput(currentInput)
session.addOutput(output)
session.startRunning()
callback.eventFlow.collect {
when (it) {
CameraEvent.CaptureImage -> {
val connection = output.connectionWithMediaType(AVMediaTypeVideo)
if (connection != null) {
output.captureStillImageAsynchronouslyFromConnection(connection) { sampleBuffer, error ->
if (sampleBuffer != null && error == null) {
val imageData =
AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(
sampleBuffer
)
if (imageData != null) {
val filePath =
platform.Foundation.NSTemporaryDirectory() + UIDevice.currentDevice.identifierForVendor?.UUIDString + ".jpg"
imageData.writeToFile(filePath, true)
callback.onCaptureImage(Path(filePath))
}
}
}
}
}
CameraEvent.SwitchCamera -> {
session.stopRunning()
session.removeInput(currentInput)
currentCamera = if (currentCamera == backCamera) frontCamera else backCamera
currentInput = AVCaptureDeviceInput.deviceInputWithDevice(
currentCamera,
null
) as AVCaptureDeviceInput
session.addInput(currentInput)
session.startRunning()
}
}
}
}
UIKitView(
modifier = Modifier.fillMaxSize(),
background = Color.Black,
factory = {
val container = UIView()
container.layer.addSublayer(cameraPreviewLayer)
cameraPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
container
},
onResize = { container: UIView, rect: CValue<CGRect> ->
CATransaction.begin()
CATransaction.setValue(true, kCATransactionDisableActions)
container.layer.setFrame(rect)
cameraPreviewLayer.setFrame(rect)
CATransaction.commit()
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment