permiso-accessibility-permissions

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Permiso — macOS Permission Dialog Helper

Permiso — macOS权限对话框助手

Skill by ara.so — Daily 2026 Skills collection.
Permiso provides a polished permission dialog UI for macOS apps that guides users through enabling accessibility and privacy settings — replicating the guided flow seen in OpenAI's Codex Computer Use product.
ara.so开发的Skill — 属于Daily 2026 Skills合集。
Permiso为macOS应用提供了一套精致的权限对话框UI,引导用户启用辅助功能和隐私设置——复刻了OpenAI Codex Computer Use产品中的引导流程。

What It Does

功能介绍

  • Presents an animated, guided overlay panel directing users to open System Settings and enable specific permissions (e.g. Accessibility)
  • Mirrors the UX pattern from Codex Computer Use: an on-screen assistant that walks users through enabling access
  • Handles the common friction point of macOS permission flows with a clear, app-integrated UI
  • 展示带有动画效果的引导式覆盖面板,指引用户打开系统设置并启用特定权限(如辅助功能)
  • 复刻Codex Computer Use的UX模式:通过屏幕助手引导用户完成权限启用流程
  • 借助清晰的应用集成式UI,解决macOS权限流程中的常见痛点

Installation

安装方法

Swift Package Manager

Swift Package Manager

Add to your
Package.swift
:
swift
dependencies: [
    .package(url: "https://github.com/zats/permiso", branch: "main")
]
Or in Xcode: File → Add Package Dependencies → enter
https://github.com/zats/permiso
Then add
Permiso
to your target's dependencies:
swift
.target(
    name: "YourApp",
    dependencies: ["Permiso"]
)
添加到你的
Package.swift
中:
swift
dependencies: [
    .package(url: "https://github.com/zats/permiso", branch: "main")
]
或者在Xcode中操作:File → Add Package Dependencies → 输入
https://github.com/zats/permiso
然后将
Permiso
添加到你的目标依赖中:
swift
.target(
    name: "YourApp",
    dependencies: ["Permiso"]
)

Core API

核心API

Basic Usage

基础用法

swift
import Permiso

@MainActor
func showAccessibilityHelper() {
    PermisoAssistant.shared.present(panel: .accessibility)
}
swift
import Permiso

@MainActor
func showAccessibilityHelper() {
    PermisoAssistant.shared.present(panel: .accessibility)
}

Triggering on App Launch

应用启动时触发

swift
import SwiftUI
import Permiso

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear {
                    checkAndRequestAccessibility()
                }
        }
    }

    @MainActor
    func checkAndRequestAccessibility() {
        let trusted = AXIsProcessTrusted()
        if !trusted {
            PermisoAssistant.shared.present(panel: .accessibility)
        }
    }
}
swift
import SwiftUI
import Permiso

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear {
                    checkAndRequestAccessibility()
                }
        }
    }

    @MainActor
    func checkAndRequestAccessibility() {
        let trusted = AXIsProcessTrusted()
        if !trusted {
            PermisoAssistant.shared.present(panel: .accessibility)
        }
    }
}

AppDelegate Pattern

AppDelegate模式

swift
import AppKit
import Permiso

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(_ notification: Notification) {
        requestAccessibilityIfNeeded()
    }

    @MainActor
    func requestAccessibilityIfNeeded() {
        guard !AXIsProcessTrusted() else { return }
        PermisoAssistant.shared.present(panel: .accessibility)
    }
}
swift
import AppKit
import Permiso

class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(_ notification: Notification) {
        requestAccessibilityIfNeeded()
    }

    @MainActor
    func requestAccessibilityIfNeeded() {
        guard !AXIsProcessTrusted() else { return }
        PermisoAssistant.shared.present(panel: .accessibility)
    }
}

Common Patterns

常见使用模式

Check Permission Before Sensitive Actions

敏感操作前检查权限

