0

I'm using React Native and Expo. I'm using the Expo image picker which returns a local URI to an image file. The URI returned looks like this: file:///data/user/0/com.myapp/cache/ExperienceData/%2540myapp%252Fmyapp/ImagePicker/c5a29113-7c8f-4224-99ec-007f641841ee.jpg

On iOS, I can use the React Native Fetch API to get the blob so I can upload it to S3 using the Amplify Storage Service. Everything works fine.

On Android, however, it does not work. The fetch command returns 1 rather than a response; there are no errors.

I can't use (well, don't want to use) rn-fetch-blob because my application is detached and the rn-fetch-blob needs to be patched to work with Expo 32.

Funny thing though ... if instead of using the image resizer's URI, I use an image URL from the network, it works on both Android and iOS. So, how do I use fetch on Android to return the contents of the local file from the Android image picker?

1 Answer 1

2

In my searching for a solution to this problem, I ran across this post. The explanation is pretty thorough. Here's the TL;DR . . .

As of RN 0.57, the polyfill they use for fetch doesn't default the xhr.responseType to blob anymore. The React Native for Android BlobModule checks the response type to determine if it can handle the URL when it's not an http or https request. Since the responseType is never 'blob', this module never handles the request, and a type error is thrown . . . on android . . . for file requests . . . through the whatwg-fetch.js polyfill . . . for RN 0.57+.

Based on the aforementioned post on the expo issue, I added this as a (hopefully) temporary solution.

requestBlob = (uri) => {
  return new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest();
    xhr.onload = () => resolve(xhr.response);
    xhr.onerror = () => reject(new TypeError('Network request failed'));
    xhr.responseType = 'blob';

    xhr.open('GET', uri, true);
    xhr.send(null);
  });
}

I'm saving my image like this:

  let body, storedImage;
  try {
    body = await requestBlob(localImageUri).catch(error => errors.push(error));
    storedImage = await Storage.put(path, body).catch(error => errors.push(error));
  } finally {
    body.close();
  }
Sign up to request clarification or add additional context in comments.

1 Comment

This worked as a charm for react-native 0.72.x, thanks. issue: github.com/facebook/react-native/issues/38625

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.