A camera in mobile applications is a hardware module of the device accessible to the developer through system APIs for capturing images and video. According to Google Android Developers (2025), CameraX is used in over 85% of Android applications that require camera functionality. AVFoundation on iOS and CameraX on Android provide high-level interfaces that hide the complexity of hardware management.
Key Takeaways
A mobile camera is an integrated optical module consisting of a lens, an image sensor, and an image signal processor (ISP). The developer accesses the camera through the operating system using specialized frameworks. On Android, these are Camera2 API (low-level) and CameraX (high-level, built on Camera2), and on iOS — AVFoundation and UIKit for simple scenarios. Each platform provides its own set of tools, but the general concept is the same: the application initializes a capture session, configures parameters (resolution, focus, exposure), and receives a frame stream or individual images.
Modern mobile cameras support many shooting modes: HDR, night mode, portrait with background blur, slow-motion video, and RAW format recording. The developer has access to software settings: ISO (sensor sensitivity), shutter speed (exposure), white balance, focus (automatic and manual), and image stabilization. Flagship devices can have up to 4 cameras with different focal lengths, and the application can select a specific camera by ID.
Mobile platforms offer several APIs for working with the camera, varying in abstraction level and functionality. The choice of a specific API depends on the project requirements: for simple photo capture, CameraX or UIImagePickerController is sufficient; for professional applications, Camera2 or AVFoundation with direct sensor control is needed. Below is a comparison of the main APIs.
| API | Platform | Level | Features |
|---|---|---|---|
| CameraX | Android | High | Lifecycle-aware, 95% of devices |
| Camera2 | Android | Low | Full control, RAW, Burst |
| AVFoundation | iOS | Medium | Full capture control |
| UIKit (UIImagePickerController) | iOS | High | Ready UI, no customization |
CameraX is the optimal choice for most Android applications that need a camera without deep customization. The library automatically handles the Activity and Fragment lifecycle, supports permissions, and ensures compatibility across different Android versions. CameraX guarantees consistent behavior on 95% of Android devices thanks to its compatibility layer. If you need camera preview (Preview), photo capture (ImageCapture), or frame analysis (ImageAnalysis) — CameraX handles all three scenarios without writing complex code.
Camera2 is a low-level API for professional scenarios: RAW recording, manual exposure adjustment, burst capture, and simultaneous control of multiple cameras. Camera2 requires the developer to have a deep understanding of the image capture pipeline, StateMachine management, and callback handling. Use Camera2 only if CameraX does not cover the requirements: for example, document scanning applications with manual focus or custom cameras with non-standard resolution.
Access to the camera requires explicit user permission on both platforms. On Android, the CAMERA permission is added to the manifest, and starting from Android 6.0, the permission must also be requested at runtime via ActivityCompat.requestPermissions. On iOS, the NSCameraUsageDescription key is added to Info.plist with a description of why the camera is used. Without this description, the application will crash when trying to access the camera. Starting from iOS 14, the permission dialog displays not only the application name but also the specified reason — the wording must be clear to the user.
CameraX simplifies working with the camera to just a few lines of code. To launch a preview, you need to create a Preview instance, bind it to a LifecycleOwner, and obtain a SurfaceProvider for display. For photo capture, ImageCapture with a save target is used. Below is a complete example of launching the camera and taking a photo using CameraX in Kotlin.
val preview = Preview.Builder()
.build()
.also {
it.surfaceProvider = viewFinder.surfaceProvider
}
val imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture
)
} catch (e: Exception) {
Log.e("CameraX", "Bind failed", e)
}
}, ContextCompact.getMainExecutor(this))
The bindToLifecycle method binds the camera to the Activity's lifecycle — when the screen rotates or the app goes into the background, the camera is automatically released. CameraSelector.DEFAULT_BACK_CAMERA selects the rear camera; for the front camera, DEFAULT_FRONT_CAMERA is used. After binding, Preview starts displaying the camera feed in PreviewView, and the user sees the camera image on the screen.
val photoFile = File(
externalMediaDirs.firstOrNull(),
"IMG_${System.currentTimeMillis()}.jpg"
)
val outputOptions = ImageCapture.OutputFileOptions
.Builder(photoFile)
.build()
imageCapture.takePicture(
outputOptions,
ContextCompact.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
Log.d("CameraX", "Photo saved: ${photoFile.absolutePath}")
}
override fun onError(exception: ImageCaptureException) {
Log.e("CameraX", "Capture error", exception)
}
}
)
The takePicture method captures a frame from the camera and saves it to a file. OutputFileOptions supports writing to File, ContentResolver, and MediaStore. In the onImageSaved callback, the application receives a notification of successful saving and can update the UI. CAPTURE_MODE_MINIMIZE_LATENCY ensures maximum shutter speed by reducing post-processing.
On iOS, access to the camera is provided by the AVFoundation framework through the AVCaptureSession class. The developer creates a capture session, adds the necessary inputs (AVCaptureDeviceInput) and outputs (AVCapturePhotoOutput, AVCaptureVideoDataOutput), and starts the session. AVCaptureVideoPreviewLayer is used for displaying the preview. Below is an example of setting up a session for photo capture on Swift.
import AVFoundation
let captureSession = AVCaptureSession()
captureSession.sessionPreset = .photo
guard let camera = AVCaptureDevice.default(
for: .video
) else { return }
guard let input = try? AVCaptureDeviceInput(device: camera)
else { return }
let output = AVCapturePhotoOutput()
captureSession.addInput(input)
captureSession.addOutput(output)
DispatchQueue.global(qos: .userInitiated).async {
captureSession.startRunning()
}
AVCaptureSessionPreset.photo sets the optimal resolution for photos (usually 12 MP on modern devices). The input is an AVCaptureDeviceInput created for the device's camera. After adding the input and output, the session is started on a background thread via startRunning — starting the session can take up to 200 ms on older devices. To capture a photo, capturePhoto(with:delegate:) is called, and the result is returned through the AVCapturePhotoCaptureDelegate.
When working with the camera on mobile devices, hardware limitations must be considered: device heating during prolonged recording, battery drain when working with high resolution, and varying camera quality across different devices. On Android, ecosystem fragmentation means the same CameraX configuration may behave differently on different models. On iOS, limitations mainly concern licensing: using the camera in the background requires special permission from Apple. It is also important to remember that simulators do not have access to a real camera — testing is only possible on a physical device.
CameraX solves the Android fragmentation problem through the CameraXConfig compatibility layer — the library automatically applies workarounds for known manufacturer bugs. On iOS, AVFoundation works uniformly across all devices starting from iOS 6, but some features (e.g., Portrait Mode or LiDAR) are only available on iPhone 12 and newer models. When developing a cross-platform application, it is recommended to use Flutter or React Native with camera plugins — they abstract platform differences and provide a unified API for both operating systems.
Frequently Asked Questions
For most applications, CameraX is recommended due to its ease of use, built-in lifecycle handling, and compatibility with 95% of devices. Camera2 should only be chosen when RAW, burst capture, or manual sensor control is needed.
On Android, add the CAMERA permission to the manifest and request it at runtime via ActivityCompat.requestPermissions. On iOS, add NSCameraUsageDescription to Info.plist with a clear explanation of why the camera is used.
On iOS, background camera usage is strictly limited — a special Apple permission is required. On Android, the camera can work in the background through a foreground service, but this negatively affects battery life and device heating.
iOS simulators and Android emulators do not have access to a hardware camera — they do not emulate a physical sensor. To test camera functionality, always use a physical device or an external camera connected to the computer.
ImageAnalysis is a frame stream analyzer from CameraX that passes each frame to ImageAnalysis.Analyzer for processing. It is used for QR code recognition, face detection, document scanning, and other computer vision tasks.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also