在基于沙盒的基于NSDocument的应用程序中,无论文档保存在哪里,都可以使用NSOpenPanel访问任何兼容的文档。没有NSOpenPanel,应用程序只能访问沙箱容器中的文件。
由于我的应用程序管理两种类型的子类NSdocument(文本作为读取器/编写器,图像仅作为读取器),因此我尝试为图像实现单独的“打开最近”菜单。当用户打开它们时,我禁用了它们的常规行为,覆盖了NSDocumentController的noteNewRecentDocumentURL: (NSURL *)url
方法,以为图像URL返回NO。这样,只有文本文档会出现在普通的“文件”->“打开最近的文档”菜单中(并在用户选择它们时正常打开)。图片在自定义菜单中列出。
这些图像URL出现问题,因为应用程序被沙箱化:应用程序无法直接打开专用菜单中列出的任何图像文件(任何读取操作均会返回-54错误。可以使用以下方式检查此行为:
[[NSFileManager defaultManager] isReadableFileAtPath:[fileURL path]]
在这种情况下总是返回FALSE
。唯一的例外是:当我重新打开时,从专用的“打开最近的”菜单中,先前已在同一应用程序会话中使用NSOpenPanel打开了一个文件,然后将其关闭:在这种情况下,isReadableFileAtPath:
返回{{1 }},可以访问该文件。但是当应用程序退出并重新启动时,无法以这种方式访问最近的图像文件。
我找到了解决此问题的解决方案:
一旦用户通过NSOpenPanel“合法”访问了图像文件,便将其移动到沙箱容器中。当然,它可以工作,但是会阻止用户自行决定文件的位置!同样,在沙箱中复制文件也不是解决方案。
在沙箱中为这些文件创建别名。由于找不到方法,因此无法测试这是否是解决方案。
禁用应用程序沙箱。但这是最糟糕的解决方案,因为使用沙箱的原因很多!
是否有第四个解决方案,该解决方案将授权对任何映像文件(无论位于何处)进行只读访问,而不会禁用沙箱?
答案 0 :(得分:1)
无论如何都无法访问任何文件。
我也不知道您的第二个解决方案意味着什么,这可能就是您无法遵循它的原因。您可能想要引用“安全范围内的书签”,而不是“别名”,它们工作得很好,这是您应该遵循的路径。
答案 1 :(得分:1)
伊万的建议很好。经过几读(不到一个小时),我可以实现那些安全范围内的书签。对于感兴趣的人,这是主要发现。
将该功能添加到沙盒应用程序的授权文件中 将com.apple.security.files.bookmarks.document-scope(或com.apple.security.files.bookmarks.app-scope或两者)设置为TRUE。
修改文档打开方法(称为NSOpenPanel),如下所示:
-(void) openMyDocument:(id)sender{
// ... do your stuff
[self.panel beginWithCompletionHandler:^(NSInteger result) {
if (result == NSModalResponseOK) {
NSURL* selectedURL = [[self.panel URLs] objectAtIndex:0];
NSData *bookmark = nil;
NSError *error = nil;
bookmark = [selectedURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil // Make it app-scoped
error:&error];
if (error) {
NSLog(@"Error while creating bookmark for URL (%@): %@", selectedURL, error);
}
NSString *access = [NSString stringWithFormat:@"%@%@", @"Access:", [selectedURL path]];
[[NSUserDefaults standardUserDefaults] setObject:bookmark forKey:access];
[[NSUserDefaults standardUserDefaults] synchronize];
// ... then open the document your way
}
}
}
- (void) openDocumentForScopedURL: (NSURL *) fileURL
NSString *accessKey = [NSString stringWithFormat:@"%@%@", @"Access:", [fileURL path]];
NSData *bookmarkData = [[NSUserDefaults standardUserDefaults] objectForKey:accessKey];
NSURL *bookmarkFileURL = nil;
if (bookmarkData == nil){
// no secured-scoped bookmark found, alert the user
return;
} else {
NSError *error = nil;
BOOL bookmarkDataIsStale;
bookmarkFileURL = [NSURL
URLByResolvingBookmarkData:bookmarkData
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:nil
bookmarkDataIsStale:&bookmarkDataIsStale
error:&error];
[bookmarkFileURL startAccessingSecurityScopedResource];
}
// ... Then open your file, using bookmarkFileURL
// ... and do your stuff
// IMPORTANT. You must notify that stopped to access
[bookmarkFileURL stopAccessingSecurityScopedResource];
}