firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.75k stars 872 forks source link

uploadBytes to storage with expo Image picker causing app to crash with no logs #5848

Open sejaljhawer opened 2 years ago

sejaljhawer commented 2 years ago

[REQUIRED] Describe your environment

[REQUIRED] Describe the problem

I am using Expo Image picker to select an image, convert to blob, then the Firebase 9.0 SDK function uploadBytes to add the image to my storage bucket. Around 60-80% of the time, the uploadBytes function causes my app to crash with no errors or logs recorded. When the app does not crash, the upload to Storage is successful.

Similar code and crashing symptoms as: https://stackoverflow.com/questions/70528896/react-native-expo-image-picker-upload-image-to-firebase-storage-v9-crash

Steps to reproduce:

Relevant Code:

const uploadNewPhoto = async() => {
  let result = await ImagePicker.launchImageLibraryAsync({
              mediaTypes: ImagePicker.MediaTypeOptions.Images,
              allowsEditing: false,
              // aspect: [4, 3],
              quality: 0.1,
          });

  if (!result.cancelled) {
              // Convert URI to a Blob via XHTML request, and actually upload it to the network
              const blob = await new Promise((resolve, reject) => {
                  const xhr = new XMLHttpRequest();
                  xhr.onload = function() {
                      resolve(xhr.response);
                  };
                  xhr.onerror = function() {
                      reject(new TypeError('Network request failed'));
                  };
                  xhr.responseType = 'blob';
                  xhr.open('GET', result.uri, true);
                  xhr.send(null);
              });
              const thisUsersNewPostRef = ref(storageRef, 'users/img1' );    

              uploadBytes(thisUsersNewPostRef, blob).then((snapshot) => { // causes crash
                  console.log('Uploaded a blob or file!');
              });
  }
}
Eesha-Jain commented 2 years ago

Hello! In order to solve your issue, I first recommend that you update to the latest version of firebase (v9) within your Expo application. Then, watch this video: https://www.youtube.com/watch?v=H-yXO46WDak . Very recent video so it incorporates version 9 and also should solve your issue because it also tries to upload image to firebase storage. Hope this helps!

Eesha-Jain commented 2 years ago

When looking at your code, I believe that it is the method that you use to generate the blob is complicated and prone to errors. Reference the video I just sent to see how I recommend you turn your image into a blob.

rgioeli commented 2 years ago

@Eesha-Jain Your YouTube code works for images through ImagePicker but not for videos. It always crashes on iOS videos. Android videos go through just fine.

Eesha-Jain commented 2 years ago

Ohh, alright. Looks like this may hold a solution: https://github.com/expo/expo/issues/3177

bricee98 commented 2 years ago

@rgioeli hey, I am having the same issue - did you end up finding a solution that worked for you?

pfibbe commented 2 years ago

@rgioeli hey, I am having the same issue - did you end up finding a solution that worked for you?

I downgraded to v8 of firebase sdk, that worked for me. Not sure if it's an option for you, but maybe for other people reading this.

As described in the comment at https://www.youtube.com/watch?v=H-yXO46WDak&lc=UgwNOcXKFQl2UARHz6Z4AaABAg.9Wqk13KYbzW9WuNC4HWz_s

bricee98 commented 2 years ago

@pfibbe I just saw that mentioned somewhere else as well - seems like the way to go. Thanks!

hsubox76 commented 2 years ago

Thanks for the info that this works with 8.10.0 and not in 9.6.1. Would anybody be able to try and see if this is also broken in any earlier v9 builds, such as 9.2.0 perhaps? It would help us narrow down when the relevant change happened.

bricee98 commented 2 years ago

I was actually using 9.2.0 when I came across the issue.

hsubox76 commented 2 years ago

Does the error also occur in 9.0.0?

bricee98 commented 2 years ago

Unsure - unfortunately, I won't be able to check for a while, sorry.

Eesha-Jain commented 2 years ago

I would recommend going to 8.10.0 cause we're sure that works

Eesha-Jain commented 2 years ago

However, trying won't do any harm! :)

jackblackCH commented 2 years ago

Same issue, some video files fail randomly.

hsubox76 commented 2 years ago

If anyone can confirm the error also occurs in 9.0.0 and does not occur in 8.10.0, it will help us a lot in narrowing down the change that caused it.

jackblackCH commented 2 years ago

I will test it now with specific version of 9.0.0. It was definitely not working with ^9.2.0, then I switched back to 8.10.0 as mentioned here) and it was not working either. That being said, only with certain videos. Probably, as mentioned coz of memory issues with not small videos.

If anyone can confirm the error also occurs in 9.0.0 and does not occur in 8.10.0, it will help us a lot in narrowing down the change that caused it.

pranav-singh-parmar commented 2 years ago

Hello, everyone i also faced the same issue, on firebase version 9.6.5, so i have used function uploadBytesResumable instead of uploadBytes, it works just fine, if it is urgent you can use that function for the time being, just a recommendation, for reference:- https://firebase.google.com/docs/storage/web/upload-files

I faced this issue in iOS 15 and 15 + only, rest below iOS 15 and in android OS uploadBytes is working fine.

Note:- when using XMLHttpRequest with uploadBytesResumable, first time image uploads smoothly on iOS 15.2 then, on uploading it on second time there is crash while uploading image. To avoid it use, const img = await fetch(image_url); const blob = await img.blob();

this way we can also get blob file;

import { getStorage, ref, getDownloadURL } from "firebase/storage";

const storageRef = ref(getStorage(), "image_name");

const img = await fetch(image_url); const blob = await img.blob();

console.log("uploading image"); const uploadTask = uploadBytesResumable(storageRef, blob);

// Listen for state changes, errors, and completion of the upload. uploadTask.on('state_changed',(snapshot) => { // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log('Upload is ' + progress + '% done'); switch (snapshot.state) { case 'paused': console.log('Upload is paused'); break; case 'running': console.log('Upload is running'); break; } }, (error) => { this.setState({ isLoading: false }) // A full list of error codes is available at // https://firebase.google.com/docs/storage/web/handle-errors switch (error.code) { case 'storage/unauthorized': console.log("User doesn't have permission to access the object"); break; case 'storage/canceled': console.log("User canceled the upload"); break; case 'storage/unknown': console.log("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); //perform your task }); });

salmanExpo commented 2 years ago

If anyone can confirm the error also occurs in 9.0.0 and does not occur in 8.10.0, it will help us a lot in narrowing down the change that caused it.

well i was using v9.4 then i upgrade it to latest version. i was able to upload file less than 2mb ... greater files will make the app crash

so i went down to version 9.0.0 and i was able to upload files at 100mb+ so i think this issue related to newer versions of firebase.

hsubox76 commented 2 years ago

Will keep trying to dig into this but so far it seems that this error:

1) affects larger files 2) can be avoided by using uploadBytesResumable() instead of uploadBytes() 3) can also be avoided by using fetch() instead of XMLHttpRequest to get the image from the Expo image picker url

It seems 2 and 3 may be viable workarounds for the time being if anyone is blocked.

As far as more info about versions affected, it seems to affect: 1) iOS 15+ 2) Firebase JS SDK 9.2.0 ?? +

Feel free to chime in with any corrections, updates, or other workarounds. We will try to keep looking for what might have caused this in the Firebase SDK.

GYatesIII commented 2 years ago

I am experiencing this issue as well.

  1. This is in an expo managed app.
  2. The error only appears on videos longer than about 10 seconds @ 720p.
  3. I am using fetch to retrieve the blob before upload.
  4. I experience it both with uploadBytesResumable where it crashes without error after a few seconds. And uploadBytes where it crashes immediately.

I have pinpointed that I can rollback to Firebase JS SDK 9.3.0 and everything works as expected, but upgrading to 9.4.1 - 9.6.6 causes the failure to occur. So for our experience it's something introduced between 9.3.0 and 9.4.1.

pranav-singh-parmar commented 2 years ago

The code that i wrote above is running fine on my mac but when complied from my colleague's pc created the same issue. We were still not able to resolve it by downgrading firebase version. I don't think issue lies in firebase sdk. It's just that it is not compatible with iOS 15 ?? + (because i only faced this issue in iOS 15). Maybe a support for iOS 15 needs to be added as iOS 15 has come up with major updations. Just a guess. Try to solve issue by changing firebase version and maybe compiling your code on other device. I will still recommend to use uploadResumable bytes and fetch.

