Swift中fileImporter获取PDF后无法在PDFKitView加载的问题
问题根源与解决办法
问题出在保存环节,你不该存URL的path字符串,核心原因有两个:
- iOS沙盒的容器路径会在App重启、更新后发生变化,旧的path字符串会直接失效
.fileImporter拿到的URL带有安全访问权限,存path等于丢弃了这个权限,后续用path重建的URL没有访问该文件的权限,自然找不到文件
正确的做法:保存URL的Bookmark数据
Bookmark是苹果提供的用来持久化文件URL权限和路径的机制,既能保留对文件的访问权,还能应对沙盒路径变化的问题。
保存Bookmark的代码示例
// 拿到.fileImporter返回的url后执行保存 func savePDFURL(_ url: URL) { do { // 创建带安全权限的bookmark数据 let bookmarkData = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) // 存到UserDefaults(也可以用Core Data等其他持久化方式) UserDefaults.standard.set(bookmarkData, forKey: "PDFBookmark") } catch { print("保存Bookmark失败:\(error)") } }
加载PDF时还原URL并获取权限
func loadPDFURL() -> URL? { guard let bookmarkData = UserDefaults.standard.data(forKey: "PDFBookmark") else { return nil } var isStale = false do { // 从bookmark还原URL,同时激活安全权限 let url = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) // 如果bookmark过期,重新保存一次 if isStale { let newBookmarkData = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) UserDefaults.standard.set(newBookmarkData, forKey: "PDFBookmark") } // 激活权限,用完要记得关闭 url.startAccessingSecurityScopedResource() return url } catch { print("还原URL失败:\(error)") return nil } }
关键注意事项
- 调用
startAccessingSecurityScopedResource()后,一定要在不再需要访问文件时调用stopAccessingSecurityScopedResource()释放权限 - 如果用户后续修改了文件权限或者删除文件,要做好对应的错误处理逻辑
内容的提问来源于stack exchange,提问作者arroyot24
相关产品推荐
相关产品推荐

