从安全范围书签解析NSURL时,如果用户重命名或移动了该文件或文件夹,则书签将过时.Apple的文档说明了陈旧性:
isStale
返回时,如果是,则书签数据是陈旧的.您的应用应使用返回的URL创建新书签,并使用它代替现有书签的任何存储副本.
不幸的是,这对我很少有用.它有可能在5%的时间内工作.尝试使用返回的URL创建新书签会导致错误,代码256,并且在控制台中查看会显示来自sandboxd的消息,说明在更新的URL上拒绝文件读取数据.
注意如果重新生成书签确实有效,它似乎只在第一次重新生成时才起作用.如果再次移动/重命名文件夹/文件似乎永远不会工作.
我最初如何创建和存储书签
-(IBAction)bookmarkFolder:(id)sender {
_openPanel = [NSOpenPanel openPanel];
_openPanel.canChooseFiles = NO;
_openPanel.canChooseDirectories = YES;
_openPanel.canCreateDirectories = YES;
[_openPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
if (_openPanel.URL != nil) {
NSError *error;
NSData *bookmark = [_openPanel.URL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
if (error != nil) {
NSLog(@"Error bookmarking selected URL: %@", error);
return;
}
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:bookmark forKey:@"bookmark"];
}
}];
}
Run Code Online (Sandbox Code Playgroud)
解析书签的代码
-(void)resolveStoredBookmark {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSData *bookmark = [userDefaults …
Run Code Online (Sandbox Code Playgroud) 我正在制作一个沙盒 Mac 应用程序,我使用 NSOpenPanel 获取文件 URL,并将其保存到 UserDefaults 作为安全范围的书签。当我退出并重新启动应用程序时,我可以再次将数据块解析为 URL。
文档说我应该调用startAccessingSecurityScopedResource()
,并检查它的返回值。(true
当我调用它时确实会返回。)但是如果我不调用它,我仍然有一个已解析的 URL,而且我似乎仍然有权访问它。
什么是startAccessingSecurityScopedResource()
真正做到?如果我不打电话,有什么不好的事情会发生吗?
我正在创建一个 TodayWidget 应用程序扩展,它显示有关用户在应用程序目录之外选择的文件夹的信息。
在我的主应用程序中,我可以通过 NSOpenPanel 使用 powerbox 来选择文件夹。然后,我可以将安全范围书签保存到我的 TodayWidget 可访问的应用程序组容器的用户默认值。
TodayWidget 可以读取书签数据,但是当它调用URLByResolvingBookmarkData 时,它会出错:
The file couldn’t be opened because it isn’t in the correct format.
我的主应用程序和 TodayWidget 都具有以下权利:
根据 Apple 的文档,只有创建安全范围书签的应用程序才能使用它。我猜这些意味着不允许嵌入式应用程序?
我已经考虑使用 XPC,但这并不能真正解决问题,因为 XPC 也不能使用安全范围的书签,只能使用普通书签。一旦计算机重新启动,XPC 进程将失去对目录的访问权限。
我真正需要的只是一种让 XPC 进程获得对用户指定目录的读取访问权限的方法。有没有办法不必每次重新启动计算机都重新启动我的主应用程序?
我正在构建一个允许用户编辑文件的 MacOS 应用程序。为了访问文件,我使用了一个安全范围的书签,如下所示:
do {
self.securityScopedBookmark = try asset?.url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
} catch {
print("failed bookmark. error info: \(error)")
}
Run Code Online (Sandbox Code Playgroud)
当用户完成并且 NSDocument 被取消初始化时,我停止访问书签,如下所示:
deinit {
if let securityScopedBookmark = self.securityScopedBookmark {
do {
var isStale: Bool = false
let url = try URL.init(resolvingBookmarkData: securityScopedBookmark, options: [.withoutUI, .withSecurityScope], relativeTo: nil, bookmarkDataIsStale: &isStale)
url.stopAccessingSecurityScopedResource()
} catch let error as NSError {
print("Bookmark Access Fails: \(error.description)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当尝试调用 .stopAccessingSecurityScopedBookmark() 时,我收到了几个日志错误。
[scoped] handle 0: sandbox_extension_release error [22: Invalid argument] …
Run Code Online (Sandbox Code Playgroud) macos sandbox entitlements appstore-sandbox security-scoped-bookmarks
我在应用程序启动之间为文件夹“重用”安全范围 URL 书签时遇到问题(在 Mojave 和 Catalina 上)。
这是使用libarchive
框架的简单解压缩应用程序。用户选择要解压缩的文件,我想为它的父文件夹(例如 ~/Desktop)存储 URL 书签,并在用户下次尝试在同一文件夹中解压缩文件时重新使用它。
首先,我在我的应用程序的权利文件中添加了以下内容:
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
Run Code Online (Sandbox Code Playgroud)
第一次访问文件(分别为父文件夹)时:
NSOpenPanel
以获取对文件夹的访问权限:let directoryURL = fileURL.deletingLastPathComponent()
let openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.prompt = "Grant Access"
openPanel.directoryURL = directoryURL
openPanel.begin { [weak self] result in
guard let self = self else { return }
// WARNING: It's absolutely necessary to access NSOpenPanel.url property to get access
guard …
Run Code Online (Sandbox Code Playgroud) 编辑:在底部添加的其他信息
我有一个基于文档的沙盒应用程序,该程序将用户选择的QuickTime影片加载到AVPlayer中,并且一切运行正常。
现在,我正在升级代码,以便它将使用Security Scoped书签来获取URL,而不仅仅是存储URL字符串,以便持久存储将允许在重新启动应用程序时加载影片。创建书签后,它将存储在托管对象的Data变量中。
由于某些原因,这破坏了AVPlayer。虽然我已经从用户选择的URL创建了书签,并且可以在重新启动应用程序时从书签中解析URL,但是电影无法正确地加载到AVPlayer中,我不知道为什么...我已经确认从书签解析的URL确实指向电影文件。
我还为项目添加了适当的权利。
这是我的代码:
用户选择要加载的电影并创建书签的功能
@IBAction func loadMovie(_ sender: Any) {
let openPanel = NSOpenPanel()
openPanel.title = "Select Video File To Import"
openPanel.allowedFileTypes = ["mov", "avi", "mp4"]
openPanel.begin { (result: NSApplication.ModalResponse) -> Void in
if result == NSApplication.ModalResponse.OK {
self.movieURL = openPanel.url
self.player = AVPlayer.init(url: self.movieURL!)
self.setupMovie()
if self.loadedMovieDatabase.count > 0 {
print("Movie Object Exists. Adding URL String")
self.loadedMovieDatabase[0].urlString = String(describing: self.movieURL!)
} else {
print("No Movie Object Exists Yet. Creating one and adding URL String")
let …
Run Code Online (Sandbox Code Playgroud) 我有一个 iOS 应用程序,我正在尝试使用 UserDefaults 保留并重新加载书签数据。似乎工作正常,但我遇到一个问题,有时从书签数据到 URL 的转换失败。它似乎在一段时间内工作正常(甚至在应用程序终止和重新启动等情况下),但最终书签数据将失败(可能在几个小时后?)。
\n\n因此,在解析书签数据时,如下所示:
\n\nlet url = try URL(resolvingBookmarkData: data, bookmarkDataIsStale: &isStale)
抛出捕获的异常并附带描述:Error Domain=NSCocoaErrorDomain Code=4 "The file doesn\xe2\x80\x99t exist."
我将书签作为数据存储在 UserDefaults 中。我简单地使用以下内容创建书签数据:
\n\nlet bookmarkData = try url.bookmarkData(options: .minimalBookmark)
有趣的是,如果我再次从文档选择器中手动选择相同的文件,则存储在 UserDefaults 中的原始书签将再次可访问。
\n\n我已经审查了 GitHub 中的开源代码,没有发现我的实现与其他实现有任何本质上的不同。寻找有关可能导致此问题的原因的任何提示或想法。
\nmacos ×4
nsurl ×3
swift ×3
cocoa ×2
avplayer ×1
entitlements ×1
foundation ×1
ios ×1
sandbox ×1
xpc ×1