juliancstrocodes commented 2 years ago

How would i rollback to a different version of FIREBASE?

salmanExpo commented 2 years ago

How would i rollback to a different version of FIREBASE? you will need to use name and version of the package npm install packageName@X.X.X

SRoche14 commented 2 years ago
async function uploadImageAsync(uri, title, index) {
    // Why are we using XMLHttpRequest? See:
    // https://github.com/expo/expo/issues/2402#issuecomment-443726662
    const blob = await new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.onload = function () {
        resolve(xhr.response);
      };
      xhr.onerror = function (e) {
        reject(new TypeError("Network request failed"));
      };
      xhr.responseType = "blob";
      xhr.open("GET", uri, true);
      xhr.send(null);
    });

    const fileRef = ref(storage, `images/events/${title}/image${index}`);
    const result = await uploadBytesResumable(fileRef, blob);

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

    return await getDownloadURL(fileRef);
  }

Been using the above code to upload images to firebase (version 9.6.6). Works perfectly with one image, but cannot upload multiple images. Any suggestions? Have tried using await and .then() to try looping, but that has not worked either.

hsubox76 commented 2 years ago

So we have one report that the bug occurred in 9.2.0, and a separate report that it did not occur in 9.3.0 but did occur in 9.4.1, which seems confusing to me. Any additional data about what versions the error is or isn't happening would be helpful in sorting out what changes to look at.

pranav-singh-parmar commented 2 years ago
async function uploadImageAsync(uri, title, index) {
   // Why are we using XMLHttpRequest? See:
   // https://github.com/expo/expo/issues/2402#issuecomment-443726662
   const blob = await new Promise((resolve, reject) => {
     const xhr = new XMLHttpRequest();
     xhr.onload = function () {
       resolve(xhr.response);
     };
     xhr.onerror = function (e) {
       reject(new TypeError("Network request failed"));
     };
     xhr.responseType = "blob";
     xhr.open("GET", uri, true);
     xhr.send(null);
   });

   const fileRef = ref(storage, `images/events/${title}/image${index}`);
   const result = await uploadBytesResumable(fileRef, blob);

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

   return await getDownloadURL(fileRef);
 }

Been using the above code to upload images to firebase (version 9.6.6). Works perfectly with one image, but cannot upload multiple images. Any suggestions? Have tried using await and .then() to try looping, but that has not worked either.

Use this code to get blob file instead of XMLHttpRequest const img = await fetch(uri); const blob = await img.blob();

GYatesIII commented 2 years ago

So we have one report that the bug occurred in 9.2.0, and a separate report that it did not occur in 9.3.0 but did occur in 9.4.1, which seems confusing to me. Any additional data about what versions the error is or isn't happening would be helpful in sorting out what changes to look at.

I can confirm that I stepped through minor versions one-by-one until it started occurring and it first started in 9.4

This is on managed Expo app served through the Expo app. The impact on iOS it uploads for a bit then crashes without error. On Android, it uploads for a bit then hangs forever without error. This testing was done on real devices, not simulators.

I only stepped through the individual versions within the Expo app but can also verify it worked in 9.0 when deployed through the official stores, and was broken in 9.6. On both platforms.

cpon00 commented 2 years ago

Hello, I'm having the same issue, but I might be able to add some insight. Here is my current takePicture function:

const takePicture = async () => { if (cameraRef.current) { const options = { quality: 0.1, base64: true, skipProcessing: true }; const data = await cameraRef.current.takePictureAsync(options); const source = data.uri if (source) { navigateToSave(source) } } };

I'm also using the Full Example from the Firebase Upload Files documentation.

With the current options, I am able to upload both images from the camera to Firebase. However, if I remove the quality option, the upload fails 100% of the time. It would seem that the size of the file might cause uploadBytesResumable to crash.

Using Firebase v9.6.6 and Expo v43.0.0; Windows 10 and Expo Go.

hsubox76 commented 2 years ago

