AgentStack
SKILL verified MIT Self-run

Macos Permissions

skill-makgunay-claude-swift-skills-macos-permissions · by makgunay

macOS permission handling for Accessibility (AXIsProcessTrusted), Screen Recording, Full Disk Access, input monitoring, camera, microphone, location, and contacts. Covers TCC (Transparency Consent and Control) database, graceful degradation when permissions are denied, permission prompting patterns, opening System Settings to the correct pane, detecting permission changes, and the privacy manifes…

No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add skill-makgunay-claude-swift-skills-macos-permissions

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Are you the author of Macos Permissions? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

macOS Permissions

Critical Constraints

  • ❌ DO NOT assume permissions are granted → ✅ Always check before using protected APIs
  • ❌ DO NOT repeatedly prompt after denial → ✅ Guide user to System Settings instead
  • ❌ DO NOT block the entire app on missing permission → ✅ Gracefully degrade, offer reduced functionality
  • ❌ DO NOT forget PrivacyInfo.xcprivacy → ✅ Required for App Store submission

Permission Types

| Permission | Check API | Required For | |------------|-----------|-------------| | Accessibility | AXIsProcessTrusted() | Global hotkeys, text insertion, CGEvent | | Screen Recording | CGPreflightScreenCaptureAccess() | Screen capture, window list | | Full Disk Access | Try access + handle error | Reading other app data | | Camera | AVCaptureDevice.authorizationStatus(for: .video) | Camera access | | Microphone | AVCaptureDevice.authorizationStatus(for: .audio) | Audio capture | | Location | CLLocationManager().authorizationStatus | Location services | | Contacts | CNContactStore.authorizationStatus(for: .contacts) | Contact access |

Accessibility Permission

import ApplicationServices

// Check without prompting
func isAccessibilityGranted() -> Bool {
    AXIsProcessTrusted()
}

// Check and prompt user (shows system dialog)
func requestAccessibilityPermission() -> Bool {
    let options = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as String: true]
    return AXIsProcessTrustedWithOptions(options as CFDictionary)
}

// Open System Settings → Privacy → Accessibility
func openAccessibilitySettings() {
    NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility")!)
}

Screen Recording Permission

import CoreGraphics

// Check (macOS 15+)
func isScreenRecordingGranted() -> Bool {
    CGPreflightScreenCaptureAccess()
}

// Request (macOS 15+)
func requestScreenRecording() -> Bool {
    CGRequestScreenCaptureAccess()
}

// Open Settings
func openScreenRecordingSettings() {
    NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture")!)
}

Camera / Microphone

import AVFoundation

func checkCameraPermission() async -> Bool {
    switch AVCaptureDevice.authorizationStatus(for: .video) {
    case .authorized: return true
    case .notDetermined: return await AVCaptureDevice.requestAccess(for: .video)
    case .denied, .restricted: return false
    @unknown default: return false
    }
}

Graceful Degradation Pattern

struct FeatureAvailability {
    var canInsertText: Bool { AXIsProcessTrusted() }
    var canUseGlobalHotkey: Bool { AXIsProcessTrusted() }
    var canCaptureScreen: Bool { CGPreflightScreenCaptureAccess() }

    var degradedFeatures: [String] {
        var features: [String] = []
        if !canInsertText { features.append("Text insertion into other apps") }
        if !canUseGlobalHotkey { features.append("Global keyboard shortcuts") }
        return features
    }
}

struct PermissionBanner: View {
    let availability: FeatureAvailability

    var body: some View {
        if !availability.degradedFeatures.isEmpty {
            VStack(alignment: .leading, spacing: 8) {
                Label("Some features require permissions", systemImage: "lock.shield")
                    .font(.headline)
                ForEach(availability.degradedFeatures, id: \.self) { feature in
                    Text("• \(feature)")
                        .font(.caption)
                }
                Button("Open System Settings") { openAccessibilitySettings() }
                    .buttonStyle(.borderedProminent)
            }
            .padding()
            .glassEffect(.regular.tint(.orange), in: .rect(cornerRadius: 12))
        }
    }
}

Permission Onboarding Flow

struct OnboardingPermissionView: View {
    @State private var accessibilityGranted = AXIsProcessTrusted()
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    var body: some View {
        VStack(spacing: 20) {
            Image(systemName: accessibilityGranted ? "checkmark.circle.fill" : "lock.circle")
                .font(.system(size: 48))
                .foregroundStyle(accessibilityGranted ? .green : .orange)

            Text(accessibilityGranted ? "Permission Granted!" : "Accessibility Permission Required")
                .font(.title2)

            if !accessibilityGranted {
                Text("This app needs Accessibility access to insert text into other apps and register global shortcuts.")
                    .multilineTextAlignment(.center)

                Button("Open System Settings") {
                    requestAccessibilityPermission()
                }
                .buttonStyle(.borderedProminent)
            }
        }
        .onReceive(timer) { _ in
            accessibilityGranted = AXIsProcessTrusted()
        }
    }
}

Privacy Manifest (PrivacyInfo.xcprivacy)


    NSPrivacyTracking
    
    NSPrivacyTrackingDomains
    
    NSPrivacyCollectedDataTypes
    
    NSPrivacyAccessedAPITypes
    
        
            NSPrivacyAccessedAPIType
            NSPrivacyAccessedAPICategoryUserDefaults
            NSPrivacyAccessedAPITypeReasons
            CA92.1
        
    

Common Mistakes & Fixes

| Mistake | Fix | |---------|-----| | Prompting repeatedly after denial | Check status first, guide to Settings if denied | | App crashes without permission | Always check before calling protected API | | User can't find permission setting | Open specific System Settings pane via URL | | Missing privacy manifest | Add PrivacyInfo.xcprivacy to app bundle |

References

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.