1

应用沙盒设计指南说:

App Sandbox 的相关项目功能允许您的应用访问与用户选择的文件同名但扩展名不同的文件。此功能由两部分组成:应用程序的 Info.plist 文件中的相关扩展列表和告诉沙箱您在做什么的代码。

我的 Info.plist 定义了文件的文档类型.pnd(用户选择的文件),以及文件的文档类型.bak。文件的条目.bak除其他属性外,还具有属性NSIsRelatedItemType = YES

当用户编写 .pnd 文件的新版本时,我正在尝试使用相关项将现有文件移动到备份文件(将 .pnd 后缀更改为 .bak 后缀)。该应用程序是沙盒的。我不精通沙盒。

PasteurOrgManager用作NSFilePresenter原始文件和备份文件的类:

@interface PasteurOrgData : NSObject <NSFilePresenter>
. . . .
@property (readonly, copy) NSURL *primaryPresentedItemURL;
@property (readonly, copy) NSURL *presentedItemURL;
@property (readwrite) NSOperationQueue *presentedItemOperationQueue;
@property (readwrite) NSFileCoordinator *fileCoordinator;
. . . .
- (void) doBackupOf: (NSString*) path;
. . . .
@end

doBackupOf:方法如下。请注意,它还设置了NSFilePresenter属性:

- (void) doBackupOf: (NSString*) path
{
    NSError *error = nil;
    NSString *appSuffix = @".pnd";

    NSURL *const pathAsURL = [NSURL URLWithString: [NSString stringWithFormat: @"file://%@", path]];
    NSString *const baseName = [pathAsURL lastPathComponent];
    NSString *const prefixToBasename = [path substringToIndex: [path length] - [baseName length] - 1];
    NSString *const baseNameWithoutExtension = [baseName substringToIndex: [baseName length] - [appSuffix length]];
    NSString *backupPath = [NSString stringWithFormat: @"%@/%@.bak", prefixToBasename, baseNameWithoutExtension];
    NSURL *const backupURL = [NSURL URLWithString: [NSString stringWithFormat: @"file://%@", backupPath]];

    // Move backup to trash — I am sure this will be my next challenge
    // (it's a no-op now because there is no pre-existing .bak file)
    [[NSFileManager defaultManager] trashItemAtURL: backupURL
                                  resultingItemURL: nil
                                             error: &error];

    // Move file to backup
    primaryPresentedItemURL = pathAsURL;
    presentedItemURL = backupURL;
    presentedItemOperationQueue = [NSOperationQueue mainQueue];

    [NSFileCoordinator addFilePresenter: self];
    fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter: self];   // error here
    [self backupItemWithCoordinationFrom: pathAsURL
                                      to: backupURL];
    [NSFileCoordinator removeFilePresenter: self];
    fileCoordinator = nil;
}

backupItemWithCoordinationFrom:方法完成繁重的工作,基本上:

[fileCoordinator coordinateWritingItemAtURL: from
                                    options: NSFileCoordinatorWritingForMoving
                                      error: &error
                                 byAccessor: ^(NSURL *oldURL) {
                                     [self.fileCoordinator itemAtURL: oldURL willMoveToURL: to];
                                     [[NSFileManager defaultManager] moveItemAtURL: oldURL
                                                                             toURL: to
                                                                             error: &error];
                                     [self.fileCoordinator itemAtURL: oldURL didMoveToURL: to];
                                 }

但代码并没有那么远。我已经跟踪了代码,并且 URL 变量符合我的预期,并且是合理的。在上面代码中的“此处错误”处,我分配了 File Presenter,我得到:

NSFileSandboxingRequestRelatedItemExtension: an error was received from pboxd instead of a token. Domain: NSPOSIXErrorDomain, code: 1
[presenter] +[NSFileCoordinator addFilePresenter:] could not get a sandbox extension. primaryPresentedItemURL: file:///Users/cope/Me.pnd, presentedItemURL: file:///Users/cope/Me.bak

任何帮助表示赞赏。

(我已经阅读了相关的帖子Where can a sandboxed Mac app save files?以及为什么 NSFilePresenter 协议方法永远不会被调用?。我注意到其他几个似乎与此问题无关的沙盒相关帖子。)

MacBook Pro、MacOS 10.13.5、XCode 版本 9.3 (9E145)

4

1 回答 1

0

不要阅读太多关于避免沙盒的内容。大多数解释都离最明显的问题太远了。他们没有解释正确触发沙盒的陷阱,而是主要解释了如何完全避免沙盒。这不是一个解决方案 - 它是一个线程!

因此,最明显的问题是将 URL 暴露给粘贴板,在转换为NSURL.

所以你以“file://”NSString开头应该使用类似..

NSString *encodeStringForURL = [yourstring stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

在你转变为NSURLwith之前

NSURL *fileurl = [NSURL URLWithString:encodeStringForURL];
NString *output = fileurl.absoluteString;
于 2021-06-06T19:09:39.250 回答