使用UIDocumentPickerViewController访问iCloud时URL异常不可用
iOS UIDocumentPickerController 读取iCloud目录文件异常问题
我开发的iOS应用通过UIDocumentPickerController提供目录选择对话框,多数场景运行正常,但选择iCloud账户目录时,枚举得到的是带.xxx.icloud后缀的占位文件URL,复制到沙盒后内容并非原文件,而是URL格式的占位数据,无法正常使用。
相关代码
初始化UIDocumentPickerController
var documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open) documentPicker.delegate = self sView.present(documentPicker, animated: true, completion: nil)
枚举目录文件
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { (url) in let access = url.startAccessingSecurityScopedResource() var directoryContents: [URL] do { let keys : [URLResourceKey] = [.nameKey, .isDirectoryKey] directoryContents = try FileManager.default.contentsOfDirectory( at: url, includingPropertiesForKeys: keys) } catch { print("error \(error))") if access { url.stopAccessingSecurityScopedResource() } return } if access { url.stopAccessingSecurityScopedResource() } }
文件复制到沙盒
for fromURL in directoryContents { var lastPath = fromURL.lastPathComponent print("Lastpath is \(lastPath)") let toURL: URL = documentURL.appendingPathComponent(lastPath) print("fromURL - \(fromURL)") print("toURL \(toURL)") let fM = FileManager.default if(fM.fileExists(atPath: toURL.path)) { exists += 1 } else { do { let access = url.startAccessingSecurityScopedResource() try fM.copyItem(at: fromURL, to: toURL) if access { url.stopAccessingSecurityScopedResource() } count += 1 } catch { print("Error on file copy \(error)") } } }
异常现象
选择iCloud目录时,输出的URL带有前缀.和后缀.icloud:
fromURL - file:///Users/greg/Library/Developer/CoreSimulator/Devices/FFDED20B-B142-4FC6-BA8F-C1DC193E2AB7/data/Library/Mobile%20Documents/com~apple~CloudDocs/Savvy/SavvyLink/SmallEngineDataRepo/.Flt0002_20180913P.csv.icloud toURL file:///Users/greg/Library/Developer/CoreSimulator/Devices/FFDED20B-B142-4FC6-BA8F-C1DC193E2AB7/data/Containers/Data/Application/167AC69D-494C-4CB1-8A36-E230C5303F30/Documents/.Flt0002_20180913P.csv.icloud
复制到沙盒的文件内容不是原文件,而是指向云端文件的URL格式数据。
解决方案
1. 识别iCloud占位文件并获取真实URL
.xxx.icloud是iCloud Drive的本地占位文件,仅存储元数据,需通过URLResourceKey解析真实文件URL:
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { (coordinatedURL) in let access = coordinatedURL.startAccessingSecurityScopedResource() defer { if access { coordinatedURL.stopAccessingSecurityScopedResource() } } var directoryContents: [URL] do { // 添加iCloud相关资源键 let keys: [URLResourceKey] = [.nameKey, .isDirectoryKey, .isUbiquitousItemKey, .ubiquitousItemURLKey] directoryContents = try FileManager.default.contentsOfDirectory( at: coordinatedURL, includingPropertiesForKeys: keys) // 替换占位文件URL为真实iCloud文件URL directoryContents = directoryContents.compactMap { itemURL in var isUbiquitous: Bool = false try? itemURL.getResourceValue(&isUbiquitous, forKey: .isUbiquitousItemKey) if isUbiquitous { var cloudURL: URL? try? itemURL.getResourceValue(&cloudURL, forKey: .ubiquitousItemURLKey) return cloudURL ?? itemURL } return itemURL } } catch { print("error \(error))") return } }
2. 确保iCloud文件下载完成后再复制
iCloud文件可能未缓存到本地,需触发下载并等待完成:
for fromURL in directoryContents { var lastPath = fromURL.lastPathComponent // 清理占位文件的特殊命名 if lastPath.hasPrefix(".") && lastPath.hasSuffix(".icloud") { lastPath = String(lastPath.dropFirst().dropLast(7)) } let toURL = documentURL.appendingPathComponent(lastPath) let fM = FileManager.default if fM.fileExists(atPath: toURL.path) { exists += 1 } else { do { let access = fromURL.startAccessingSecurityScopedResource() defer { if access { fromURL.stopAccessingSecurityScopedResource() } } // 检查并触发iCloud文件下载 var isUbiquitous: Bool = false try fromURL.getResourceValue(&isUbiquitous, forKey: .isUbiquitousItemKey) if isUbiquitous { try fM.startDownloadingUbiquitousItem(at: fromURL) // 等待下载完成(实际开发建议用异步回调优化) while fM.isUbiquitousItemDownloading(at: fromURL) { Thread.sleep(forTimeInterval: 0.1) } } try fM.copyItem(at: fromURL, to: toURL) count += 1 } catch { print("Error on file copy \(error)") } } }
3. 修正安全作用域资源的使用
安全作用域资源需针对单个文件URL调用startAccessingSecurityScopedResource(),而非目录URL,确保每个文件的访问权限正确。
内容的提问来源于stack exchange,提问作者gregt
相关产品推荐
相关产品推荐