There's 2 reports indicating this may have started in 9.4.1, and if so, this would be the relevant commit: https://github.com/firebase/firebase-js-sdk/pull/5703 Will try to take a closer look.

Cosmicoda commented 2 years ago

There's 2 reports indicating this may have started in 9.4.1, and if so, this would be the relevant commit: #5703 Will try to take a closer look.

I can confirm that I have the problem with 9.2.0 and above (including 9.3.0). I haven't been able to test yet with 9.0.0 and 9.1.0.

doldoldol21 commented 2 years ago

failed in Expo v44.0.0 and Firebase v9.6.6

succeeded in Expo v44.0.0 and Firebase v9.4.0

Problems with the latest version?

My test code

const filename = new Date().getTime() + "-chat.jpg";
    const metadata = {
      contentType: "image/jpeg",
      height: result.height,
      width: result.width,
    };
    const response = await fetch(result.uri);
    const blob = await response.blob();

    const storageRef = Storage.ref(Storage.getStorage(), "chat/" + filename);
    const uploadTask = Storage.uploadBytesResumable(storageRef, blob, metadata);

    const unsubscribe = uploadTask.on(
      "state_changed",
      (snapshot) => {

        const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);

        console.log(progress);

      },
      (error) => {

        console.log(error);
      },
      () => {

        getDownloadURL(uploadTask.snapshot.ref).then(async (downloadURL) => {
          console.log("File available at", downloadURL);

        });
      }
lfaz commented 2 years ago

Expo v44.0.0 and Firebase v9.4.0 also doesnt work for me on iOS 15.3 , the only way how I got it working is to set a timeout like:

xhr.onload = function () {
      setTimeout(() => {
        resolve(xhr.response);
      }, 1000);
    };

to make it work, I know this is just a workaround and not a real solution

lfaz commented 2 years ago

Has anyone have a working solution for this? Still app crashing on random phones with random images when using Expo v44.0.0 and Firebase v9.4.0, v9.6.7 and Firebase cloud storage! I have tried with cloudinary with same config and I didnt get any crash while uploading any image at all, certainly the problem seems to be the Firebase sdk!

jackblackCH commented 2 years ago

It's unstable. I send it to my own upload endpoint and upload it from there.

JacobJaffe commented 2 years ago

It's unstable. I send it to my own upload endpoint and upload it from there.

I'm also doing this -- using a firebase function endpoint similar to: https://cloud.google.com/functions/docs/writing/http#multipart_data .

FWIW for those trying to work around this, using a signed upload URL might be more straightforward for many use cases. However, signed uploads aren't available with the emulators.

hsubox76 commented 2 years ago

Some people mentioned a workaround where it works if you use uploadBytesResumable() and use fetch() instead of XMLHttpRequest to get the blob:

const img = await fetch(image_url);
const blob = await img.blob();

Unfortunately it's difficult to pinpoint because there seem to be conflicting reports of what Firebase SDK version this is broken in, as in, some say it broke in 9.2.0, some say 9.4.0, or 9.4.1, and there's one report it was working in 9.4.0 but broken in 9.6.6. The only thing I think we can be sure of is that it was working in 9.0.0 and earlier.

Edit: I don't suppose anyone has filed an issue in the Expo repo? Not that I'm saying the bug is their fault, but wondering if they could shed some light on why certain image files might be different from others and help us know what to look for on our side.

JacobJaffe commented 2 years ago

For what it's worth, using fetch() goes against the explicit documentation in the firebase-with-expo example by the Expo docs: https://docs.expo.dev/versions/latest/sdk/imagepicker/#using-imagepicker-with-firebase

The example code: https://github.com/expo/examples/blob/c1ed3dec2f3c263ebae97262ea5506192f3d7b9c/with-firebase-storage-upload/App.js#L193

async function uploadImageAsync(uri) {
  // Why are we using XMLHttpRequest? See:
  // https://github.com/expo/expo/issues/2402#issuecomment-443726662
  const blob = await new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.onload = function () {
      resolve(xhr.response);
    };
    xhr.onerror = function (e) {
      console.log(e);
      reject(new TypeError("Network request failed"));
    };
    xhr.responseType = "blob";
    xhr.open("GET", uri, true);
    xhr.send(null);
  });

  const fileRef = ref(getStorage(), uuid.v4());
  const result = await uploadBytes(fileRef, blob);

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

  return await getDownloadURL(fileRef);
}

