Created
February 24, 2026 08:24
-
-
Save hellensoloviy/d3d849eb3c6d306b1003eed2287a020d to your computer and use it in GitHub Desktop.
PermissionManager with examples SwiftUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import SwiftUI | |
| import UserNotifications | |
| import AVFoundation | |
| import Photos | |
| import CoreLocation | |
| @MainActor | |
| final class PermissionManager: NSObject, ObservableObject, CLLocationManagerDelegate { | |
| // MARK: Published states for UI toggles | |
| @Published var notificationsAuthorized = false | |
| @Published var cameraAuthorized = false | |
| @Published var photoLibraryAuthorized = false | |
| @Published var microphoneAuthorized = false | |
| @Published var locationAuthorized = false | |
| // Location manager for permission request | |
| private var locationManager: CLLocationManager? | |
| // MARK: Initialization | |
| override init() { | |
| super.init() | |
| refreshAllPermissions() | |
| } | |
| // MARK: Refresh all permissions | |
| func refreshAllPermissions() { | |
| Task { | |
| await refreshNotificationStatus() | |
| refreshCameraStatus() | |
| refreshPhotoLibraryStatus() | |
| refreshMicrophoneStatus() | |
| refreshLocationStatus() | |
| } | |
| } | |
| // MARK: Notifications | |
| func refreshNotificationStatus() async { | |
| let settings = await UNUserNotificationCenter.current().notificationSettings() | |
| notificationsAuthorized = settings.authorizationStatus == .authorized || settings.authorizationStatus == .provisional | |
| } | |
| func requestNotifications() async { | |
| let granted = try? await UNUserNotificationCenter.current() | |
| .requestAuthorization(options: [.alert, .sound, .badge]) | |
| notificationsAuthorized = granted ?? false | |
| } | |
| // MARK: Camera | |
| func refreshCameraStatus() { | |
| let status = AVCaptureDevice.authorizationStatus(for: .video) | |
| cameraAuthorized = status == .authorized | |
| } | |
| func requestCamera() { | |
| AVCaptureDevice.requestAccess(for: .video) { granted in | |
| Task { @MainActor in | |
| self.cameraAuthorized = granted | |
| } | |
| } | |
| } | |
| // MARK: Photo Library | |
| func refreshPhotoLibraryStatus() { | |
| let status = PHPhotoLibrary.authorizationStatus() | |
| photoLibraryAuthorized = status == .authorized || status == .limited | |
| } | |
| func requestPhotoLibrary() { | |
| PHPhotoLibrary.requestAuthorization { status in | |
| Task { @MainActor in | |
| self.photoLibraryAuthorized = status == .authorized || status == .limited | |
| } | |
| } | |
| } | |
| // MARK: Microphone | |
| func refreshMicrophoneStatus() { | |
| let status = AVAudioSession.sharedInstance().recordPermission | |
| microphoneAuthorized = status == .granted | |
| } | |
| func requestMicrophone() { | |
| AVAudioSession.sharedInstance().requestRecordPermission { granted in | |
| Task { @MainActor in | |
| self.microphoneAuthorized = granted | |
| } | |
| } | |
| } | |
| // MARK: Location | |
| func refreshLocationStatus() { | |
| let status = CLLocationManager.authorizationStatus() | |
| locationAuthorized = status == .authorizedWhenInUse || status == .authorizedAlways | |
| } | |
| func requestLocation() { | |
| locationManager = CLLocationManager() | |
| locationManager?.delegate = self | |
| locationManager?.requestWhenInUseAuthorization() | |
| } | |
| // CLLocationManager Delegate | |
| func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { | |
| refreshLocationStatus() | |
| } | |
| } | |
| //MARK: - Example | |
| struct SettingsScreenView: View { | |
| @StateObject var permissions = PermissionManager() | |
| var body: some View { | |
| Form { | |
| Section("Permissions") { | |
| Toggle("Notifications", isOn: $permissions.notificationsAuthorized) | |
| .onChange(of: permissions.notificationsAuthorized) { _, newValue in | |
| if newValue == false { | |
| // guide user to settings | |
| if let url = URL(string: UIApplication.openSettingsURLString) { | |
| UIApplication.shared.open(url) | |
| } | |
| } else { | |
| Task { await permissions.requestNotifications() } | |
| } | |
| } | |
| Toggle("Camera", isOn: $permissions.cameraAuthorized) | |
| .onChange(of: permissions.cameraAuthorized) { _, newValue in | |
| if newValue == false { | |
| if let url = URL(string: UIApplication.openSettingsURLString) { | |
| UIApplication.shared.open(url) | |
| } | |
| } else { | |
| permissions.requestCamera() | |
| } | |
| } | |
| Toggle("Photo Library", isOn: $permissions.photoLibraryAuthorized) | |
| .onChange(of: permissions.photoLibraryAuthorized) { _, newValue in | |
| if newValue == false { | |
| if let url = URL(string: UIApplication.openSettingsURLString) { | |
| UIApplication.shared.open(url) | |
| } | |
| } else { | |
| permissions.requestPhotoLibrary() | |
| } | |
| } | |
| Toggle("Microphone", isOn: $permissions.microphoneAuthorized) | |
| .onChange(of: permissions.microphoneAuthorized) { _, newValue in | |
| if newValue == false { | |
| if let url = URL(string: UIApplication.openSettingsURLString) { | |
| UIApplication.shared.open(url) | |
| } | |
| } else { | |
| permissions.requestMicrophone() | |
| } | |
| } | |
| Toggle("Location", isOn: $permissions.locationAuthorized) | |
| .onChange(of: permissions.locationAuthorized) { _, newValue in | |
| if newValue == false { | |
| if let url = URL(string: UIApplication.openSettingsURLString) { | |
| UIApplication.shared.open(url) | |
| } | |
| } else { | |
| permissions.requestLocation() | |
| } | |
| } | |
| } | |
| } | |
| .onAppear { | |
| permissions.refreshAllPermissions() | |
| } | |
| .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in | |
| permissions.refreshAllPermissions() | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment