在沙盒应用程序中请求文档权限

问题描述 投票:0回答:1

我正在 SwiftUI 中编写一个 Mac 应用程序,希望显示实时更新的文档和文件夹列表,并且能够编辑文件。

首先,用户使用“打开文件”对话框选择任何文件夹,然后我将 URL 保存到 UserDefaults 中,并在应用程序启动时尝试读取文件和文件夹列表。

假设我有一个有效的 URL,那么我会执行以下操作:

// Open the folder referenced by URL for monitoring only.
monitoredFolderFileDescriptor = open(url.path, O_EVTONLY)

// Define a dispatch source monitoring the folder for additions, deletions, and renamings.
folderMonitorSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: monitoredFolderFileDescriptor, eventMask: .write, queue: folderMonitorQueue)

当我调用

DispatchSource.makeFileSystemObjectSource
并出现
EXC_BREAKPOINT
异常时,应用程序崩溃。

FileManager.default.isReadableFile(atPath: url.path)
返回 false,告诉我我没有访问此文件夹的权限。 URL路径是
/Users/username/Documents/Folder

我已将

NSDocumentsFolderUsageDescription
添加到信息列表中。

目前尚不清楚如何以编程方式请求许可。 理论上,我的 URL 可以指向用户在“打开”对话框中选择的文件系统上的任何文件夹。目前尚不清楚仅在必要时请求许可的最佳做法是什么。我应该解析“文档”或“下载”字符串的 URL 吗? 我也看过这个 WWDC 视频。

感谢您的阅读,这是我想要展示的示例。

App would like to access files in your documents folder permissions dialog

macos io appkit appstore-sandbox
1个回答
4
投票

就像@vadian 所说,这需要安全范围书签。如果您用户从

NSOpenPanel
选择文件夹,则不需要权限对话框。 这个答案对我帮助很大。

我创建了新的

NSOpenPanel
,它给了我
URL?
,我将此 URL 传递给下面的
saveAccess()
函数:

let bookmarksPath = "bookmarksPath"
var bookmarks: [URL: Data] = [:]

func saveAccess(url: URL) {
    do {
        let data = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
        bookmarks[url] = data
        NSKeyedArchiver.archiveRootObject(bookmarks, toFile: bookmarksPath)
    } catch {
        print(error)
    }
}

保存书签后,您可以在应用程序启动时访问。

func getAccess() {
    guard let bookmarks = NSKeyedUnarchiver.unarchiveObject(withFile: bookmarksPath) as? [URL: Data] else {
        print("Nothing here")
        return
    }
    guard let fileURL = bookmarks.first?.key else {
        print("No bookmarks found")
        return
    }
    guard let data = bookmarks.first?.value else {
        print("No data found")
        return
    }
    var isStale = false
    do {
        let newURL = try URL(resolvingBookmarkData: data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
        newURL.startAccessingSecurityScopedResource()
        print("Start access")
    } catch {
        print(error)
        return
    }
}

代码很粗糙,但我希望它可以帮助别人。获取

newURL
后,即可打印文件夹内容。

let files = try FileManager.default.contentsOfDirectory(at: newURL, includingPropertiesForKeys: [.localizedNameKey, .creationDateKey], options: .skipsHiddenFiles)

完成后别忘了打电话给

.stopAccessingSecurityScopedResource()

© www.soinside.com 2019 - 2024. All rights reserved.