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)
    }
}