App Sandbox:文档范围的书签无法解析;没有返回任何错误

时间:2012-04-21 14:17:56

标签: objective-c macos cocoa osx-lion appstore-sandbox

我正在沙箱化我的应用程序,并尝试允许导入/导出多个文件,使用XML文件来引用它们。为了允许我的应用程序(或其他沙盒应用程序)访问XML中列出的文件,我还包括一个序列化的安全范围书签。我正按照this answer中的描述对其进行序列化,我的单元测试(沙盒化)会毫无问题地写入和读取XML数据。当我的应用程序解析书签时,返回的NSURL为nil,NSError引用也是如此。既然我不相信应该是这样的话,为什么会这样呢?我可以通过提示用户选择带有NSOpenPanel的文件/目录来解决这个问题,但我仍然希望书签能够正常工作。

在测试项目中重现

要在家中重现,请在Xcode中创建一个新的Cocoa应用程序,并对项目中的文件使用以下Gist:https://gist.github.com/2582589使用正确的下一个视图循环更新

然后,按照Apple's instructions对项目进行代码签名。您通过按顺序单击按钮重现问题(我作为rdar://11369377提交给Apple)。您选择磁盘上的任何文件(在应用程序的容器外),然后选择要导出的XML,然后导入相同的XML。

希望你们能够帮助我弄清楚我做错了什么。要么我做错了,框架错误地保留了自己,要么我做得对,它完全被打破了。我尽量不去blame the framework,这是什么?还是有另一种可能吗?

示例代码

将XML导出到docURL

// After the user picks an XML (docURL) destination with NSSavePanel

[targetURL startAccessingSecurityScopedResource];
NSData *bookmark = [targetURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                       includingResourceValuesForKeys:nil
                                        relativeToURL:docURL
                                                error:&error];
[targetURL stopAccessingSecurityScopedResource];

docURL导入XML:

// After the user selected the XML (docURL) from an NSOpenPanel

NSURL *result = [NSURL URLByResolvingBookmarkData:bookmarkData
                                          options:NSURLBookmarkResolutionWithSecurityScope
                                    relativeToURL:docURL
                              bookmarkDataIsStale:nil
                                            error:&error];

我尝试使用[docURL ..AccessingSecurityScopedResource]围绕此调用,这没有任何区别(正如预期的那样,因为在开放面板中选择了docURL已经在范围内

另外,我在app.entitlements文件中指定了以下内容:

com.apple.security.files.user-selected.read-write
com.apple.security.files.bookmarks.app-scope
com.apple.security.files.bookmarks.collection-scope

如上所述,第二步(解析书签)完成,但errorresult都没有。由于我一直在实施沙盒,我所犯的大部分错误导致返回NSError,这有助于我解决这个问题。但现在没有错误,也没有解析URL。

其他问题排查步骤

  • 我尝试将XML文件放入我的应用程序的沙箱中,这没有什么区别,因此访问XML文件不是问题

  • 该应用程序使用ARC,但单元测试成功。我尝试使用alloc / init而不是autoreleased类方法(以防万一)

  • 我在创建书签后立即粘贴了网址解析代码,运行正常,产生了一个安全范围的网址

  • 我在最初创建的书签(序列化之前)上做了po,然后在反序列化之后在书签上做了bookmarkDataIsStale:,它们匹配100%。序列化不是问题

  • 我用CFURLCreateByResolvingBookmarkData(..)替换了分辨率调用,没有任何变化。如果它是一个错误,它存在于Core Foundation API以及Cocoa层

  • 指定0的值无效

  • 如果我为options:指定NSURL.h,那么我 执行 会获得有效的NSURL,但它没有安全范围,因此后续调用读取文件仍然失败

    换句话说,反序列化的书签似乎确实有效。如果书签数据已损坏,我怀疑NSURL能够用它做任何事情

  • {{1}}没有任何有用的评论来指出我做错了什么

是否有其他人在沙盒应用程序中使用安全范围的文档书签成功了?如果是这样,你做的与我不同的是什么?

操作系统版本请求

有权访问Mountain Lion测试版的用户是否可以验证我的示例项目是否显示相同(缺少)错误?如果这是在Lion之后修复的错误,我不会担心它。我还没有进入开发者计划,所以没有访问权限。我不确定回答这个问题是否违反了NDA,但我希望不会。

1 个答案:

答案 0 :(得分:6)

在您的Gist代码中,更改AppDelegate.m中的以下行(第61行):

[xmlTextFileData writeToURL:savePanel.URL atomically:YES];

[xmlTextFileData writeToURL:savePanel.URL atomically:NO];

您的代码将有效。

原因可能与调用[anURL bookmarkDataWithOptions]之前需要包含文档范围书签的现有(但空)文件的原因相同:创建NSData实例时,ScopedBookmarkAgent添加该文件的某些内容(如标记,可能是扩展文件属性)。

如果您以原子方式将数据(即书签URL)写入该文件,实际上它们不是直接写入文件,而是首先写入在写入操作成功时重命名的临时文件。似乎已经添加到包含书签的(空的,但是现有的)文件的标记在写入临时文件然后重命名它(从而可能删除原始的空文件)的过程中丢失了

顺便说一下:在将相应的URL传递给包含文档范围书签的xml文件之前,不必创建应用程序范围的书签。

另外:com.apple.security.files.bookmarks.collection-scope已在10.7.4中重命名为com.apple.security.files.bookmarks.document-scope。