jamomani
jamomani

Reputation: 983

React Native - send image from local cache to firebase storage

With React Native on Android I am trying to send the image profile of the user from local cache to a firebase storage bucket. If I send it as blob or Uint8Array, when I open the image on firebase I get the error The image "https://firebasestorage<resto of url here>" cannot be displayed because it contain errors. If I send it as base64 data url,it does not upload to the bucket and I get the message Firebase Storage: String does not match format 'base64': Invalid character found. I have tested the base64 data url with a decoder and it works. How can I get this to work, either as blob, Uint8Array or base64?. Here is the code:

As blob

let mime = 'image/jpeg';
getFile(imageUri)
  .then(data => {
    return new Blob([data], { type: mime });
  })
  .then(blob => {
    return imageRef.put(blob, { contentType: mime });
  })

async function getFile(imageUri) {
  let bytes = await FileSystem.readAsStringAsync(imageUri);
  return Promise.resolve(bytes);
}

As Uin8Array

let mime = 'image/jpeg';
getFile(imageUri)
  .then(data => {
    return imageRef.put(data, { contentType: mime });
  })


async function getFile(imageUri) {
  let bytes = await FileSystem.readAsStringAsync(imageUri);
  const imageBytes = new Uint8Array(bytes.length);
  for ( let i = 0; i < imageBytes.length; i++) {
    imageBytes[i] = bytes.charCodeAt(i);
  }
  return Promise.resolve(imageBytes);
}

As base64 data url

imageBase64Url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAF0lEQVQI12P8//8/AwMDAwMDEwMMIFgAVCQDA25yGkkAAAAASUVORK5CYII=";
return imageRef.putString(imageBase64Url, 'data_url');

The URI

I retrieve the uri from this object:

Object {
    "cancelled": false,
    "height": 60,
    "type": "image",
    "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FMCC_Project-ee81e7bd-82b1-4624-8c6f-8c882fb131c4/ImagePicker/6ec14b33-d2ec-4f80-8edc-2ee501bf6e92.jpg",
    "width": 80,
 }

Upvotes: 3

Views: 1565

Answers (1)

jamomani
jamomani

Reputation: 983

We found at least two problems with the way I was trying to retrieve the picture and send it to the Firebase bucket:

1) When retrieving the image from memory and trying to send it as blob to the bucket, FileSystem.readAsStringAsync(imageUri) was returning for some reason a corrupted file

2) Instead when trying to save the image to Firebase bucket as base64, the problem seems to be with firebase, since not even the very same examples provided here https://firebase.google.com/docs/storage/web/upload-files were working.

The solution:

We retrieved the image from local cache with XMLHttpRequestinstead of Expo's FileSystem, and saved it to Firebase bucket as blob:

import React, { Component } from 'react';
import firebase from './firebase';

export default async function saveImage(picture, uid) {
  const storageRef = firebase
    .storage('gs://*<bucket-here>*')
    .ref(uid + '/' + 'profile-picture.jpeg');

  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', picture.uri, true);
    xhr.send(null);
  });

  const metadata = {
    contentType: 'image/jpeg',
  };

  return (downloadURL = await new Promise((resolve, reject) => {
    try {
      storageRef.put(blob, metadata).then(snapshot => {
        snapshot.ref.getDownloadURL().then(downloadURL => {
          resolve(downloadURL);
        });
      });
    } catch (err) {
      reject(err);
    }
  }));
}

Upvotes: 2

Related Questions