如何在用户图库或相机中获取所选照片的URL?



我有一个应用程序,用户可以选择是要拍照还是从他们的库中选择一个。我拥有的代码获取Xcode设备模拟器的图像URL,但不适用于我的物理iPhone。 当我使用个人设备选择图像时,打印结果

Failed: There is a client side validation error for the field [local] with message: The file located at the `local` URL is missing. Make sure the file exists before uploading to storage.

但是当我使用设备模拟器运行时,它运行完美,图像存储在我的后端。我不确定为什么会发生这种情况。

我希望能够从自己的设备获取URL。

来自 Xcode 设备模拟器的打印网址

file:///Users/GBMR/Library/Developer/CoreSimulator/Devices/877A8184-D857-4211-94B1-00A6B724A956/data/Containers/Data/Application/094279FA-37B1-45E6-ABC4-ADAA08B5477B/PicturesB71286E4-1994-4D76-AC14-D40A062BC832.jpeg
Completed: ywassupo

从我的实体 iPhone 打印的网址

file:///var/mobile/Containers/Data/Application/C0415B3C-F50E-4D20-8D8A-941D29B9C4D1/Pictures9BA481F9-C52A-40FD-8A06-AAA2D6CDA6D7.jpeg
Failed: There is a client side validation error for the field [local] with message: The file located at the `local` URL is missing. Make sure the file exists before uploading to storage.

法典:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
imageView.image = selectedImage
imageView.contentMode = .scaleAspectFit
//            detect(image: ciimage)
navigationItem.title = "Tap next to continue"
nextButton.isEnabled = true
if let imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL{
let imgName = imgUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.picturesDirectory, .allDomainsMask, true).first
let localPath = documentDirectory?.appending(imgName)
//let image = info[UIImagePickerController.InfoKey] as! UIImage
let data = selectedImage.pngData()! as NSData
data.write(toFile: localPath!, atomically: true)
//let imageData = NSData(contentsOfFile: localPath!)!
let photoURL = URL.init(fileURLWithPath: localPath!)
let infoTVC = InfoTableViewController()
infoTVC.imageChosenName = photoURL
_ = Amplify.Storage.uploadFile(key: "ywassupo", local: photoURL ,resultListener: {(event) in
switch event{
case .success(let data):
print("Completed: (data)")
case .failure(let storageError):
print("Failed: (storageError.errorDescription). (storageError.recoverySuggestion)")
}
})
//NSURL(fileURLWithPath: localPath!)
print(photoURL)
dismiss(animated:true, completion: nil)
}
}
}

任何人都可以引导我朝着如何解决这个问题的正确方向前进吗?

由于UIImagePickerController不会为您提供所选图像的路径,您所要做的就是简单地获取图像info[UIImagePickerControllerOriginalImage] as UIImage并通过提供目录路径保存到应用程序存储区域中的本地。

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let image = info[.editedImage] as? UIImage else { return }
let imageName = UUID().uuidString
let imagePath = getDocumentsDirectory().appendingPathComponent(imageName)
if let jpegData = image.jpegData(compressionQuality: 0.8) {
try? jpegData.write(to: imagePath)
}
dismiss(animated: true)
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}

如果您只需要保存一张图像,效果很好。如果是多个映像,则需要编写一些逻辑来创建唯一的映像名称并将其保存到同一目录中。

不要忘记在 info.plist 中添加权限以下键

照相机:

Key       :  Privacy - Camera Usage Description   
Value     :  <your project name> will use camera to capture photo.

相片:

Key       :  Privacy - Photo Library Usage Description    
Value     :  <your project name> will use photo library to select photo.

您没有正确构建路径。有几个问题:

  1. 您只需将文件名附加到图片路径字符串。文件夹和文件名之间缺少斜杠。显然,您可以自己添加它,但为了将来参考,如果您使用 URL,它会为您添加必要的斜杠。

  2. 此"图片"目录不适用于 iOS。我建议使用不同的文件夹。也许将其复制到临时目录中的文件夹中,从那里上传,然后在完成后进行清理。

  3. 如果你想知道为什么你的代码在模拟器上工作,而不是在设备上工作,那是因为前者不强制执行沙盒规则,而后者会。


顺便说一句,除非必要,否则我建议避免在UIImage中"往返"。上面,我们正在处理原始资产,但是如果您创建一个UIImage,然后提取JPG或PNG表示形式,您将丢失有关资产的信息,并可能使资产大于需要。获取图像 URL、复制该文件并上传的效率要高得多:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let imageUrl = info[.imageURL] as? URL else {
return
}
do {
let tempDirectory = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent("uploads")
try FileManager.default.createDirectory(at: tempDirectory, withIntermediateDirectories: true, attributes: nil)
let fileURL = tempDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathComponent(imageUrl.pathExtension)
try FileManager.default.copyItem(at: imageUrl, to: fileURL)
// when done, clean up (presumably in the completion handler of the async upload routine)
try FileManager.default.removeItem(at: fileURL)
} catch {
print(error)
}
dismiss(animated: true)
}