Swift IOS - 在设备上测试时如何获得上传文档的权限?
Swift IOS - How can I obtain permission to upload a document when testing on a device?
我正在将 documentPicker 集成到我的 IOS 应用程序中。所选文件将使用 Firebase 存储上传。在 iPhone:
上测试应用程序时尝试上传文件时出现此错误
Error uploading file: The file “file.pdf” couldn’t be opened because you don’t have permission to view it.
另一方面,在使用模拟器进行测试时我没有收到此错误或任何其他错误,并且无论我 select 来自 iCloud 还是本地存储的文件都会发生错误。
这是选择器的代码:
struct DocumentPicker: UIViewControllerRepresentable {
@Binding var filePath: URL?
func makeCoordinator() -> DocumentPicker.Coordinator {
return DocumentPicker.Coordinator(parent1: self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController {
let picker = UIDocumentPickerViewController(documentTypes: ["public.item"], in: .open)
picker.allowsMultipleSelection = false
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: DocumentPicker.UIViewControllerType, context: UIViewControllerRepresentableContext<DocumentPicker>) {
}
class Coordinator: NSObject, UIDocumentPickerDelegate {
var parent: DocumentPicker
init(parent1: DocumentPicker){
parent = parent1
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
// Here is where I get the path for the file to be uploaded
parent.filePath = urls[0]
print(urls[0].absoluteString)
}
}
}
这里是上传函数,报错的地方:
do {
let fileName = (PickedDocument?.lastPathComponent)!
let fileData = try Data(contentsOf: PickedDocument!)
let StorageRef = Storage.storage().reference().child(uid + "/" + doc.documentID + "/" + fileName)
StorageRef.putData(fileData, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
return
}
StorageRef.downloadURL { (url, error) in
guard let urlStr = url else{
completion(nil)
return
}
let urlFinal = (urlStr.absoluteString)
ShortenUrl(from: urlFinal) { result in
if (result != "") {
print("Short URL:")
print(result)
completion(result)
}
else {
completion(nil)
return
}
}
}
}
}
catch {
print("Error uploading file: " + error.localizedDescription)
self.IsLoading = false
return
}
}
显然,我需要申请某种许可才能访问和上传物理 iPhone 上的文件,但我不确定如何获得许可?我已尝试在 info.plist
中添加以下内容,但它仍然无效。
<key>NSDocumentsFolderUsageDescription</key>
<string>To access device files for upload upon user request</string>
我根据找到的一个答案弄明白了 here。
我所做的是:我正在存储对本地文件的引用,这是一个安全范围的资源。因此引发了权限错误。
我做了什么来解决这个问题:在用户选择文件的那一刻,我将使用 url.startAccessingSecurityScopedResource()
开始访问其内容并制作文件的副本而不是保留其引用。
这是选择器的更新代码 didPickDocumentsAt
:
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard controller.documentPickerMode == .open, let url = urls.first, url.startAccessingSecurityScopedResource() else { return }
defer {
DispatchQueue.main.async {
url.stopAccessingSecurityScopedResource()
}
}
do {
let document = try Data(contentsOf: url.absoluteURL)
parent.file = document
parent.fileName = url.lastPathComponent
print("File Selected: " + url.path)
}
catch {
print("Error selecting file: " + error.localizedDescription)
}
}
然后我的存储上传功能是:
func UploadFile(doc: DocumentReference, completion:@escaping((Bool?, String?) -> () )) {
do {
let StorageReference = Storage.storage().reference().child(self.User + "/" + doc.documentID + "/" + fileName!)
StorageReference.putData(file!, metadata: nil) { (metadata, error) in
if let error = error {
self.alertMessage = error.localizedDescription
self.showingAlert = true
completion(false, nil)
}
else {
StorageReference.downloadURL { (url, error) in
if let error = error {
self.alertMessage = error.localizedDescription
self.showingAlert = true
completion(false, nil)
}
else {
ShortenUrl(from: url!.absoluteString) { result in
if (result != "") {
completion(true, result)
}
else {
completion(false, nil)
}
}
}
}
}
}
}
catch {
self.alertMessage = "Error uploading file: " + error.localizedDescription
self.showingAlert = true
completion(false, nil)
}
}
我正在将 documentPicker 集成到我的 IOS 应用程序中。所选文件将使用 Firebase 存储上传。在 iPhone:
上测试应用程序时尝试上传文件时出现此错误Error uploading file: The file “file.pdf” couldn’t be opened because you don’t have permission to view it.
另一方面,在使用模拟器进行测试时我没有收到此错误或任何其他错误,并且无论我 select 来自 iCloud 还是本地存储的文件都会发生错误。
这是选择器的代码:
struct DocumentPicker: UIViewControllerRepresentable {
@Binding var filePath: URL?
func makeCoordinator() -> DocumentPicker.Coordinator {
return DocumentPicker.Coordinator(parent1: self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPicker>) -> UIDocumentPickerViewController {
let picker = UIDocumentPickerViewController(documentTypes: ["public.item"], in: .open)
picker.allowsMultipleSelection = false
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: DocumentPicker.UIViewControllerType, context: UIViewControllerRepresentableContext<DocumentPicker>) {
}
class Coordinator: NSObject, UIDocumentPickerDelegate {
var parent: DocumentPicker
init(parent1: DocumentPicker){
parent = parent1
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
// Here is where I get the path for the file to be uploaded
parent.filePath = urls[0]
print(urls[0].absoluteString)
}
}
}
这里是上传函数,报错的地方:
do {
let fileName = (PickedDocument?.lastPathComponent)!
let fileData = try Data(contentsOf: PickedDocument!)
let StorageRef = Storage.storage().reference().child(uid + "/" + doc.documentID + "/" + fileName)
StorageRef.putData(fileData, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
return
}
StorageRef.downloadURL { (url, error) in
guard let urlStr = url else{
completion(nil)
return
}
let urlFinal = (urlStr.absoluteString)
ShortenUrl(from: urlFinal) { result in
if (result != "") {
print("Short URL:")
print(result)
completion(result)
}
else {
completion(nil)
return
}
}
}
}
}
catch {
print("Error uploading file: " + error.localizedDescription)
self.IsLoading = false
return
}
}
显然,我需要申请某种许可才能访问和上传物理 iPhone 上的文件,但我不确定如何获得许可?我已尝试在 info.plist
中添加以下内容,但它仍然无效。
<key>NSDocumentsFolderUsageDescription</key>
<string>To access device files for upload upon user request</string>
我根据找到的一个答案弄明白了 here。
我所做的是:我正在存储对本地文件的引用,这是一个安全范围的资源。因此引发了权限错误。
我做了什么来解决这个问题:在用户选择文件的那一刻,我将使用 url.startAccessingSecurityScopedResource()
开始访问其内容并制作文件的副本而不是保留其引用。
这是选择器的更新代码 didPickDocumentsAt
:
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard controller.documentPickerMode == .open, let url = urls.first, url.startAccessingSecurityScopedResource() else { return }
defer {
DispatchQueue.main.async {
url.stopAccessingSecurityScopedResource()
}
}
do {
let document = try Data(contentsOf: url.absoluteURL)
parent.file = document
parent.fileName = url.lastPathComponent
print("File Selected: " + url.path)
}
catch {
print("Error selecting file: " + error.localizedDescription)
}
}
然后我的存储上传功能是:
func UploadFile(doc: DocumentReference, completion:@escaping((Bool?, String?) -> () )) {
do {
let StorageReference = Storage.storage().reference().child(self.User + "/" + doc.documentID + "/" + fileName!)
StorageReference.putData(file!, metadata: nil) { (metadata, error) in
if let error = error {
self.alertMessage = error.localizedDescription
self.showingAlert = true
completion(false, nil)
}
else {
StorageReference.downloadURL { (url, error) in
if let error = error {
self.alertMessage = error.localizedDescription
self.showingAlert = true
completion(false, nil)
}
else {
ShortenUrl(from: url!.absoluteString) { result in
if (result != "") {
completion(true, result)
}
else {
completion(false, nil)
}
}
}
}
}
}
}
catch {
self.alertMessage = "Error uploading file: " + error.localizedDescription
self.showingAlert = true
completion(false, nil)
}
}