skip to Main Content

I’m trying to upload images on firebase storage using my expo app. I went through their documentation and tried to implement using the docs. but whenever I upload I don’t get any error but the image that appears on firebase is just a plain white box

Images uploaded to Firebase

1

Error when viewing the preview

2

This is my whole code

import React, { useState } from 'react';
import { Image, View, Text, Button, ActivityIndicator } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import { app } from './firebaseConfig';
import { getStorage, ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import 'firebase/storage'; 


const App = () => {
  const [image, setImage] = useState(null);
  const [uploading, setUploading] = useState(false);

  

  const pickImage = async () => {
    try {
      let result = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ImagePicker.MediaTypeOptions.Images,
        allowsEditing: true,
        aspect: [4, 3],
        quality: 1,
      });
      if (!result.canceled) {
        console.log(result.assets[0].uri)
        setImage(result.assets[0].uri);
      }
    } catch (E) {
      console.log(E);
    }
  };

const storage = getStorage(app);
  // Create the file metadata
/** @type {any} */
const metadata = {
  contentType: 'image/jpeg'
};

// Upload file and metadata to the object 'images/mountains.jpg'
const storageRef = ref(storage, 'images/' + Date.now());
const uploadTask = uploadBytesResumable(storageRef, image, metadata);

console.log(storageRef)
// 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) => {
    // 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);
    });
  }
);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Pick an image from camera roll" onPress={pickImage} />
      {image && (
        <>
          <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />
        </>
      )}
      {uploading && <ActivityIndicator />}
    </View>
  );
};

export default App;

2

Answers


  1. The URL path result.assets[0].uri returned by expo-image-picker is a reference to image data but not contains actual image data.

    As firebase expects to upload binary data, the app requires to fetch image binary data first.

    const getBlobFroUri = async (uri) => {
      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);
      });
    
      return blob;
    };
    
    const imageBlob = await getBlobFroUri(image)
    
    const uploadTask = uploadBytesResumable(storageRef, imageblob, metadata);
    
    

    I wrote an in-depth article on this subject – https://dev.to/emmbyiringiro/upload-image-with-expo-and-firebase-cloud-storage-3481

    Login or Signup to reply.
  2. Create a new file filename.js and paste this code. Import pickImage function to pick image from gallery and uploadImage to upload the image you picked. uploadImage has to parameters -> uri and path. uri is the value returned from pickImage function and path is the storage path where you want to store the image, eg: images/{Date.now()}_img.png.

    import * as ImagePicker from 'expo-image-picker';
    import firebase from 'firebase/app';
    import 'firebase/storage';
    
    export const pickImage = async() => {
        try{
            const result = await ImagePicker.launchImageLibraryAsync({
                mediaTypes: ImagePicker.MediaTypeOptions.Images,
                allowsEditing: true,
                aspect: [4,4],
                quality: 1,
                allowsMultipleSelection: false,
            });
            return result.canceled?null:result.assets[0].uri;
        }catch(e){
           throw e;
        }
    }
    
    export const uploadImage = async(uri, path) => {
        let URL;
        try{
            const response = await fetch(uri);
            const blob = await response.blob();
            const storageRef = firebase.storage().ref();
            const upload = storageRef.child(path);
            await upload.put(blob);
            await upload.getDownloadURL().then((url) => {
                URL = url;
            });
            return URL;
        }catch(e){
           throw e;
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search