(It very well might be that this is outdated -- this is referencing RN 0.57, and old polyfill issues -- but it's the still-referenced code example)

lfaz commented 2 years ago

does anyone has actually a working solution for this rather workarounds which are not reliable at all?

edi commented 2 years ago

We are facing the same issue. First upload goes through, second one crashes expo app and client, without any logs. We on iOS 15.4, using Expo SDK 44 and Firebase 9.6.9.

We are already using uploadBytesResumable, alongside fetch blob.

let file = await fetch(data.uri)
blob = await file.blob()

So, no workarounds for us ... please advise.

Crash log:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 
[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]
NaikDeepak commented 2 years ago

Frustrating it is, it working sometimes and not working sometimes, instead of using firebase storage, I shifted to cloudinary for image storage and it worked.

edi commented 2 years ago

Does the error also occur in 9.0.0?

I can confirm it does not work in any version >= 9.1.0.

Cannot test with 9.0.0 since it just throws the following error

Considering nothing's changed between 9.0.0 and 9.1.0 in terms of Storage (as far as I can see in the release notes that is), I doubt it works with 9.0.0 either.

We have not had any issues before porting to v9 from v8.2.3.

For the time being, I'm just going to shift our projects to Cloudinary, as we can't just go back to v8 anymore.

harrymansworth commented 2 years ago

This issue is present in all versions >=9.0.0.

Any file >=2mb will cause the app to crash. This may appear to be a random occurance, but this is likely down to the variance in image size from the phone camera which on an iPhone 13 hovers around 1.5mb to 2.5mb when quality is set to 0.5. As soon as the bytes sent hits 2mb 💀

AngelDev0329 commented 2 years ago

I am facing the same issue. First upload goes through, second one crashes expo app and client, without any logs. We on iOS 15.2.1, using Expo SDK 44 and Firebase 9.6.10. And it happens for large images (>2mb).

On only production version

Here is my code.

try {
        const response = await fetch(attach.uri);
        const blob = await response.blob();
        const path = `${user.email}/${new Date().getTime()}`;
        const storageRef = ref(storage, path);
        await uploadBytes(storageRef, blob);
        const src = await getDownloadURL(storageRef);
} catch (error) {
        setLoading(false);
        console.log("🚀 ~ file: grouppage.jsx ~ error", error);
}
jackblackCH commented 2 years ago

I downgraded to 8.x and seems to work. As a workaround I recommend to send it to your own proxy api of your choice and upload it from there via the SDK or REST Api.

farchijets commented 2 years ago

The example on Expo's repo mentioned by @JacobJaffe is the way to go about this

Expo 44, Firebase 9.6.10, no more IOS issues, Expo Example

Here is that same example but in a functional component minus the app initialized check, share, and clipboard functions for simplicity sake

import { getStorage, ref, uploadBytes, getDownloadURL } from "firebase/storage";
import React, {useState, useEffect} from "react";
import {
  ActivityIndicator,
  Button,
  Image,
  StatusBar,
  StyleSheet,
  Text,
  View,
} from "react-native";
import uuid from "uuid";

// ----------------------------------------------------
// -------------- START COMPONENT ----------------
// ----------------------------------------------------

export default function Home(){

  const[image, setImage] = useState(null)
  const[uploading, setUploading] = useState(false)

// ----------------------------------------------------
// ---- GET DEVICE PERMISSIONS ON INITIAL MOUNT -------
// ----------------------------------------------------

  useEffect(()=>{
    async ()=>{
      if (Platform.OS !== "web") {
        const {
          status,
        } = await ImagePicker.requestMediaLibraryPermissionsAsync();
        if (status !== "granted") {
          alert("Sorry, we need camera roll permissions to make this work!");
        }
      }
    }
  },[])

// ---------------------------------------------------
// --------- GET BLOB / UPLOAD TO FIREBASE -----------
// ---------------------------------------------------

async function uploadImageAsync(uri) {
  const blob = await new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.onload = function () {
      resolve(xhr.response);
    };
    xhr.onerror = function (e) {
      console.log(e);
      reject(new TypeError("Network request failed"));
    };
    xhr.responseType = "blob";
    xhr.open("GET", uri, true);
    xhr.send(null);
  });

  const fileRef = ref(getStorage(), uuid.v4());
  const result = await uploadBytes(fileRef, blob);

  blob.close();

  return await getDownloadURL(fileRef);
}

