我正在沙箱化我的应用程序,并尝试允许导入/导出多个文件,使用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
如上所述,第二步(解析书签)完成,但error
和result
都没有。由于我一直在实施沙盒,我所犯的大部分错误导致返回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,但我希望不会。
答案 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。