无法访问/导入在iOS 11文档浏览器中选择的iCloud文件的内容



除了打开和保存自己的自定义文档外,我的iOS 11文档基于浏览器的应用程序应该能够导入适当格式的文本文件并将其转换为自己的文档。

但是,在文稿浏览器中选取文本文件时,仅当所选文件位于本地储存中时,App 才能访问其内容(然后执行转换),但当文件储存在 iCloud 中时,无法访问内容。

下面提供了我用于documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL])委托方法的代码的简化注释版本:

func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {
guard let sourceURL = documentURLs.first else { return }
// Check extension to verify if it is a custom document
if sourceURL.pathExtension == "mydoc" {
// If it is a custom document, we present it directly
// (the presentDocument method is a standard implementation from Apple docs)
presentDocument(at: sourceURL)
} else {
// Otherwise, we suppose the file is a text file to be imported
// We first create a new document, then try to import the contents of the text file     
let url = FileManager().temporaryDirectory.appendingPathComponent("New Document").appendingPathExtension("mydoc")
let doc = MyDocument(fileURL: url)
do {
let textFileContents = try String(contentsOf: sourceURL)
// It works fine if the text file is in local storage
// Here the document model is updated by converting the contents of the text file 
// (code omitted, it is actually a method in the MyDocument class)
// ...
} catch {
// Produce error message: cannot access text file
// The error message is always produced if the text file is in iCloud storage!
}
// Save and close the document with standard code, e.g.:               
doc.save(to: url, for: .forCreating) { (saveSuccess) in
guard saveSuccess else { return }
doc.close(completionHandler: { (closeSuccess) in
guard closeSuccess else { return }  
})
// Reveal and import the document
self.revealDocument(at: url, importIfNeeded: true) { (revealedDocumentURL, error) in
if let error = error {
// Handle the error appropriately
return
}
// Present the Document View Controller for the revealed URL
self.presentDocument(at: revealedDocumentURL!)
}
}
}

info.plist 文件将自定义文档和 public.text 声明为文档类型(具有相应的角色和处理程序等级),将自定义文档声明为导出的 UTI。如果选择的文件是自定义文档,则无论文件是本地文件还是在iCloud中,一切正常。

由于导入工作是在文件位于本地存储中时工作的,我认为这可能是iCloud权限的问题,即使Apple文档的状态为UIDocumentBrowserViewController

系统会自动为您处理对 iCloud 的访问;您不会 需要启用应用的 iCloud 功能。

但是,尝试将iCloud功能添加到我的应用程序的权利中并没有解决问题(实际上使情况变得更糟,从某种意义上说,完全相同的代码现在将新创建的文档保存在应用程序的默认iCloud容器中,这与文档浏览器使用的iCloud驱动器位置不同,因此所有文档对浏览器都变得"不可见" - 但我跑题了......

另一个"有趣"的元素是,我还在应用程序中实现了一个UIDocumentPickerViewController,将其他内容从文本文件导入到已经打开的自定义文档中。我使用的代码与上面基本相同...它可以完美运行,无论文本文件是在本地存储中还是在iCloud中!这可能会强化问题与UIDocumentBrowserViewController的特定权限问题有关的观点。

那么,总而言之:我该怎么做才能访问存储在iCloud中的文本文件的内容并将其转换为我的应用程序的自定义文档?提前感谢您的任何建议(如果问题的表述有问题,请保持温和 - 这是我潜伏数月后的第一个堆栈溢出问题!

我不是 100% 确定,但我相信您需要在该 URL 上调用startAccessingSecurityScopedResource才能使用文档浏览器提供给您的沙盒扩展。完成后不要忘记调用stopAccessing,以免泄漏内核资源。另外,如果您没有真正编辑该文档,您可能正在寻找UIDocumentPickerViewController?用户打开一个文件然后最终编辑另一个文件很奇怪。启动一个新文档,然后使用选取器将文本文件导入其中不是更好的用户体验吗?

小的插入片段:(Swift 5.x)

public func documentBrowser(_ controller: UIDocumentBrowserViewController,
didPickDocumentsAt documentURLs: [URL]) {
dismiss(animated: true, completion: nil)
self.importAll(urls: documentURLs)
}

final func importAll(urls: [URL]) {
//TODO: use timer/loop/async stuff..
// for multiple files..
urls.forEach { (url: URL) in
let secured = url.startAccessingSecurityScopedResource()
= myImportInSessionFrom(url: url)
if secured { url.stopAccessingSecurityScopedResource() }
}
}

相关内容

  • 没有找到相关文章

最新更新