MacOS沙盒应用程序:在没有NSOpenPanel的情况下访问文件 [英] MacOS sandboxed application: access files without NSOpenPanel

查看:357
本文介绍了MacOS沙盒应用程序:在没有NSOpenPanel的情况下访问文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在基于沙盒的基于NSDocument的应用程序中,无论文档保存在哪里,都可以使用NSOpenPanel访问任何兼容的文档.如果没有NSOpenPanel,应用程序只能访问沙箱容器中的文件.

In a sandboxed NSDocument-based application, any compatible document can be accessed using the NSOpenPanel, no matter where the document is saved. Without NSOpenPanel, the application can only access files in the sandbox container.

由于我的应用程序管理两种类型的子类NSdocument(文本作为读取器/编写器,图像仅作为读取器),因此我尝试为图像实现单独的打开最近"菜单.当用户打开它们时,我禁用了它们的常规行为,覆盖了NSDocumentController的noteNewRecentDocumentURL: (NSURL *)url方法,以为图像URL返回NO.这样,只有文本文档会出现在普通的文件"->打开最近的文件"菜单中(并在用户选择它们时正常打开).图片在自定义菜单中列出.

As my application manages two types of subclassed NSdocument (Text as a reader/writer and Image as a reader only), I try to implement a separate "Open Recent" menu for images. I disabled the the ordinary behaviour for them as they are opened by the user, overriding the noteNewRecentDocumentURL: (NSURL *)url method of the NSDocumentController to return NO for image urls. So that only the text documents appear in the ordinary File -> Open Recent menu (and open normally when user select them). Images are listed in a custom menu.

这些图像URL出现问题,因为该应用程序已被沙箱化:该应用程序无法直接打开专用菜单中列出的任何图像文件(任何读取操作均返回-54错误.可以使用以下方式检查此行为:

The problem occurs with these image urls, because the application is sandboxed: the application cannot open directly any image file listed in the dedicated menu (any reading operation returns a -54 error. This behaviour can be checked using:

[[NSFileManager defaultManager] isReadableFileAtPath:[fileURL path]]

在这种情况下总是返回FALSE.唯一的例外是:当我重新打开时,从专用的打开最近的"菜单中,先前已在同一应用程序会话中使用NSOpenPanel打开了一个文件,然后将其关闭:在这种情况下,isReadableFileAtPath:返回TRUE,并且可以访问文件.但是当应用程序退出并重新启动时,无法以这种方式访问​​最近的图像文件.

which always returns FALSE in this situation. There is only one exception to that: when I reopen, from the dedicated Open Recent menu, a file that has been previously opened with the NSOpenPanel in the same application session, then closed: in this case isReadableFileAtPath: returns TRUE and the file can be accessed. But when application quits and restarts, recent images files cannot be accessed this way.

我找到了解决此问题的解决方案:

I identified thre solutions to deal with this problem:

  1. 用户通过"NSOpenPanel"以合法方式对其进行访问后,便立即将图像文件移动到沙箱容器中.当然,它可以工作,但是会阻止用户自行决定文件的位置!同样,在沙箱中复制文件也不是解决方案.

  1. Moving the image file in the sandbox container as soon as it has been accessed "legally" by the user, through the NSOpenPanel. It works, of course, but prevent the user from deciding on his own the location of his files! In the same way, duplicating the file in the sandbox is not a solution.

在沙箱中为这些文件创建别名.由于找不到方法,因此无法测试这是否是解决方案.

Creating an alias to these files in the sandbox. As I couldn't find a way to do this, I couldn't test whether this is a solution or not.

禁用应用程序沙箱.但这是最糟糕的解决方案,因为使用沙箱的原因很多!

Disable the application sandboxing. But this is the worse solution as there are many reasons to use sandboxing!

是否有第4个解决方案,该解决方案将授权对任何图像文件(无论位于何处)进行只读访问,而不会禁用沙箱?

Is there a 4th solution, which would authorize a read-only access to any image file, wherever it is located, without disabling the sandbox?

推荐答案

Ivan的建议很好.经过几读(不到一个小时),我可以实现那些安全范围内的书签.对于感兴趣的人,这是主要发现.

Well Ivan's suggestion was excellent. After a few readings (less than an hour), I could implement those security-scoped bookmark. For interested people, here are the main findings.

  1. 将该功能添加到沙盒应用程序的权利文件中 将com.apple.security.files.bookmarks.document-scope(或com.apple.security.files.bookmarks.app-scope或两者)设置为TRUE.

  1. add the feature to your sandboxed application's entitlement file set the com.apple.security.files.bookmarks.document-scope (or the com.apple.security.files.bookmarks.app-scope, or both) key to TRUE.

像这样修改文档打开方法(称为NSOpenPanel):

Modify your document opening method (which calls the NSOpenPanel) like this:

-(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
        }
    }
}

  1. 修改您创建的无需使用NSOpenPanel即可读取文件的方法

- (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];            
}

这篇关于MacOS沙盒应用程序:在没有NSOpenPanel的情况下访问文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