【问题标题】:Firebase storage upload works in Simulator but not on iPhoneFirebase 存储上传适用于模拟器,但不适用于 iPhone
【发布时间】:2016-10-02 20:48:19
【问题描述】:

为什么 Xcode 会向我抱怨关于将图像上传到 Firebase 存储的权限,但是当我在模拟器中运行相同的应用程序时,它工作正常?

权限错误:

无法访问正文文件:/var/mobile/Media/DCIM/100APPLE/IMG_0974.JPG 错误域=NSCocoaErrorDomain 代码=257 “文件“IMG_0974.JPG” 无法打开,因为您无权查看。” UserInfo={NSURL=file:///var/mobile/Media/DCIM/100APPLE/IMG_0974.JPG, NSFilePath=/var/mobile/Media/DCIM/100APPLE/IMG_0974.JPG, NSUnderlyingError=0x14805d680 {错误域=NSPOSIXErrorDomain 代码=1 "不允许操作"}}

【问题讨论】:

  • 不是 Firebase 问题。 iOS 问题。
  • 谢谢?我知道,因为它在 sim 中工作。
  • @EricD 为什么我没有权限写入自己的设备?我知道这不是 Firebase 问题。
  • 模拟器上的应用沙盒可能与物理设备不同,/var 目录很可能不是用户可在物理设备上写入的。有关完整详细信息,请参阅 developer.apple.com/library/mac/documentation/FileManagement/…(TL;DR:使用 /Documents/tmp)。
  • 您找到解决方案了吗?对我来说同样的问题

标签: ios swift firebase-storage


【解决方案1】:

我现在也有同样的问题。在模拟器中上传工作正常,但在设备上它给了我权限错误。我的解决方法是将图像作为数据而不是文件的 URL 上传:

let imageData = UIImageJPEGRepresentation(image, 1.0)
let uploadTask = storageReference.child(remoteFilePath).putData(imageData, metadata: metadata, completion: { (metadata, error) in
    // Your code here
}

【讨论】:

  • 抱歉,什么是元数据:元数据?为什么 xcode 无法解析此标识符
【解决方案2】:

在模拟器中上传工作正常,但在设备上它给了我权限错误。 将图像作为数据而不是文件的 URL 上传:

先声明

    fileprivate lazy var storageRef: StorageReference = Storage.storage().reference(forURL: "gs://yourAPP.appspot.com/")

然后

     let path : String = "\(String(describing: Auth.auth().currentUser?.uid))/\(Int(Date.timeIntervalSinceReferenceDate * 1000))/\(photoReference)"

                // 6

                let imageData = UIImageJPEGRepresentation(photoReference, 0.1)
                let uploadTask = self.storageRef.child(path).putData(imageData!, metadata: nil, completion: { (metadata, error) in
                    // Your code here
                    if let error = error {
                        print("Error uploading photo: \(error.localizedDescription)")
                        return
                    }

                    // 7
                    self.setImageURL(self.storageRef.child((metadata?.path)!).description, forPhotoMessageWithKey: key)
                })

【讨论】:

    【解决方案3】:

    另一种选择是将文件复制到“文档”目录(可写)。它使用的代码比UIImageJPEGRepresentation 方法多一点,所以您可能仍然更喜欢使用该技术。如果您真的不想更改原始图像,也许可以使用“文档目​​录”方法(但是,理论上,原始图像与 100% 使用 UIImageJPEGRepresentation 创建的图像之间的差异应该是难以察觉的)。

    asset.requestContentEditingInput(with: options, completionHandler: {(contentEditingInput: PHContentEditingInput?, info: [AnyHashable : Any]) -> Void in
    
        let originalFileUrl = contentEditingInput!.fullSizeImageURL!
    
        /* Copy file from photos app to documents directory */
        let fileManager = FileManager.default
        let documentsDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
        let destinationPath = documentsDirectory.appendingPathComponent(originalFileUrl.lastPathComponent)
        let destinationUrl = URL(fileURLWithPath: destinationPath)
    
        do {
            try fileManager.copyItem(at: originalFileUrl, to: destinationUrl)
        }
        catch {
            print("Unable to copy file from photos to documents directory (run out of space on device?)")
            return
        }
    
        /* Create metadata etc. for Firebase... */
    
        /* Upload file to Firebase */
        fileRef.putFile(from: destinationUrl, metadata: metadata, completion: { (metadata, error) in
    
            // Remove the file from the documents directory
            do {
                try fileManager.removeItem(at: destinationUrl)
            }
            catch {
                print("Unable to remove file from documents directory")
            }
    
        })
    
    
    })
    

    【讨论】:

      【解决方案4】:

      这个代码在didFinishPickingMediaWithInfo下面。

      我评论了当用户从照片库中选择图像时处理的代码:

      func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
          picker.dismissViewControllerAnimated(true,completion:nil)
          let image = info[UIImagePickerControllerOriginalImage] as! UIImage//<--
      
          let imageData = UIImageJPEGRepresentation(image, 1.0)
          let imagePath = "photos/xxxyyyzzz.jpg"//whatever you want
          let metadata = FIRStorageMetadata()
          metadata.contentType = "image/jpeg"
                  
          storageRef.child(imagePath).putData(imageData!,metadata:metadata){
                      (metadata, error) in
                      if let error = error{
                          print("Error uploading photo: \(error)")
                      }
                      else{
                          //if there is no error the compiler will come here
                          print("no error")
                          //and maybe you want to use the full url or download url after success
                          //for example you wanna have tha downloadURL...
                          let downloadURL = metadata!.downloadURL()
                          print("\(downloadURL)")
                          //do whatever you want...
                      }
          }
      
      }
      

      【讨论】:

        【解决方案5】:

        我正在使用 SwiftUI 和 .fileImporter 它对我来说仍然很新,所以我不确定它是否可以,但它现在可以工作了,所以我想我会把代码留在这里,让那些也在苦苦挣扎的人。

        添加文件管理器扩展

         extension FileManager {
        
        
           static func getDocumentsDirectory() -> URL {
               let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
               let documentsDirectory = paths[0]
               return documentsDirectory
           }
        }
        

        【讨论】:

          【解决方案6】:

          查看 Firebase 存储规则。 并临时允许所有没有身份验证的路径。

          【讨论】:

          • 我已经这样做了,它可以在 xcode 的模拟器中运行。这些规则用于写入 a 和从 Firebase 读取。这是我的设备的权限问题。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-11
          • 1970-01-01
          • 1970-01-01
          • 2011-03-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多