React Native Expo ImagePicker -->Blob -->Firebase Storage未上传

fcg9iug3  于 2023-03-31  发布在  React
关注(0)|答案(2)|浏览(137)

目标:

使用Expo ImagePicker从本地存储(IOS模拟器)中选择一个映像并将其上传到Firebase存储

控制台输出:

Upload is 0% done
Upload is running

但它卡在那里,图像无法上传
首先,我调用这个函数从本地存储中选择一个图像并检索blob,图像在屏幕上显示良好,如果我试图控制台记录blob,我会得到一个错误,说它不能显示,我猜是因为它是一个blob

async function pickImage() {

    result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true, 
      aspect: [4, 3],
      quality: 1,
    }); 

    if (!result.cancelled) {
      let imageFile = await fetch(result.uri);
      let imageBlob = await imageFile.blob()
      setBlob(imageBlob)
    }
  }

然后我尝试上传到Firebase存储:

function uploadToFirebase(){ 

    const storageRef = ref(storage, 'anything.jpg');
    const uploadTask = uploadBytesResumable(storageRef, blob);

    uploadTask.on('state_changed',
  (snapshot) => {
    // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
    setImageProgress((snapshot.bytesTransferred / snapshot.totalBytes) * 100)
   
    console.log('Upload is ' + imageProgress + '% done');
    switch (snapshot.state) {
      case 'paused':
        console.log('Upload is paused');
        break;
      case 'running':
        console.log('Upload is running');
        break;
    }
  }, 
  (error) => {
    // A full list of error codes is available at
    // https://firebase.google.com/docs/storage/web/handle-errors
    switch (error.code) {
      case 'storage/unauthorized':
        // User doesn't have permission to access the object
        break;
      case 'storage/canceled':
        // User canceled the upload
        break;

      // ...

      case 'storage/unknown':
        // Unknown error occurred, inspect error.serverResponse
        break;
    }
  }, 
  () => {
    // Upload completed successfully, now we can get the download URL
    getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
      console.log('File available at', downloadURL);
      setLoadedImage(downloadURL)
    });
  }
);

  }

我已经尝试了每一个迭代,这我可以找到网上,但无济于事

ql3eal8s

ql3eal8s1#

我也遇到了同样的问题。在搜索了不同的主题后,我找到了答案。下面的代码将图像上传到Firebase存储

const uploadToFirebase = async () {
    const id = 101;
    // this is the id of the file or you can name it
   const filename = `${id}`;

const blob = await new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    // on load
    xhr.onload = function () {
    resolve(xhr.response);
};
    // on error
    xhr.onerror = function (e) {
    console.log(e);
    reject(new TypeError("Network request failed"));
};
    // on complete
    xhr.responseType = "blob";
    xhr.open("GET", pickImageResult.uri, true);
    xhr.send(null);
});

// a reference that points to this 'userphoto/101' location 
const fileRef = ref(getStorage(), 'usersphoto/${filename}');
// upload the 'blob' (the image) in the location refered by 'fileRef'
const result = await uploadBytes(fileRef, blob);

// We're done with the blob, close and release it
blob.close();

 }

注意:pickImageResult.uriImagePicker.launchImageLibraryAsync()的镜像结果;

jtoj6r0c

jtoj6r0c2#

有几个方法你可以试试。我看过其他的答案,也试过了,但有时也会失败。这里有几个方法你可以先试试。
1.将contentType元数据添加到您的上载。
1.存储最好接受png文件。如果你能重新格式化它们,用Expo manipulateAsync()。
1.切换到react-native-firebase。现在用cli builds管理expo应用非常容易。
1.我确信这只是一个firestore/realtime的东西,但是我现在从我上传到firebase服务的任何东西中删除未定义的键。有时候,我使用的键在图像上是未定义的,所以我只是在后面的前端说明这一点。
介绍用于图像上传的1和2

const newImage = await manipulateAsync(uri, [], {
              compress: 0.1, //// compressing your image is also supposed to help with the upload.
              format: SaveFormat.PNG,
            });

let file = newImage.uri
let metadata = {
   contentType: "image/png"
}

/// 3. I prefer react-native-firebase. 
/// that upload would look like 
const uploadTask = storageRef.putFile(file, metadata)

