[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-1694":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":23,"hasPages":23,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":36,"readmeContent":37,"aiSummary":38,"trendingCount":16,"starSnapshotCount":16,"syncStatus":14,"lastSyncTime":39,"discoverSource":40},1694,"PermissionFlow","jaywcjlove\u002FPermissionFlow","jaywcjlove","A macOS library for guiding users through permission setup with System Settings deeplinks and drag-to-authorize support.","",null,"Swift",316,15,2,4,0,3,20,133,9,3.61,"MIT License",false,"main",[26,27,28,7,29,30,31,32,33,34,35],"accessibility","accessibility-permission","appkit","macos","permission-manager","permissions","sandbox","sandbox-permissions","swift","swift-package","2026-06-12 02:00:31","\u003Cdiv align=\"left\">\n  \u003Csup>Using \u003Ca href=\"https:\u002F\u002Fwangchujiang.com\u002F#\u002Fapp\" target=\"_blank\">my app\u003C\u002Fa> is also a way to \u003Ca href=\"https:\u002F\u002Fwangchujiang.com\u002F#\u002Fsponsor\" target=\"_blank\">support\u003C\u002Fa> me:\u003C\u002Fsup>\n  \u003Cbr>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6766860898\" title=\"Zipora: Zip\u002FRAR\u002F7Z Unarchiver\">\u003Cimg alt=\"Zipora: Zip\u002FRAR\u002F7Z Unarchiver\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fzipora.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6758053530\" title=\"Scap: Screenshot & Markup Edit for macOS\">\u003Cimg alt=\"Scap: Screenshot & Markup Edit\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fscap.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6757317079\" title=\"Screen Test for macOS\">\u003Cimg alt=\"Screen Test\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fscreen-test.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6755948110\" title=\"Deskmark for macOS\">\u003Cimg alt=\"Deskmark\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fdeskmark.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6500434773\" title=\"Keyzer for macOS\">\u003Cimg alt=\"Keyzer\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fkeyzer.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fgithub.com\u002Fjaywcjlove\u002Fvidwall-hub\" title=\"Vidwall Hub for macOS\">\u003Cimg alt=\"Vidwall Hub\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fvidwall-hub.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6752624705\" title=\"VidCrop for macOS\">\u003Cimg alt=\"VidCrop\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fvidcrop.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6747587746\" title=\"Vidwall for macOS\">\u003Cimg alt=\"Vidwall\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fvidwall.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fwangchujiang.com\u002Fmousio-hint\u002F\" title=\"Mousio Hint for macOS\">\u003Cimg alt=\"Mousio Hint\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fmousio-hint.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6746747327\" title=\"Mousio for macOS\">\u003Cimg alt=\"Mousio\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fmousio.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6745227444\" title=\"Musicer for macOS\">\u003Cimg alt=\"Musicer\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fmusicer.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6743841447\" title=\"Audioer for macOS\">\u003Cimg alt=\"Audioer\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Faudioer.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6744690194\" title=\"FileSentinel for macOS\">\u003Cimg alt=\"FileSentinel\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Ffile-sentinel.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6743495172\" title=\"FocusCursor for macOS\">\u003Cimg alt=\"FocusCursor\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Ffocus-cursor.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6742680573\" title=\"Videoer for macOS\">\u003Cimg alt=\"Videoer\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fvideoer.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6740425504\" title=\"KeyClicker for macOS\">\u003Cimg alt=\"KeyClicker\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fkey-clicker.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6739052447\" title=\"DayBar for macOS\">\u003Cimg alt=\"DayBar\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fdaybar.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6739444407\" title=\"Iconed for macOS\">\u003Cimg alt=\"Iconed\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Ficoned.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6737160756\" title=\"Menuist for macOS\">\u003Cimg alt=\"Menuist\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Frightmenu-master.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6723903021\" title=\"Paste Quick for macOS\">\u003Cimg alt=\"Quick RSS\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fpaste-quick.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6670696072&platform=mac\" title=\"Quick RSS for macOS\u002FiOS\">\u003Cimg alt=\"Quick RSS\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fquick-rss.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6670167443\" title=\"Web Serve for macOS\">\u003Cimg alt=\"Web Serve\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fweb-serve.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6503953628&platform=mac\" title=\"Copybook Generator for macOS\u002FiOS\">\u003Cimg alt=\"Copybook Generator\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fcopybook-generator.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6471227008&platform=mac\" title=\"DevTutor for macOS\u002FiOS\">\u003Cimg alt=\"DevTutor for SwiftUI\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fdevtutor.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6479819388&platform=mac\" title=\"RegexMate for macOS\u002FiOS\">\u003Cimg alt=\"RegexMate\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fregex-mate.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6479194014&platform=mac\" title=\"Time Passage for macOS\u002FiOS\">\u003Cimg alt=\"Time Passage\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Ftime-passage.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6478772538\" title=\"IconizeFolder for macOS\">\u003Cimg alt=\"Iconize Folder\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Ficonize-folder.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6478511402&platform=mac\" title=\"Textsound Saver for macOS\u002FiOS\">\u003Cimg alt=\"Textsound Saver\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Ftextsound-saver.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6476924627\" title=\"Create Custom Symbols for macOS\">\u003Cimg alt=\"Create Custom Symbols\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fcreate-custom-symbols.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6476452351\" title=\"DevHub for macOS\">\u003Cimg alt=\"DevHub\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fdevhub.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6476400184\" title=\"Resume Revise for macOS\">\u003Cimg alt=\"Resume Revise\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fresume-revise.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6472593276\" title=\"Palette Genius for macOS\">\u003Cimg alt=\"Palette Genius\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fpalette-genius.png\">\u003C\u002Fa>\n  \u003Ca target=\"_blank\" href=\"https:\u002F\u002Fjaywcjlove.github.io\u002Fmaslink\u002F?id=6470879005\" title=\"Symbol Scribe for macOS\">\u003Cimg alt=\"Symbol Scribe\" height=\"52\" src=\"https:\u002F\u002Fwangchujiang.com\u002Fappicon\u002Fsymbol-scribe.png\">\u003C\u002Fa>\n\u003C\u002Fdiv>\n\u003Chr>\n\n[中文](.\u002FREADME.zh.md) • [Installation](#installation) • [Public API](#public-api) • [System Settings URL Scheme](#system-settings-url-scheme)\n\n\u003Chr>\n\nPermissionFlow\n===\n\n\u003Cimg alt=\"PermissionFlow\" src=\"https:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002F9af78ef4-be7b-48b2-8651-3b8c42e0a9c8\" \u002F>\n\n`PermissionFlow` is a macOS permission-guidance library that opens the target `System Settings` privacy pane and, for supported drag-based authorization pages, shows a floating panel that follows the System Settings window and lets users drag the current `.app` into the permission list. It also includes `SystemSettingsKit` for strongly typed deeplinks into `System Settings` pages and subsections.\n\n- `PermissionFlow`: macOS-only floating guidance for drag-based privacy authorization\n- `SystemSettingsKit`: typed Settings deeplinks for macOS, with partial iOS support\n\nIt opens the correct privacy page automatically and, for panes that support drag-based authorization, shows a floating helper panel that follows the `System Settings` window and lets the user drag the current `.app` bundle into the permission list.\n\n\n## Features\n\n- **Real-time permission status display**: Buttons automatically show whether permissions are granted with visual feedback (green checkmark for granted, blue arrow for not granted)\n- Opens the target `System Settings` privacy pane automatically\n- Animates the floating panel from the click position to the `System Settings` window\n- Follows the `System Settings` window while it moves\n- Shows the current app as a native drag source\n- Keeps only one active floating panel at a time\n- Closes the floating panel automatically when `System Settings` closes\n- Supports adaptive floating panel height based on content\n- **Intelligent permission detection**: Uses official Apple APIs for accurate permission status checking without triggering system prompts\n\n## Requirements\n\n- macOS 13+\n- Swift 6 package toolchain\n- SwiftUI + AppKit host application\n\n## Installation\n\nAdd the package to your app:\n\n```swift\ndependencies: [\n    .package(url: \"https:\u002F\u002Fgithub.com\u002Fjaywcjlove\u002FPermissionFlow.git\", from: \"1.0.0\")\n]\n```\n\nThe package URL and installation entry stay the same as before. What changed is the product layout: permission status detection for some panes is now split into optional extensions instead of being linked by default.\n\nThis package now exposes these library products:\n\n- `PermissionFlow`: floating authorization guidance for supported privacy panes on macOS\n- `SystemSettingsKit`: reusable deeplink API for arbitrary System Settings pages\n- `PermissionFlowExtendedStatus`: one-stop optional status detection for `.bluetooth`, `.inputMonitoring`, `.mediaAppleMusic`, and `.screenRecording`\n- `PermissionFlowBluetoothStatus`: optional status detection for `.bluetooth`\n- `PermissionFlowMediaStatus`: optional status detection for `.mediaAppleMusic`\n- `PermissionFlowInputMonitoringStatus`: optional status detection for `.inputMonitoring`\n- `PermissionFlowScreenRecordingStatus`: optional status detection for `.screenRecording`\n\nThen add the product you need to your target:\n\n```swift\n.target(\n    name: \"YourApp\",\n    dependencies: [\n        .product(name: \"PermissionFlow\", package: \"PermissionFlow\"),\n        .product(name: \"SystemSettingsKit\", package: \"PermissionFlow\")\n    ]\n)\n```\n\nIf you want status detection for `.bluetooth`, `.inputMonitoring`, `.mediaAppleMusic`, and `.screenRecording`, add the optional extension product as well:\n\n```swift\n.target(\n    name: \"YourApp\",\n    dependencies: [\n        .product(name: \"PermissionFlow\", package: \"PermissionFlow\"),\n        .product(name: \"PermissionFlowExtendedStatus\", package: \"PermissionFlow\")\n    ]\n)\n```\n\nYou can also depend on only the specific extension products you need:\n\n```swift\n.product(name: \"PermissionFlowBluetoothStatus\", package: \"PermissionFlow\")\n.product(name: \"PermissionFlowMediaStatus\", package: \"PermissionFlow\")\n.product(name: \"PermissionFlowInputMonitoringStatus\", package: \"PermissionFlow\")\n.product(name: \"PermissionFlowScreenRecordingStatus\", package: \"PermissionFlow\")\n```\n\nWhy this split matters:\n\n- Apps that only use `PermissionFlow` keep the original core integration and do not need to link optional status-detection modules by default.\n- This reduces unnecessary compile-time and link-time dependencies such as `CoreBluetooth`, `MusicKit`, and `Carbon` when those permission states are not needed.\n- In practice, this usually keeps the final app product cleaner and can reduce the amount of optional code that ends up linked into your binary.\n\nPlatform support:\n\n- `PermissionFlow`: `macOS 13+`\n- `SystemSettingsKit`: `macOS 13+`, `iOS 16+`\n\n`SystemSettingsKit` is intentionally partial on iOS. The macOS deeplink-based pane and anchor APIs remain macOS-only, while iOS only exposes destinations that are publicly supported by UIKit, such as the current app's Settings page.\n\n## Supported Permission Panes\n\n`PermissionFlow` covers these privacy panes. Most use the floating drag-and-drop authorization workflow; `.microphone` uses the system microphone prompt instead.\n\n- `.accessibility`: Opens `Privacy & Security > Accessibility`. ✅ **Status Detection Supported**\n- `.fullDiskAccess`: Opens `Privacy & Security > Full Disk Access`. ✅ **Status Detection Supported**\n- `.inputMonitoring`: Opens `Privacy & Security > Input Monitoring`. ✅ **Status Detection Supported**\n- `.screenRecording`: Opens `Privacy & Security > Screen Recording`. ✅ **Status Detection Supported**\n- `.microphone`: Requests microphone authorization and opens `Privacy & Security > Microphone` when settings access is needed. ✅ **Status Detection Supported**\n- `.bluetooth`: Opens `Privacy & Security > Bluetooth`. ✅ **Supports status detection**\n- `.mediaAppleMusic`: Opens `Privacy & Security > Media & Apple Music`. ✅ **Supports status detection**\n- `.appManagement`: Opens `Privacy & Security > App Management`. ⚠️ Status detection not available\n- `.developerTools`: Opens `Privacy & Security > Developer Tools`. ⚠️ Status detection not available\n\n**Permission Status Display**: For supported permissions, `PermissionFlowButton` automatically displays the current authorization status:\n- ✅ **Granted**: Green checkmark icon with \"Granted\" text\n- ➡️ **Not Granted**: Blue arrow icon with \"Grant\" text  \n- Built into `PermissionFlow`: `.accessibility`, `.fullDiskAccess`, `.microphone`\n- Available through optional status extensions: `.bluetooth`, `.inputMonitoring`, `.mediaAppleMusic`, `.screenRecording`\n- 🔄 **Checking**: Clock icon with \"Checking...\" text\n- ❓ **Unknown**: Blue arrow icon with \"Open\" text (for unsupported detection)\n\nFor every other `System Settings` page or privacy subsection, use `SystemSettingsKit`.\n\n## Info.plist Privacy Descriptions\n\nPermissions that trigger Apple's system privacy prompt must include the matching usage description in the host app's `Info.plist`. If the host macOS app uses App Sandbox, also enable the matching entitlement in **Signing & Capabilities > App Sandbox**.\n\n### Microphone\n\nUse this when requesting `.microphone` or calling Apple's microphone authorization APIs.\n\n```xml\n\u003Ckey>NSMicrophoneUsageDescription\u003C\u002Fkey>\n\u003Cstring>This app needs microphone access for audio recording.\u003C\u002Fstring>\n```\n\nFor sandboxed macOS apps, turn on `Audio Input`, or add:\n\n```xml\n\u003Ckey>com.apple.security.device.audio-input\u003C\u002Fkey>\n\u003Ctrue\u002F>\n```\n\n### Camera\n\nUse this when requesting camera access.\n\n```xml\n\u003Ckey>NSCameraUsageDescription\u003C\u002Fkey>\n\u003Cstring>This app needs camera access for video capture.\u003C\u002Fstring>\n```\n\nFor sandboxed macOS apps, turn on `Camera`, or add:\n\n```xml\n\u003Ckey>com.apple.security.device.camera\u003C\u002Fkey>\n\u003Ctrue\u002F>\n```\n\n### Apple Events\n\nUse this when your app sends Apple Events, such as automating or controlling another app.\n\n```xml\n\u003Ckey>NSAppleEventsUsageDescription\u003C\u002Fkey>\n\u003Cstring>This app needs to control other apps for authorization guidance.\u003C\u002Fstring>\n```\n\nFor sandboxed macOS apps, turn on `Apple Events`, or add:\n\n```xml\n\u003Ckey>com.apple.security.automation.apple-events\u003C\u002Fkey>\n\u003Ctrue\u002F>\n```\n\n## Quick Start\n\n### SwiftUI button\n\n```swift\nimport PermissionFlow\nimport SwiftUI\n\nstruct ContentView: View {\n    var body: some View {\n        PermissionFlowButton(\n            title: \"Grant Accessibility\",\n            pane: .accessibility,\n            suggestedAppURLs: [Bundle.main.bundleURL]\n        )\n    }\n}\n```\n\n### Enable optional status detection\n\nTo enable status detection for `.bluetooth`, `.inputMonitoring`, `.mediaAppleMusic`, and `.screenRecording`, add the optional extension products and register them once at app startup:\n\n```swift\nimport PermissionFlowExtendedStatus\nimport SwiftUI\n\n@main\nstruct MyApp: App {\n    init() {\n        PermissionFlowExtendedStatus.register()\n    }\n\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n    }\n}\n```\n\n### Manual status display\n\n```swift\nimport AppKit\nimport PermissionFlow\nimport SwiftUI\n\nstruct ManualPermissionButton: View {\n    @StateObject private var controller = PermissionFlow.makeController()\n    @State private var authorizationState: PermissionAuthorizationState = .checking\n\n    let didBecomeActive = NotificationCenter.default.publisher(\n        for: NSApplication.didBecomeActiveNotification\n    )\n\n    var body: some View {\n        Button {\n            controller.authorize(\n                pane: .accessibility,\n                suggestedAppURLs: [Bundle.main.bundleURL],\n                sourceFrameInScreen: clickSourceFrameInScreen()\n            )\n        } label: {\n            Label {\n                Text(title(for: authorizationState))\n            } icon: {\n                let icon = PermissionFlowButtonState\n                    .make(from: authorizationState).systemImage\n                Image(systemName: icon)\n            }\n        }\n        .onAppear(perform: refreshStatus)\n        .onReceive(didBecomeActive) { _ in\n            refreshStatus()\n        }\n    }\n\n    private func refreshStatus() {\n        let provider = PermissionStatusRegistry.provider(for: .accessibility)\n        authorizationState = provider.authorizationState()\n    }\n\n    private func title(for state: PermissionAuthorizationState) -> String {\n        switch state {\n        case .granted:\n            \"Granted\"\n        case .notGranted:\n            \"Grant\"\n        case .unknown:\n            \"Open\"\n        case .checking:\n            \"Checking...\"\n        }\n    }\n\n    private func clickSourceFrameInScreen() -> CGRect {\n        let mouse = NSEvent.mouseLocation\n        return CGRect(x: mouse.x - 16, y: mouse.y - 16, width: 32, height: 32)\n    }\n}\n```\n\n### Manual controller usage\n\nUse `PermissionFlowController` when you want to control the flow yourself:\n\n```swift\nimport PermissionFlow\nimport SwiftUI\n\n@MainActor\nfinal class PermissionViewModel: ObservableObject {\n    private let controller = PermissionFlow.makeController()\n\n    func requestFullDiskAccess() {\n        controller.authorize(\n            pane: .fullDiskAccess,\n            suggestedAppURLs: [Bundle.main.bundleURL]\n        )\n    }\n}\n```\n\n### Keep the launch animation\n\nIf you use `PermissionFlowButton`, the package captures the click position for you and the floating panel will animate from the button click to the `System Settings` window automatically.\n\nIf you call `PermissionFlowController.authorize(...)` manually, pass the click source frame yourself. Otherwise the panel will still appear, but it will skip the launch animation and jump directly to the target position.\n\n```swift\nimport AppKit\nimport PermissionFlow\n\n@MainActor\nfinal class PermissionViewModel: ObservableObject {\n    private let controller = PermissionFlow.makeController()\n\n    func requestAccessibility() {\n        let mouseLocation = NSEvent.mouseLocation\n        let sourceFrame = CGRect(\n            x: mouseLocation.x - 16,\n            y: mouseLocation.y - 16,\n            width: 32,\n            height: 32\n        )\n\n        controller.authorize(\n            pane: .accessibility,\n            suggestedAppURLs: [Bundle.main.bundleURL],\n            sourceFrameInScreen: sourceFrame\n        )\n    }\n}\n```\n\n## Public API\n\n### `PermissionFlowButton`\n\nConvenience SwiftUI button for launching a permission flow.\n\n```swift\nPermissionFlowButton(\n    title: \"Open Screen Recording\",\n    pane: .screenRecording,\n    suggestedAppURLs: [Bundle.main.bundleURL],\n    configuration: .init()\n)\n```\n\n### `PermissionFlow.makeController`\n\nCreates a reusable controller:\n\n```swift\nlet controller = PermissionFlow.makeController(\n    configuration: .init(\n        requiredAppURLs: [Bundle.main.bundleURL],\n        promptForAccessibilityTrust: false\n    )\n)\n```\n\n### `PermissionFlowController`\n\nMain entry points:\n\n- `authorize(pane:suggestedAppURLs:sourceFrameInScreen:)`\n- `showPanel()`\n- `closePanel()`\n- `resetDroppedApps()`\n- `registerDroppedApp(_:)`\n\n### `SystemSettings.open`\n\nOpen any System Settings page directly from a pane identifier and optional anchor:\n\n```swift\nimport SystemSettingsKit\n\nSystemSettings.open(\n    paneIdentifier: \"com.apple.Wallpaper-Settings.extension\"\n)\n\nSystemSettings.open(\n    paneIdentifier: \"com.apple.settings.PrivacySecurity.extension\",\n    anchor: \"Privacy_Advertising\"\n)\n```\n\nYou can also use `SystemSettingsDestination`:\n\n```swift\nimport SystemSettingsKit\n\nSystemSettings.open(.wallpaper)\nSystemSettings.open(.privacy(anchor: .privacyAllFiles))\nSystemSettings.open(.displays(anchor: .resolutionSection))\n```\n\n## System Settings URL Scheme\n\n`SystemSettingsKit` exposes a lightweight API for opening arbitrary System Settings panes using the `x-apple.systempreferences:` URL scheme.\n\nThe behavior and examples are based on the identifiers and deeplink notes collected in [SystemSettings-URLs-macOS](https:\u002F\u002Fgithub.com\u002Fjaywcjlove\u002FSystemSettings-URLs-macOS\u002Fblob\u002Fmain\u002FREADME.md).\n\n### URL format\n\n```text\nx-apple.systempreferences:\u003Cpane-identifier>\nx-apple.systempreferences:\u003Cpane-identifier>?\u003Canchor>\n```\n\nExamples:\n\n```text\nx-apple.systempreferences:com.apple.Wallpaper-Settings.extension\nx-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Advertising\nx-apple.systempreferences:com.apple.Wallpaper-Settings.extension?ScreenSaver\n```\n\n### Package type\n\n```swift\npublic struct SystemSettingsDestination {\n    public let paneIdentifier: String\n    public let anchor: String?\n    public var url: URL { get }\n}\n```\n\n### Convenience destinations\n\nThe package includes a few common helpers:\n\n- `.wallpaper`\n- `.displays`\n- `.displays(anchor:)`\n- `.accessibility`\n- `.accessibility(anchor:)`\n- `.bluetooth`\n- `.loginItems`\n- `.loginItems(anchor:)`\n- `.loginItems(extensionPointIdentifier:)`\n- `.wifi`\n- `.wifi(anchor:)`\n- `.vpn`\n- `.vpn(anchor:)`\n- `.privacy(anchor:)`\n\n### Privacy anchors\n\nFor Privacy & Security subsections, use:\n\n```swift\nSystemSettings.open(.privacy(anchor: .privacyAllFiles))\nSystemSettings.open(.privacy(anchor: .privacyAdvertising))\nSystemSettings.open(.privacy(anchor: .privacyAccessibility))\nSystemSettings.open(.privacy(anchor: .security))\n```\n\nThe existing `PermissionFlowPane` type continues to handle the privacy pages used by the authorization workflow.\n\n- `.appManagement`: Opens `Privacy & Security > App Management`.\n- `.accessibility`: Opens `Privacy & Security > Accessibility`.\n- `.bluetooth`: Opens `Privacy & Security > Bluetooth`.\n- `.developerTools`: Opens `Privacy & Security > Developer Tools`.\n- `.fullDiskAccess`: Opens `Privacy & Security > Full Disk Access`.\n- `.inputMonitoring`: Opens `Privacy & Security > Input Monitoring`.\n- `.mediaAppleMusic`: Opens `Privacy & Security > Media & Apple Music`.\n- `.microphone`: Requests microphone authorization and opens `Privacy & Security > Microphone` when settings access is needed.\n- `.screenRecording`: Opens `Privacy & Security > Screen Recording`.\n\nAvailable typed privacy anchors and their destinations:\n\n- `.advanced`: `Privacy & Security > Advanced`\n- `.fileVault`: `Privacy & Security > FileVault`\n- `.locationAccessReport`: `Privacy & Security > Location Access Report`\n- `.lockdownMode`: `Privacy & Security > Lockdown Mode`\n- `.privacyAccessibility`: `Privacy & Security > Accessibility`\n- `.privacyAdvertising`: `Privacy & Security > Advertising`\n- `.privacyAllFiles`: `Privacy & Security > Full Disk Access`\n- `.privacyAnalytics`: `Privacy & Security > Analytics & Improvements`\n- `.privacyAppBundles`: `Privacy & Security > App Management`\n- `.privacyAudioCapture`: `Privacy & Security > Audio Capture`\n- `.privacyAutomation`: `Privacy & Security > Automation`\n- `.privacyBluetooth`: `Privacy & Security > Bluetooth`\n- `.privacyCalendars`: `Privacy & Security > Calendars`\n- `.privacyCamera`: `Privacy & Security > Camera`\n- `.privacyContacts`: `Privacy & Security > Contacts`\n- `.privacyDevTools`: `Privacy & Security > Developer Tools`\n- `.privacyFilesAndFolders`: `Privacy & Security > Files & Folders`\n- `.privacyFocus`: `Privacy & Security > Focus`\n- `.privacyHomeKit`: `Privacy & Security > Home`\n- `.privacyListenEvent`: `Privacy & Security > Input Monitoring`\n- `.privacyLocationServices`: `Privacy & Security > Location Services`\n- `.privacyMedia`: `Privacy & Security > Media & Apple Music`\n- `.privacyMicrophone`: `Privacy & Security > Microphone`\n- `.privacyMotion`: `Privacy & Security > Motion & Fitness`\n- `.privacyNudityDetection`: `Privacy & Security > Sensitive Content Warning`\n- `.privacyPasskeyAccess`: `Privacy & Security > Passkey Access`\n- `.privacyPhotos`: `Privacy & Security > Photos`\n- `.privacyReminders`: `Privacy & Security > Reminders`\n- `.privacyRemoteDesktop`: `Privacy & Security > Remote Desktop`\n- `.privacyScreenCapture`: `Privacy & Security > Screen Recording`\n- `.privacySpeechRecognition`: `Privacy & Security > Speech Recognition`\n- `.privacySystemServices`: `Privacy & Security > System Services`\n- `.security`: `Privacy & Security > Security`\n- `.securityImprovements`: `Privacy & Security > Security Improvements`\n\n### Displays anchors\n\nDisplays now has a typed helper instead of raw string anchors:\n\n```swift\nSystemSettings.open(.displays)\nSystemSettings.open(.displays(anchor: .arrangementSection))\nSystemSettings.open(.displays(anchor: .resolutionSection))\nSystemSettings.open(.displays(anchor: .nightShiftSection))\n```\n\nAvailable display anchors and their destinations:\n\n- `.advancedSection`: `Displays > Advanced`\n- `.ambienceSection`: `Displays > Ambience`\n- `.arrangementSection`: `Displays > Arrangement`\n- `.characteristicSection`: `Displays > Display Characteristics`\n- `.displaysSection`: `Displays > Displays`\n- `.miscellaneousSection`: `Displays > Miscellaneous`\n- `.nightShiftSection`: `Displays > Night Shift`\n- `.profileSection`: `Displays > Color Profile`\n- `.resolutionSection`: `Displays > Resolution`\n- `.sidecarSection`: `Displays > Sidecar`\n\n### Login Items anchors\n\nLogin Items supports typed subsection anchors:\n\n```swift\nSystemSettings.open(.loginItems)\nSystemSettings.open(.loginItems(anchor: .extensionItems))\nSystemSettings.open(.loginItems(extensionPointIdentifier: .quickLookPreview))\nSystemSettings.open(.loginItems(extensionPointIdentifier: .shareServices))\n```\n\nAvailable login item anchors and extension point helpers:\n\n- `.extensionItems`: `Login Items > Extension Items`\n- `.shareServices`: `extensionPointIdentifier=com.apple.share-services`\n- `.actions`: `extensionPointIdentifier=com.apple.ui-services`\n- `.photoEditing`: `extensionPointIdentifier=com.apple.photo-editing`\n- `.spotlightImporter`: `extensionPointIdentifier=com.apple.spotlight.import`\n- `.quickLookPreview`: `Login Items & Extensions > Extensions > Quick Look`, using `extensionPointIdentifier=com.apple.quicklook.preview`\n- `.fileProvider`: `extensionPointIdentifier=com.apple.fileprovider-nonui`\n- `.finderQuickActions`: `extensionPointIdentifier=com.apple.finder-quick-actions`\n- `.touchBarQuickActions`: `extensionPointIdentifier=com.apple.touchbar-quick-actions`\n- `.legacyDockTiles`: `extensionPointIdentifier=com.apple.extensionkit.legacy-plugins.docktiles`\n- `.legacySpotlightImporter`: `extensionPointIdentifier=com.apple.extensionkit.legacy-plugins.spotlight-importer`\n\n### Wi-Fi anchors\n\nWi-Fi supports typed subsection anchors:\n\n```swift\nSystemSettings.open(.wifi)\nSystemSettings.open(.wifi(anchor: .generalMain))\nSystemSettings.open(.wifi(anchor: .generalJoin))\nSystemSettings.open(.wifi(anchor: .generalDetails))\nSystemSettings.open(.wifi(anchor: .advanced))\n```\n\nAvailable Wi-Fi anchors and their destinations:\n\n- `.advanced`: `Wi-Fi > Advanced`\n- `.generalDetails`: `Wi-Fi > Details`\n- `.generalJoin`: `Wi-Fi > Join`\n- `.generalMain`: `Wi-Fi > Main`\n\n### VPN anchors\n\nVPN supports typed subsection anchors:\n\n```swift\nSystemSettings.open(.vpn)\nSystemSettings.open(.vpn(anchor: .vpn))\nSystemSettings.open(.vpn(anchor: .vpnOnDemand))\n```\n\nAvailable VPN anchors and their destinations:\n\n- `.vpn`: `VPN > VPN`\n- `.vpnOnDemand`: `VPN > VPN on Demand`\n\n### Accessibility anchors\n\nAccessibility has a typed helper for common sections and a raw string fallback for detailed control-level anchors:\n\n```swift\nSystemSettings.open(.accessibility)\nSystemSettings.open(.accessibility(anchor: .display))\nSystemSettings.open(.accessibility(anchor: .voiceOver))\nSystemSettings.open(.accessibility(anchor: \"AX_ZOOM_MAX_FACTOR\"))\n```\n\nAvailable common accessibility anchors:\n\n- `.display`: `Accessibility > Display`\n- `.text`: `Accessibility > Text`\n- `.pointer`: `Accessibility > Pointer`\n- `.mouseAndTrackpad`: `Accessibility > Mouse & Trackpad`\n- `.headphones`: `Accessibility > Headphones`\n- `.voiceOver`: `Accessibility > VoiceOver`\n- `.zoom`: `Accessibility > Zoom`\n- `.displayFilters`: `Accessibility > Display Filters`\n- `.backgroundSounds`: `Accessibility > Background Sounds`\n- `.spokenContent`: `Accessibility > Spoken Content`\n- `.captions`: `Accessibility > Captions`\n- `.audio`: `Accessibility > Audio`\n- `.descriptions`: `Accessibility > Audio Descriptions`\n- `.keyboard`: `Accessibility > Keyboard`\n- `.fullKeyboardAccess`: `Accessibility > Full Keyboard Access`\n- `.stickyKeys`: `Accessibility > Sticky Keys`\n- `.slowKeys`: `Accessibility > Slow Keys`\n- `.virtualKeyboard`: `Accessibility > Accessibility Keyboard`\n- `.voiceControl`: `Accessibility > Voice Control`\n- `.switchControl`: `Accessibility > Switch Control`\n- `.alternateMouseButtons`: `Accessibility > Alternate Mouse Buttons`\n- `.headMouse`: `Accessibility > Head Pointer`\n- `.mouseKeys`: `Accessibility > Mouse Keys`\n- `.hoverText`: `Accessibility > Hover Text`\n- `.hoverTyping`: `Accessibility > Hover Typing`\n- `.liveSpeech`: `Accessibility > Live Speech`\n- `.personalVoice`: `Accessibility > Personal Voice`\n- `.siri`: `Accessibility > Siri`\n- `.shortcut`: `Accessibility > Accessibility Shortcut`\n\n## Configuration\n\n```swift\nlet configuration = PermissionFlowConfiguration(\n    requiredAppURLs: [Bundle.main.bundleURL],\n    promptForAccessibilityTrust: false\n)\n```\n\n### Notes\n\n- `requiredAppURLs` preloads apps into the panel\n- `promptForAccessibilityTrust` controls whether AX trust is actively prompted\n\n## How It Works\n\n1. Your app requests a permission pane.\n2. `PermissionFlow` opens the matching `System Settings` page.\n3. If that pane supports drag-based authorization, a floating panel appears.\n4. The panel animates from the click location to the `System Settings` window.\n5. The panel tracks the `System Settings` window position.\n6. The user drags the current `.app` bundle into the permission list.\n\n## Example\n\nThe repository includes an `Example` macOS app that demonstrates all supported permission flows.\n\n## Notes and Limitations\n\n- The floating helper is only shown for panes that support app-list style authorization.\n- **Permission status detection**: Uses official Apple APIs (`CGPreflightListenEventAccess`, `CGPreflightScreenCaptureAccess`, `AXIsProcessTrusted`) for accurate status checking without triggering system prompts.\n- **Status refresh**: Permission status is automatically refreshed when the app becomes active and when buttons appear on screen.\n- `System Settings` behavior is controlled by macOS and may vary slightly by OS version.\n- AX-based window tracking is used when available. Window Server frame lookup is used as fallback and bootstrap.\n- The package does not bypass macOS security. It only guides the user through the system UI.\n\n## License\n\nLicensed under the MIT License.\n","PermissionFlow 是一个 macOS 库，用于引导用户通过系统设置的深度链接和拖动授权来完成权限配置。该项目使用 Swift 语言开发，支持 AppKit 框架，具备访问无障碍权限、沙箱权限管理等功能。其核心特性包括直接跳转到系统设置相关页面以及提供直观的拖拽授权方式，简化了开发者在应用中请求和处理敏感权限的过程。适用于需要用户授予特定权限才能正常运行的 macOS 应用场景，如文件访问、摄像头或麦克风使用等。","2026-06-11 02:45:29","CREATED_QUERY"]