Camera & Permissions
Handle camera permissions correctly in your iOS app when using the Circadify SDK.
The Circadify SDK requires camera access — the front (selfie) camera by default, or the rear camera when you create it with CircadifyCamera(position: .back). The permission flow is identical either way. iOS enforces strict permission controls — your app must handle the permission flow before starting a measurement.
Info.plist
Add the camera usage description to your Info.plist. Without this, iOS will terminate your app on camera access.
<key>NSCameraUsageDescription</key>
<string>This app uses the camera to measure your vital signs contactlessly.</string>xmlWrite a clear, specific description. Vague descriptions like "Camera access needed" may cause App Store review rejection.
Permission Flow
Permissions are handled through CircadifyCamera — the object that owns the shared capture session for both the live preview and the measurement.
-
Check the current status with
camera.authorizationStatus(an observableAVAuthorizationStatus). -
Request access with
await camera.requestAccess(). This shows the system dialog when the status is.notDeterminedand returns whether access was granted. -
Start the camera with
try await camera.start(). If the status is.notDetermined,start()requests access automatically — you don't have to callrequestAccess()first. If access is denied,start()throwsCircadifyError.cameraPermissionDenied. -
Handle denial — catch
.cameraPermissionDeniedand guide the user to Settings. iOS won't show the dialog again.
In the simplest case you don't manage permissions yourself at all — just call camera.start() in a .task and let it prompt:
import SwiftUI
import CircadifySDK
struct ScanView: View {
@State private var camera = CircadifyCamera()
var body: some View {
CircadifyCameraPreview(camera: camera)
.ignoresSafeArea()
.task {
try? await camera.start() // requests permission if needed, then goes live
}
.onDisappear { camera.stop() }
}
}swiftWhen you want to react to denial — for example to deep-link the user into Settings — observe camera.authorizationStatus and surface an alert.
Drive the camera from a SwiftUI view. The preview renders the shared session, .task starts the camera (prompting for permission), and a denied status triggers a Settings deep-link alert. Returning from Settings re-checks via scenePhase.
import SwiftUI
import CircadifySDK
struct ScanView: View {
@State private var camera = CircadifyCamera()
@State private var showSettingsAlert = false
@Environment(\.scenePhase) private var scenePhase
var body: some View {
ZStack {
CircadifyCameraPreview(camera: camera)
.ignoresSafeArea()
if !camera.isRunning {
Text("Camera access is required to scan.")
.foregroundStyle(.white)
}
}
.alert("Camera Access Required", isPresented: $showSettingsAlert) {
Button("Open Settings") {
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
}
Button("Cancel", role: .cancel) { }
} message: {
Text("Go to Settings > Privacy > Camera and enable access for this app.")
}
.task { await start() }
.onChange(of: scenePhase) { _, phase in
// Returning from Settings — retry if the user just enabled access.
if phase == .active, !camera.isRunning {
Task { await start() }
}
}
.onDisappear { camera.stop() }
}
func start() async {
do {
try await camera.start() // prompts if .notDetermined, then goes live
} catch CircadifyError.cameraPermissionDenied {
showSettingsAlert = true
} catch {
print("Camera failed to start: \(error)")
}
}
}swiftCircadifySDK also exposes sdk.checkCameraPermission() and await sdk.requestCameraPermission() as standalone convenience methods that query/request AVCaptureDevice directly. Unlike camera.requestAccess(), they do not refresh a CircadifyCamera's observable authorizationStatus — so prefer camera.authorizationStatus and camera.requestAccess() when you have a CircadifyCamera on hand.
Best Practices
- Let
start()do the work.camera.start()requests permission automatically when the status is.notDetermined, so you rarely need to callrequestAccess()yourself. CatchCircadifyError.cameraPermissionDeniedto handle the denied case. - Request early. Trigger the prompt during onboarding or as soon as the scan screen appears, not at the last moment before measuring.
- Handle denial gracefully. Provide a clear path to Settings with a direct deep link (
UIApplication.openSettingsURLString). - Re-check on foreground. After the user returns from Settings, re-check on
scenePhase == .active(SwiftUI) ordidBecomeActiveNotification(UIKit) and retrycamera.start(). - Stop when off-screen. Call
camera.stop()inonDisappear/viewDidDisappearto release the capture session.
iOS only shows the system permission dialog once per app install. If the user dismisses or denies it, the only way to re-enable camera access is through Settings.
Next Steps
- Methods — Start a measurement
- Error Handling — Handle permission-related errors
- Configuration — SDK setup options