iOS development
camera permissions
iOS permissions
Swift programming
mobile app development

Detect permission of camera in iOS

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Checking camera permission on iOS is not just a UI concern. It is part of the app's runtime contract with the operating system. The correct implementation includes an Info.plist usage description, a permission-status check through AVCaptureDevice, and UI behavior for the authorized, denied, restricted, and not-determined states.

Add the Privacy Usage Description First

Before you request access, the app must declare why it needs the camera.

Add this key to Info.plist:

xml
<key>NSCameraUsageDescription</key>
<string>This app uses the camera to scan receipts.</string>

Without this key, the app will crash when trying to request camera access.

Read the Current Authorization Status

Use AVCaptureDevice.authorizationStatus(for: .video) to inspect the current state.

swift
1import AVFoundation
2
3let status = AVCaptureDevice.authorizationStatus(for: .video)
4print(status.rawValue)

The possible states are:

  • '.authorized'
  • '.denied'
  • '.restricted'
  • '.notDetermined'

Your app should treat each one differently.

Request Access When Status Is .notDetermined

Only request access when the user has not been prompted yet.

swift
1import AVFoundation
2
3func requestCameraAccess(completion: @escaping (Bool) -> Void) {
4    AVCaptureDevice.requestAccess(for: .video) { granted in
5        DispatchQueue.main.async {
6            completion(granted)
7        }
8    }
9}

This system prompt appears at most once for the user unless they change permission in Settings later.

A Complete Permission Helper

This helper centralizes the logic and gives your UI one clear entry point.

swift
1import AVFoundation
2
3enum CameraPermissionState {
4    case authorized
5    case denied
6    case restricted
7    case notDetermined
8}
9
10func cameraPermissionState() -> CameraPermissionState {
11    switch AVCaptureDevice.authorizationStatus(for: .video) {
12    case .authorized:
13        return .authorized
14    case .denied:
15        return .denied
16    case .restricted:
17        return .restricted
18    case .notDetermined:
19        return .notDetermined
20    @unknown default:
21        return .restricted
22    }
23}

Then use it before presenting camera UI.

Example View Controller Flow

This example checks status, requests if needed, and handles the main branches cleanly.

swift
1import UIKit
2import AVFoundation
3
4final class CameraGateViewController: UIViewController {
5    @IBAction func openCameraTapped(_ sender: UIButton) {
6        switch cameraPermissionState() {
7        case .authorized:
8            presentCameraUI()
9
10        case .notDetermined:
11            requestCameraAccess { granted in
12                if granted {
13                    self.presentCameraUI()
14                } else {
15                    self.showDeniedAlert()
16                }
17            }
18
19        case .denied, .restricted:
20            showDeniedAlert()
21        }
22    }
23
24    private func presentCameraUI() {
25        print("Present camera here")
26    }
27
28    private func showDeniedAlert() {
29        let alert = UIAlertController(
30            title: "Camera Access Needed",
31            message: "Enable camera access in Settings to scan receipts.",
32            preferredStyle: .alert
33        )
34
35        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
36        alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in
37            if let url = URL(string: UIApplication.openSettingsURLString) {
38                UIApplication.shared.open(url)
39            }
40        })
41
42        present(alert, animated: true)
43    }
44}

This keeps the permission flow explicit and avoids trying to present the camera when access is not available.

Understand denied Versus restricted

These states are easy to confuse:

  • '.denied means the user explicitly said no.'
  • '.restricted usually means system policy, parental controls, or device management prevents access.'

For .restricted, sending the user to Settings may not solve the issue, so your UI should explain that access is unavailable rather than implying it is always user-fixable.

Build a Fallback User Experience

Permission denial should not crash the feature flow. A good camera feature provides:

  • an explanatory screen or alert
  • a Settings shortcut when appropriate
  • a non-camera fallback if the product allows it

For example, a document-scanning app might offer manual file upload when the camera is unavailable.

Common Pitfalls

The biggest mistake is trying to request or use the camera without NSCameraUsageDescription in Info.plist. Another is treating .denied and .restricted as the same user-fixable state. Teams also sometimes request permission too early, before the user understands why the app needs the camera, which lowers grant rates. Finally, permission checks are often scattered across several controllers instead of being centralized in one helper or service.

Summary

  • Add NSCameraUsageDescription before requesting camera access.
  • Use AVCaptureDevice.authorizationStatus(for: .video) to detect the current state.
  • Call requestAccess only when the status is .notDetermined.
  • Handle .authorized, .denied, and .restricted explicitly in the UI flow.
  • Provide a Settings path or fallback behavior instead of failing silently.

Course illustration
Course illustration

All Rights Reserved.