/// firebase v9 would look like
const uploadTask = uploadBytesResumable(storageRef, file, metadata)

视频上传给了我更多的麻烦,这是我的解决方案:

file = image.localUri;
            const filetype = file.split(".").pop()?.toLowerCase();
//// 1. Add file metadata
            if (filetype === "mov") {
              metaData = {
                contentType: "video/quicktime",
              };
            } else if (filetype === "mp4") {
              metaData = {
                contentType: "video/mp4",
              };
            }
            
            const res = await fetch(file);
            const blob = await res.blob();

            ///3. react native firebase
            const uploadTask = assetRef.put(blob);
            
            ///firebase v9
            const uploadTask = uploadBytesResumable(storageRef, blob, metadata);

1.删除未定义的键。

///I don't think this has a real effect on storage, but I do it as a just incase measure. Do this when you're picking your image with image picker.

const removeUndefinedKeys = (obj: any) => {
  let newObj: any = {};
  for (let key in obj) {
    if (obj[key] !== undefined) {
      newObj[key] = obj[key];
    }
  }
  return newObj;
};

const wUndKeys = { height: 100, width: 100, orientation: undefined }

const newObj = removeUndefinedKeys(wUndKeys)

/// newObj = { height: 100, width: 100 }

我先给了你TLDR
下面是上传到存储桶的实际函数

let p = images.map((image, index) => {
          return { progress: 0, i: index };
        });
        setUploadProgress(0);
        for (let i = 0; i < images.length; i++) {
          console.log(`image ${i} of ${images.length}`);
          const image = images[i];
          const id = `${uuid.v4()}}`;
          let file = "";
          let metaData = {};
          let uri = image.localUri ?? image.uri;
          const assetRef = storage().ref(
            `users/${auth.currentUser?.uid}/posts/${postId}/assets/${id}`
          );

          if (image.mediaType !== "video") {
            const newImage = await manipulateAsync(uri, [], {
              compress: 0.1,
              format: SaveFormat.PNG,
            });

            file = newImage.uri;
            metaData = {
              contentType: "image/png",
            };
   
            const uploadTask = assetRef.putFile(file, metaData);

            uploadTask.on("state_changed", (e) => {
              const progress = (e.bytesTransferred / e.totalBytes) * 100;
              const prog = Math.ceil(progress);
///This is a reduce function to calculate the total progress relative to total photos
              p = p.map((im) => {
                if (im.i === i) {
                  return { ...im, progress: prog };
                }
                return im;
              });
              const total = p.reduce((acc, cur) => {
                return acc + cur.progress;
              }, 0);

              var currentProgress = Math.ceil(total / images.length);
              setOverallProgress(currentProgress * 0.98);
              return setUploadProgress(Math.ceil(total / images.length));
            });

// this is to handle things after the upload completes without interrupting the loop
            await uploadTask.then(async () => {
              const url = await assetRef.getDownloadURL();
              urls = [...urls, { ...image, url: url }];
            });
          } else {
            file = image.localUri;
            const filetype = file.split(".").pop()?.toLowerCase();
            if (filetype === "mov") {
              metaData = {
                contentType: "video/quicktime",
              };
            } else if (filetype === "mp4") {
              metaData = {
                contentType: "video/mp4",
              };
            }
            console.log("uploading video");
            const res = await fetch(file);
            const blob = await res.blob();

            const uploadTask = assetRef.put(blob);

            uploadTask.on("state_changed", (e) => {
              const progress = (e.bytesTransferred / e.totalBytes) * 100;
              const prog = Math.ceil(progress);

              p = p.map((im) => {
                if (im.i === i) {
                  return { ...im, progress: prog };
                }
                return im;
              });
              const total = p.reduce((acc, cur) => {
                return acc + cur.progress;
              }, 0);

              var currentProgress = Math.ceil(total / images.length);
              setOverallProgress(currentProgress * 0.98);
              return setUploadProgress(Math.ceil(total / images.length));
            });
            await uploadTask.then(async () => {
              const url = await assetRef.getDownloadURL();
              const newObj = removeUndefinedKeys(image);
              console.log(newObj);
              urls = [...urls, { ...newObj, url: url }];
            });
          }
        }
        postDoc = { ...post, assets: urls };
      }

希望这对你有帮助!

相关问题