macOS管理App Sandbox权限
macOS管理App Sandbox权限

macOS管理App Sandbox权限

macOS 应用中,如果希望访问特定目录(如Downloads等文件夹),需要配合App Sandbox系统机制来允许用户授予访问权限。实现“下载”、“桌面”、“文稿”等目录的访问。

管理App Sandbox权限

打开Xcode项目,TARGETS – Signing & Capabilities,在Xcode16中,macOS项目默认添加App Sandbox权限。

如果没有App Sandbox权限,则在Capability中选择并添加 App Sandbox。

App Sandbox权限说明

1、Network(网络访问)

Incoming Connections (Server):允许 App 接受外部设备的连接,例如开 HTTP Server。默认关闭。

Outgoing Connections (Client):允许 App 主动连接网络,访问 Web API、下载文件等。默认开启(大多数 App 需要)。

2、Hardware(硬件访问)

Camera:访问摄像头(系统会弹窗提示用户)。

Audio Input:访问麦克风。

USB:访问连接的 USB 设备(较少使用)。

Printing(两项):打印权限(可能重复显示)。

Bluetooth:访问蓝牙设备(macOS 11+)。

3、App Data(用户隐私数据)

Contacts:访问通讯录(需弹窗授权)。

Location:获取定位信息(需 Info.plist 配置)。

Calendar:访问日历事件。

4、File Access(文件访问权限)

User Selected File:用户通过 NSOpenPanel 选取的文件/目录,可长期访问。

Downloads Folder:是否允许访问 ~/Downloads。

Pictures Folder:是否允许访问 ~/Pictures。

Music Folder:是否允许访问 ~/Music。

Movies Folder:是否允许访问 ~/Movies。

每个文件夹权限都可以设为:

None:禁止访问

Read Only:只读

Read/Write:读写(建议仅在需要写入时开启)

注意:这些权限如果不勾选,即使调用相关 API,系统也会拒绝访问或崩溃。其中部分权限属于 macOS 的 [TCC(Transparency Consent Control)系统],必须由用户授权才能访问。

实际应用

例如,将图片保存到Downloads文件夹中。

首先,在App Sandbox中开启Downloads权限:

图片保存文件夹的代码:

func saveTestImage() {
        // 1. 创建一个空白 NSImage(假图像)
        let size = NSSize(width: 200, height: 200)
        let image = NSImage(size: size)
        
        image.lockFocus()
        NSColor.systemBlue.setFill()
        NSBezierPath.fill(NSRect(origin: .zero, size: size))
        image.unlockFocus()
        
        // 2. 转换为 JPEG 格式的 Data
        guard let tiffData = image.tiffRepresentation,
              let bitmap = NSBitmapImageRep(data: tiffData),
              let jpegData = bitmap.representation(using: .jpeg, properties: [.compressionFactor: 0.8]) else {
            print("转换图片失败")
            return
        }
        
        // 3. 拼接 Downloads 路径
        let downloads = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first!
        let filename = "test-image-\(UUID().uuidString.prefix(6)).jpg"
        let fileURL = downloads.appendingPathComponent(filename)
        
        // 4. 写入文件
        do {
            try jpegData.write(to: fileURL)
            print("成功保存图片到:\(fileURL.path)")
        } catch {
            print("保存失败:\(error)")
        }
    }
var body: some View {
    VStack {
        // 保存图片
        Button("保存图片到Downloads文件夹") {
            saveTestImage()
        }
    }
}

当点击按钮时,会创建图像并尝试保存到Downloads文件夹中。

如果没有开启App Sandbox的Downloads权限,Xcode会提示:

保存失败:Error Domain=NSCocoaErrorDomain Code=513 "你没有将文件“test-image-6A334C.jpg”存储到文件夹“下载”中的权限。" UserInfo={NSFilePath=/Users/fangjunyu/Library/Containers/com.fangjunyu.ImageSlim/Data/Downloads/test-image-6A334C.jpg, NSURL=file:///Users/fangjunyu/Library/Containers/com.fangjunyu.ImageSlim/Data/Downloads/test-image-6A334C.jpg, NSUnderlyingError=0x60000009de90 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
App 启动了:name = NSWorkspaceDidLaunchApplicationNotification, object = Optional(<NSWorkspace: 0x600000ccc0f0>), userInfo = Optional([AnyHashable("NSApplicationProcessSerialNumberHigh"): 0, AnyHashable("NSApplicationBundleIdentifier"): com.microsoft.VSCode, AnyHashable("NSApplicationProcessIdentifier"): 92797, AnyHashable("NSApplicationPath"): /Applications/Visual Studio Code.app, AnyHashable("NSApplicationProcessSerialNumberLow"): 116096689, AnyHashable("NSApplicationName"): Code, AnyHashable("NSWorkspaceApplicationKey"): <NSRunningApplication: 0x6000020d2880 (com.microsoft.VSCode - 92797) LSASN:{hi=0x0;lo=0x6eb7eb1}>])

表示图片保存失败。

如果开启App Sandbox,则会将400px * 400px的图片保存到Downloads文件夹中。

扩展知识

正确访问目录的方式

例如,我们需要访问下载目录的文件,我们可以不开启App Sandbox权限,而是通过用户主动授权的方式访问文件。

import AppKit

Button("选择下载目录") {
    let panel = NSOpenPanel()
    panel.canChooseDirectories = true
    panel.canChooseFiles = false
    panel.directoryURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first
    if panel.runModal() == .OK {
        let selectedURL = panel.url!
        NSWorkspace.shared.open(selectedURL) // 或者记录这个 URL
    }
}

当点击Button后,系统弹出选择框,让用户选择打开的文件。

这也是Apple推荐的方式。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

一条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注