// ---------------------------------------------------
// ----------- GET IMG FROM CAMERA  ------------------
// ---------------------------------------------------

  let takePhoto = async () => {
    let pickerResult = await ImagePicker.launchCameraAsync({
      allowsEditing: true,
      aspect: [4, 3],
    });

    handleImagePicked(pickerResult);
  };

// ----------------------------------------------------
// ------------- GET IMG FROM LOCAL -------------------
// ----------------------------------------------------

  let pickImage = async () => {
    let pickerResult = await ImagePicker.launchImageLibraryAsync({
      allowsEditing: true,
      aspect: [4, 3],
    });

    console.log({ pickerResult });

    handleImagePicked(pickerResult);
  };

// -------------------------------------------------
// --- SET LOADING STATE / UPLOAD IMG TO FIREBASE --
// -------------------------------------------------

  let handleImagePicked = async (pickerResult) => {
    try {
      setUploading(true);

      if (!pickerResult.cancelled) {
        const uploadUrl = await uploadImageAsync(pickerResult.uri);
        setImage(uploadUrl);
      }
    } catch (e) {
      console.log(e);
      alert("Upload failed, sorry :(");
    } finally {
      setUploading(false);
    }
  };

// -------------------------------------------------
// ---- CHECK IF UPLOADING / SHOW WHEEL ----
// -------------------------------------------------

let maybeRenderUploadingOverlay = () => {
  if (uploading) {
    return (
      <View
        style={[
          StyleSheet.absoluteFill,
          {
            backgroundColor: "rgba(0,0,0,0.4)",
            alignItems: "center",
            justifyContent: "center",
          },
        ]}
      >
        <ActivityIndicator color="#fff" animating size="large" />
      </View>
    );
  }
};

// -------------------------------------------------
// ------- CHECK FOR IMAGE / DISPLAY IMAGE ---------
// -------------------------------------------------

let maybeRenderImage = () => {
  if (!image) {
    return;
  }
  return (
    <View
      style={{
        marginTop: 30,
        width: 250,
        borderRadius: 3,
        elevation: 2,
      }}
    >
      <View
        style={{
          borderTopRightRadius: 3,
          borderTopLeftRadius: 3,
          shadowColor: "rgba(0,0,0,1)",
          shadowOpacity: 0.2,
          shadowOffset: { width: 4, height: 4 },
          shadowRadius: 5,
          overflow: "hidden",
        }}
      >
        <Image source={{ uri: image }} style={{ width: 250, height: 250 }} />
      </View>

      <Text style={{ paddingVertical: 10, paddingHorizontal: 10 }}>
        {image}
      </Text>

    </View>
  );
};

// ---------------------------------------------------
// --------------------- RETURN ----------------------
// ---------------------------------------------------

  return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
      {!!image && (
        <Text
          style={{
            fontSize: 20,
            marginBottom: 20,
            textAlign: "center",
            marginHorizontal: 15,
          }}
        >
          Example: Upload ImagePicker result
        </Text>
      )}

      <Button
        onPress={pickImage}
        title="Pick an image from camera roll"
      />

      <Button onPress={takePhoto} title="Take a photo" />

      {maybeRenderImage()}
      {maybeRenderUploadingOverlay()}

      <StatusBar barStyle="default" />
    </View>
  );

}
AndrewHenderson commented 2 years ago

The following works for me:

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

