如何解决捕获从磁盘读取文件时出错 - 您没有权限
我在 AppDel 中使用以下代码。当用户点击 gpx 文件或使用共享选项与我的应用程序共享文件时触发。在这一点上,是用户指定他们允许我的应用程序访问该文件,所以我对为什么这仍然被拒绝感到有些困惑。非常感谢任何建议。
func application(_ app: UIApplication,open url: URL,options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
if let dir = FileManager.default.urls(for: .documentDirectory,in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(url.lastPathComponent)
if FileManager.default.fileExists(atPath: fileURL.path) {
print("File already exists")
}
else {
do {
try FileManager.default.copyItem(at: url,to: fileURL)
print("Did write file to disk")
}
catch {
dispatchQueue.main.async(){
print("Catch error writing file to disk: \(error)")
}
}
}
}
return true
}
错误打印到控制台如下:
Error Domain=NSCocoaErrorDomain Code=257 "文件 “Beech_Hill_Long_Route.gpx”无法打开,因为您没有 允许查看它。” UserInfo={NSFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/Desktop/Beech_Hill_Long_Route.gpx,NSUnderlyingError=0x282c19a70 {错误域=NSPOSIXErrorDomain 代码=1 “不允许操作”}}
解决方法
我不太了解它在 iOS 上的确切工作原理,但我对它在 macOS 上的工作原理有一些了解,两者应该相似。对于 macOS 沙盒应用,用户必须专门通过 NSOpenPanel
或 NSSavePanel
选择沙盒外的文件。 iOS 上的等效项是 UIDocumentPickerViewController
,但我认为显式共享也可以。在此基础上,如果我遇到您的问题,我会如何考虑它以及我会尝试什么:
您有两个 URL
参与了您对 FileManager.default.copy()
的调用。不清楚是哪个产生了错误,所以我会考虑两者。
首先让我们看看fileURL
。您正在构建它以将文件放入用户的 Documents
目录中。至少在 macOS 上,该目录不在应用程序的沙箱中,这意味着通过 NSSavePanel
询问用户(这也意味着他们可能决定将其放在其他地方)。您可能必须执行 UIKit
等效操作,或者只是确保您选择的位置位于您的沙箱中。
要测试它,而不是进行复制,请尝试写入 fileURL
以仅隔离那个。例如:
do { try "TestString".data(using: .utf8)?.write(url: fileURL) }
catch { print("Write failed: \(error.localizedDescription)") }
如果失败,那么您的问题在于 fileURL
,在这种情况下,您可能需要使用 UIDocumentPickerViewController
来保存它,或者选择一个绝对位于应用沙箱中的位置。
如果测试成功,问题一定出在传入的 URL
。
我将假设 url
已经在安全范围内,因为我不确定否则共享将如何工作。我认为最有可能在幕后发生的是,当用户与您的应用共享 URL
时,iOS 从 URL
创建一个安全范围的书签并发送书签而不是 {{1} }} 到您的应用程序。然后在您的应用程序结束时,该书签用于在将 URL
传递给您的应用程序的委托之前重构它。如果我是对的,您需要打开和关闭安全范围才能使用它:
URL
请注意,url.startAccessingSecurityScopedResource()
// access your file here
url.stopAccessingSecurityScopedResource()
必须在主线程上调用,因此如果您的代码是异步发生的,则需要安排它在那里运行:
stopAccessingSecurityScopeResource()
如果您需要保存 url.startAccessingSecurityScopedResource()
// access your file here
DispatchQueue.main.async { url.stopAccessingSecurityScopedResource() }
本身以供将来运行您的程序时使用...您不能。嗯,你可以,但它不会是有效的,所以你会马上回到权限错误。相反,您必须保存一个书签,然后在以后的运行中,从书签中重建 URL
。
URL
let bookmark = try url.bookmarkData(
options: .withSecurityScope,includingResourceValuesForKeys: nil,relativeTo: nil
)
是 bookmark
的一个实例,因此您可以将其写入 Data
或您想要保存的任何位置。稍后从它获取 UserDefaults
:
URL
注意,如果初始化返回后var isStale = false
let url = try URL(
resolvingBookmarkData: bookmark,options: .withSecurityScope,relativeTo: nil,bookmarkDataIsStale: &isStale
)
if isStale
{
let newBookmark = try url.bookmarkData(
options: .withSecurityScope,relativeTo: nil
)
// Save the new bookmark
}
为isStale
,则需要重新制作并重新保存书签。
很遗憾我们必须经历这么多麻烦,但我们生活在一个有些人坚持对其他人的设备和数据做坏事的世界中,因此我们必须处理这些问题以保护用户免受恶意数据泄露。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。