Implement Blob support for XMLHttpRequest

Summary:
This PR is a followup to https://github.com/facebook/react-native/pull/11417 and should be merged after that one is merged.

  1. Add support for creating blobs from strings, not just other blobs
  1. Add the `File` constructor which is a superset of `Blob`
  1. Add the `FileReader` API which can be used to read blobs as strings or data url (base64)
  1. Add support for uploading and downloading blobs via `XMLHttpRequest` and `fetch`
  1. Add ability to download local files on Android so you can do `fetch(uri).then(res => res.blob())` to get a blob for a local file (iOS already supported this)

  1. Clone the repo https://github.com/expo/react-native-blob-test
  1. Change the `package.json` and update `react-native` dependency to point to this branch, then run `npm install`
  1. Run the `server.js` file with `node server.js`
  1. Open the `index.common.js` file and replace `localhost` with your computer's IP address
  1. Start the packager with `yarn start` and run the app on your device

If everything went well, all tests should pass, and you should see a screen like this:

![screen shot 2017-06-08 at 7 53 08 pm](https://user-images.githubusercontent.com/1174278/26936407-435bbce2-4c8c-11e7-9ae3-eb104e46961e.png)!

Pull to rerun all tests or tap on specific test to re-run it

  [GENERAL] [FEATURE] [Blob] - Implement blob support for XMLHttpRequest
Closes https://github.com/facebook/react-native/pull/11573

Reviewed By: shergin

Differential Revision: D6082054

Pulled By: hramos

fbshipit-source-id: cc9c174fdefdfaf6e5d9fd7b300120a01a50e8c1
This commit is contained in:
Satyajit Sahoo
2018-01-26 09:06:14 -08:00
committed by Facebook Github Bot
parent 3fc33bb54f
commit be56a3efee
40 changed files with 2060 additions and 386 deletions

View File

@@ -14,6 +14,7 @@
const Blob = require('Blob');
const EventTarget = require('event-target-shim');
const NativeEventEmitter = require('NativeEventEmitter');
const BlobManager = require('BlobManager');
const NativeModules = require('NativeModules');
const Platform = require('Platform');
const WebSocketEvent = require('WebSocketEvent');
@@ -147,19 +148,20 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
throw new Error('binaryType must be either \'blob\' or \'arraybuffer\'');
}
if (this._binaryType === 'blob' || binaryType === 'blob') {
const BlobModule = NativeModules.BlobModule;
invariant(BlobModule, 'Native module BlobModule is required for blob support');
if (BlobModule) {
if (binaryType === 'blob') {
BlobModule.enableBlobSupport(this._socketId);
} else {
BlobModule.disableBlobSupport(this._socketId);
}
invariant(BlobManager.isAvailable, 'Native module BlobModule is required for blob support');
if (binaryType === 'blob') {
BlobManager.addWebSocketHandler(this._socketId);
} else {
BlobManager.removeWebSocketHandler(this._socketId);
}
}
this._binaryType = binaryType;
}
get binaryType(): ?BinaryType {
return this._binaryType;
}
close(code?: number, reason?: string): void {
if (this.readyState === this.CLOSING ||
this.readyState === this.CLOSED) {
@@ -176,9 +178,8 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
}
if (data instanceof Blob) {
const BlobModule = NativeModules.BlobModule;
invariant(BlobModule, 'Native module BlobModule is required for blob support');
BlobModule.sendBlob(data, this._socketId);
invariant(BlobManager.isAvailable, 'Native module BlobModule is required for blob support');
BlobManager.sendOverSocket(data, this._socketId);
return;
}
@@ -212,6 +213,10 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
} else {
WebSocketModule.close(this._socketId);
}
if (BlobManager.isAvailable && this._binaryType === 'blob') {
BlobManager.removeWebSocketHandler(this._socketId);
}
}
_unregisterEvents(): void {
@@ -231,7 +236,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
data = base64.toByteArray(ev.data).buffer;
break;
case 'blob':
data = Blob.create(ev.data);
data = BlobManager.createFromOptions(ev.data);
break;
}
this.dispatchEvent(new WebSocketEvent('message', { data }));