if (!result.cancelled) {
    const photoRef = await ref(storage, `Users/${user.id}.jpg`);
    const image = await fetch(result.uri);
    const bytes = await image.blob();
    const uploadTask = uploadBytesResumable(photoRef, bytes);

    uploadTask.on('state_changed',
        (snapshot) => {
            const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
            console.log('Upload is ' + progress + '% done');
            switch (snapshot.state) {
                case 'paused':
                    console.log('Upload is paused');
                    break;
                case 'running':
                    console.log('Upload is running');
                    break;
            }
        },
        (error) => {
            // Handle unsuccessful uploads
        },
        () => {
            getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
                console.log('File available at', downloadURL);
                setPhotoUrl(downloadURL);
            });
        }
    );
}

Switching to uploadBytesResumable got it working. I believe there is an issue with using uploadBytes. It might have something to do with using getDownloadURL outside of the callback. Doing so crashed my app, but it works perfectly in the callback, as shown.

AngelDev0329 commented 2 years ago

Yes, correct. it works when use uploadBytesResumable instead of uploadBytes.

Here is my code.


const storageRef = ref(storage, `${user.email}/photo`);
const response = await fetch(userImage);
const blob = await response.blob();
await uploadBytesResumable(storageRef, blob);
return await getDownloadURL(storageRef);```
edi commented 2 years ago

Not really. I’m using resumable as per the snippet above, still crashing. I see it has to do more with the size of the file than the actual code implementation.

I switched to base64 and file uploading directly to my backend server which then uploads to google’s storage.

On Fri, 15 Apr 2022 at 09:59, AngelDev727 @.***> wrote:

Yes, correct. it works when use uploadBytesResumable instead of uploadBytes.

Here is my code.

const storageRef = ref(storage, ${user.email}/photo); const response = await fetch(userImage); const blob = await response.blob(); await uploadBytesResumable(storageRef, blob); return await getDownloadURL(storageRef);```

— Reply to this email directly, view it on GitHub https://github.com/firebase/firebase-js-sdk/issues/5848#issuecomment-1099903880, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB23AZKA4CTVKBB6SJEL63TVFEHVFANCNFSM5LEGT2IQ . You are receiving this because you commented.Message ID: @.***>

-- Eduard Duluman Full Stack Developer

CEO - FLEXBOX SRL *C*TO - SWUP AS

Tel: +40 748 891 241 www.duluman.ro http://www.duluman.ro/

secondpathstudio commented 2 years ago

Thank you everyone for this thread, finally have pics uploading some of the time rather than none of the time! Still getting fairly common crashes on expo 44, firebase 9.6.11, using uploadBytesResumable with this code

`const uploadImage = async (imageUri, caption) => { //init storage const storage = getStorage(); const imgName = 'img-' + new Date().getTime();

    //create storage ref
    const storageRef = ref(storage, `images/${authCtx.uid}/${imgName}.jpg`)

    //get blob
    const img = await fetch(imageUri)
    const imgBlob = await img.blob()

    console.log('uploading file', imgName, imgBlob.size)

    //upload image
    const uploadTask = uploadBytesResumable(storageRef, imgBlob)

    uploadTask.on('state_changed',
        (snapshot) => {
            const progress = (snapshot.bytesTransferred/snapshot.totalBytes) * 100;
            console.log('upload is ' + progress + '% done.')
            switch(snapshot.state){
                case 'paused':
                    console.log('upload paused')
                    break;
                case 'running':
                    console.log('uploading...')
                    break;
            }
        },
        (error) => {
            switch (error.code){
                case 'storage/unauthorized':
                    console.log('user does not have permission');
                    break;
                case 'storage/canceled':
                    console.log('user canceled upload');
                    break;
                case 'storage/unknown':
                    console.log('unknown error ' + error.serverResponse)
                    break;
            }
        },
        () => {
            //successful upload
            getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
                console.log('file uploaded to ' + downloadURL)

                //call upload post function with url and caption
                uploadPost(downloadURL, caption)
            });
        }
    )
}`

Haven't been able to pinpoint a reliable reason for the crashes as sometimes a particular image will crash it but then it will work later...I put my imagePicker quality all the way down to 0.05 right now, maybe try lower lol...Definitely feels close to being fully functional though, so hoping I'm just missing something small!

AngelDev0329 commented 2 years ago

Hello. I have used this version firebase: 9.4.0 and expo 44.0. uploadBytesResumable is working successfully with this firebase version.