swift
import Permiso
import ApplicationServices

@MainActor
func performAccessibilityAction() {
    guard AXIsProcessTrusted() else {
        PermisoAssistant.shared.present(panel: .accessibility)
        return
    }
    // Proceed with accessibility-dependent work
    doAccessibilityWork()
}
swift
import Permiso
import ApplicationServices

@MainActor
func performAccessibilityAction() {
    guard AXIsProcessTrusted() else {
        PermisoAssistant.shared.present(panel: .accessibility)
        return
    }
    // 继续执行依赖辅助功能的操作
    doAccessibilityWork()
}

Polling for Permission Grant

轮询权限授予状态

swift
import Permiso
import ApplicationServices
import Combine

class PermissionMonitor: ObservableObject {
    @Published var isAccessibilityGranted = false
    private var timer: AnyCancellable?

    @MainActor
    func startMonitoring() {
        if AXIsProcessTrusted() {
            isAccessibilityGranted = true
            return
        }

        PermisoAssistant.shared.present(panel: .accessibility)

        timer = Timer.publish(every: 1.0, on: .main, in: .common)
            .autoconnect()
            .sink { [weak self] _ in
                if AXIsProcessTrusted() {
                    self?.isAccessibilityGranted = true
                    self?.timer?.cancel()
                }
            }
    }
}
swift
import Permiso
import ApplicationServices
import Combine

class PermissionMonitor: ObservableObject {
    @Published var isAccessibilityGranted = false
    private var timer: AnyCancellable?

    @MainActor
    func startMonitoring() {
        if AXIsProcessTrusted() {
            isAccessibilityGranted = true
            return
        }

        PermisoAssistant.shared.present(panel: .accessibility)

        timer = Timer.publish(every: 1.0, on: .main, in: .common)
            .autoconnect()
            .sink { [weak self] _ in
                if AXIsProcessTrusted() {
                    self?.isAccessibilityGranted = true
                    self?.timer?.cancel()
                }
            }
    }
}

SwiftUI View Integration

SwiftUI视图集成

swift
import SwiftUI
import Permiso

struct SettingsView: View {
    @State private var accessibilityGranted = AXIsProcessTrusted()

    var body: some View {
        VStack(spacing: 16) {
            HStack {
                Image(systemName: accessibilityGranted ? "checkmark.circle.fill" : "xmark.circle.fill")
                    .foregroundColor(accessibilityGranted ? .green : .red)
                Text("Accessibility Access")
            }

            if !accessibilityGranted {
                Button("Enable Accessibility Access") {
                    requestAccess()
                }
                .buttonStyle(.borderedProminent)
            }
        }
        .padding()
        .onReceive(Timer.publish(every: 2, on: .main, in: .common).autoconnect()) { _ in
            accessibilityGranted = AXIsProcessTrusted()
        }
    }

    @MainActor
    func requestAccess() {
        PermisoAssistant.shared.present(panel: .accessibility)
    }
}
swift
import SwiftUI
import Permiso

struct SettingsView: View {
    @State private var accessibilityGranted = AXIsProcessTrusted()

    var body: some View {
        VStack(spacing: 16) {
            HStack {
                Image(systemName: accessibilityGranted ? "checkmark.circle.fill" : "xmark.circle.fill")
                    .foregroundColor(accessibilityGranted ? .green : .red)
                Text("辅助功能权限")
            }

            if !accessibilityGranted {
                Button("启用辅助功能权限") {
                    requestAccess()
                }
                .buttonStyle(.borderedProminent)
            }
        }
        .padding()
        .onReceive(Timer.publish(every: 2, on: .main, in: .common).autoconnect()) { _ in
            accessibilityGranted = AXIsProcessTrusted()
        }
    }

    @MainActor
    func requestAccess() {
        PermisoAssistant.shared.present(panel: .accessibility)
    }
}

Requirements

系统要求

  • macOS: The library targets macOS (version as specified by the package; check for macOS 13+ for best compatibility)
  • Swift: Swift 5.9+
  • Main Actor:
    PermisoAssistant.shared.present(panel:)
    must be called from the main thread /
    @MainActor
    context
  • macOS:本库面向macOS(具体版本以包内说明为准;建议使用macOS 13+以获得最佳兼容性)
  • Swift:Swift 5.9+
  • Main Actor
    PermisoAssistant.shared.present(panel:)
    必须在主线程/
    @MainActor
    上下文调用

Entitlements / Info.plist

权限配置 / Info.plist

For accessibility usage, ensure your app's
Info.plist
includes a usage description (though macOS doesn't require this like iOS, it's good practice), and that your app is not sandboxed or has the correct entitlements if it needs to use accessibility APIs:
xml
<!-- In your .entitlements file if needed -->
<key>com.apple.security.temporary-exception.apple-events</key>
<true/>
For apps that actually use accessibility features after permission is granted:
swift
// Request trust prompt (system dialog) alongside Permiso's guided UI
let options = [kAXTrustedCheckOptionPrompt.takeRetainedValue(): true] as CFDictionary
AXIsProcessTrustedWithOptions(options)
对于辅助功能使用,请确保应用的
Info.plist
包含使用说明(尽管macOS不像iOS那样强制要求,但这是良好实践),并且应用未开启沙箱,或者如果需要使用辅助功能API,请配置正确的权限:
xml
<!-- 如有需要,添加到你的.entitlements文件中 -->
<key>com.apple.security.temporary-exception.apple-events</key>
<true/>
对于在获得权限后实际使用辅助功能的应用:
swift
// 在Permiso引导式UI之外,请求信任提示(系统对话框)
let options = [kAXTrustedCheckOptionPrompt.takeRetainedValue(): true] as CFDictionary
AXIsProcessTrustedWithOptions(options)

Troubleshooting

故障排除

Panel doesn't appear
  • Ensure you're calling from
    @MainActor
    / main thread
  • Check that your app has a visible window; the panel attaches to the app's UI context
AXIsProcessTrusted()
returns false even after granting
  • macOS caches trust state; the app may need to be relaunched or the check polled with a timer (see polling pattern above)
  • Some sandboxed apps require a full app restart after granting accessibility
Build errors:
cannot find 'PermisoAssistant' in scope
  • Confirm
    import Permiso
    is at the top of the file
  • Confirm the package is added to the correct target in Xcode, not just the project
Panel appears but dismisses immediately
  • Make sure you're not overriding the window or calling dismiss logic right after present
  • Avoid calling present inside a
    Task { }
    that gets cancelled immediately
面板不显示
  • 确保你在
    @MainActor
    /主线程中调用
  • 检查应用是否有可见窗口;面板会附加到应用的UI上下文
AXIsProcessTrusted()
已授予权限但仍返回false
  • macOS会缓存信任状态;可能需要重启应用,或者使用计时器轮询检查(参考上述轮询模式)
  • 部分开启沙箱的应用在授予辅助功能权限后需要完全重启
编译错误:
cannot find 'PermisoAssistant' in scope
  • 确认文件顶部已添加
    import Permiso
  • 确认包已添加到Xcode的正确目标中,而不只是项目中
面板显示后立即消失
  • 确保你没有在调用present后立即覆盖窗口或调用关闭逻辑
  • 避免在会立即被取消的
    Task { }
    中调用present

Key Types Reference

关键类型参考

TypeDescription
PermisoAssistant
Singleton entry point — use
.shared
PermisoAssistant.shared.present(panel:)
Shows the guided permission dialog
.accessibility
Panel type for Accessibility settings
类型描述
PermisoAssistant
单例入口点 — 使用
.shared
访问
PermisoAssistant.shared.present(panel:)
显示引导式权限对话框
.accessibility
用于辅助功能设置的面板类型