Code Monkey home page Code Monkey logo

rn-fetch-blob's Introduction

rn-fetch-blob

release npm npm

A project committed to making file access and data transfer easier and more efficient for React Native developers.

Version Compatibility Warning

rn-fetch-blob version 0.10.16 is only compatible with react native 0.60 and up. It should have been a major version bump, we apologize for the mistake. If you are not yet upgraded to react native 0.60 or above, you should remain on rn-fetch-blob version 0.10.15

Features

  • Transfer data directly from/to storage without BASE64 bridging
  • File API supports regular files, Asset files, and CameraRoll files
  • Native-to-native file manipulation API, reduce JS bridging performance loss
  • File stream support for dealing with large file
  • Blob, File, XMLHttpRequest polyfills that make browser-based library available in RN (experimental)
  • JSON stream supported base on Oboe.js @jimhigson

TOC (visit Wiki to get the complete documentation)

About

This project was started in the cause of solving issue facebook/react-native#854, React Native's lacks of Blob implementation which results into problems when transferring binary data.

It is committed to making file access and transfer easier and more efficient for React Native developers. We've implemented highly customizable filesystem and network module which plays well together. For example, developers can upload and download data directly from/to storage, which is more efficient, especially for large files. The file system supports file stream, so you don't have to worry about OOM problem when accessing large files.

In 0.8.0 we introduced experimental Web API polyfills that make it possible to use browser-based libraries in React Native, such as, FireBase JS SDK

Installation

Install package from npm

npm install --save rn-fetch-blob

Or if using CocoaPods, add the pod to your Podfile

pod 'rn-fetch-blob',
    :path => '../node_modules/rn-fetch-blob'

After 0.10.3 you can install this package directly from Github

# replace <branch_name> with any one of the branches
npm install --save github:joltup/rn-fetch-blob#<branch_name>

Manually Link Native Modules

If automatically linking doesn't work for you, see instructions on manually linking.

Automatically Link Native Modules

For projects 0.29.2 < 0.69.0 , simply link native packages via the following command (note: rnpm has been merged into react-native)

react-native link rn-fetch-blob

This link command no longer works for react-native 0.69.0+

As for projects < 0.29 you need rnpm to link native packages

rnpm link

You also might need add the following lines to AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.rnfetchblobtest"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />
+   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
    <intent-filter>
      <category android:name="android.intent.category.LAUNCHER" />
+     <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
    ...

For projects < 0.28

React Native has changed OkHttp version in 0.27, if your project is older than 0.28 you have to explicitly specify OkHttp version in node_modules/rn-fetch-blob/android/build.gradle

dependencies {
    implementation 'com.facebook.react:react-native:+'
+   implementation 'com.squareup.okhttp3:okhttp:3.4.1'
-   //{RNFetchBlob_PRE_0.28_DEPDENDENCY}
}

The link script might not take effect if you have non-default project structure, please visit the wiki to link the package manually.

Grant Permission to External storage for Android 5.0 or lower

The mechanism for granting Android permissions has slightly different since Android 6.0 released, please refer to Official Document.

If you're going to access external storage (say, SD card storage) for Android 5.0 (or lower) devices, you might have to add the following line to AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.rnfetchblobtest"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+   <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
    ...

Also, if you're going to use Android Download Manager you have to add this to AndroidManifest.xml

    <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
+           <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
    </intent-filter>

If you are going to use the wifiOnly flag, you need to add this to AndroidManifest.xml

+   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    ...

Grant Access Permission for Android 6.0

Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. So adding permissions in AndroidManifest.xml won't work for Android 6.0+ devices. To grant permissions in runtime, you might use PermissionAndroid API.

Usage

ES6

The module uses ES6 style export statement, simply use import to load the module.

import RNFetchBlob from "rn-fetch-blob";

ES5

If you're using ES5 require statement to load the module, please add default. See here for more detail.

var RNFetchBlob = require('rn-fetch-blob').default

HTTP Data Transfer

Regular Request

After 0.8.0 rn-fetch-blob automatically decides how to send the body by checking its type and Content-Type in the header. The rule is described in the following diagram

To sum up:

  • To send a form data, the Content-Type header does not matter. When the body is an Array we will set proper content type for you.
  • To send binary data, you have two choices, use BASE64 encoded string or path points to a file contains the body.
  • If the Content-Type containing substring;BASE64 or application/octet the given body will be considered as a BASE64 encoded data which will be decoded to binary data as the request body.
  • Otherwise, if a string starts with RNFetchBlob-file:// (which can simply be done by RNFetchBlob.wrap(PATH_TO_THE_FILE)), it will try to find the data from the URI string after RNFetchBlob-file:// and use it as the request body.
  • To send the body as-is, simply use a Content-Type header not containing ;BASE64 or application/octet.

It is Worth to mentioning that the HTTP request uses cache by default, if you're going to disable it simply add a Cache-Control header 'Cache-Control' : 'no-store'

After 0.9.4, we disabled Chunked transfer encoding by default, if you're going to use it, you should explicitly set header Transfer-Encoding to Chunked.

Download example: Fetch files that need authorization token

Most simple way is download to memory and stored as BASE64 encoded string, this is handy when the response data is small. Note that when it comes to authorization, not only can you use an authorization token, but this package will automatically pass the cookies created by normal js requests such as axios and fetch. Therefore, if you are using traditional cookie-based ways to authorize your user, you don't need to do anything before this package works.

// send http request in a new thread (using native code)
RNFetchBlob.fetch("GET", "http://www.example.com/images/img1.png", {
  Authorization: "Bearer access-token...",
  // more headers  ..
})
  .then((res) => {
    let status = res.info().status;

    if (status == 200) {
      // the conversion is done in native code
      let base64Str = res.base64();
      // the following conversions are done in js, it's SYNC
      let text = res.text();
      let json = res.json();
    } else {
      // handle other status codes
    }
  })
  // Something went wrong:
  .catch((errorMessage, statusCode) => {
    // error handling
  });

Download to storage directly

If the response data is large, that would be a bad idea to convert it into BASE64 string. A better solution is streaming the response directly into a file, simply add a fileCache option to config, and set it to true. This will make incoming response data stored in a temporary path without any file extension.

These files won't be removed automatically, please refer to Cache File Management

RNFetchBlob.config({
  // add this option that makes response data to be stored as a file,
  // this is much more performant.
  fileCache: true,
})
  .fetch("GET", "http://www.example.com/file/example.zip", {
    //some headers ..
  })
  .then((res) => {
    // the temp file path
    console.log("The file saved to ", res.path());
  });

Set Temp File Extension

Sometimes you might need a file extension for some reason. For example, when using file path as the source of Image component, the path should end with something like .png or .jpg, you can do this by add appendExt option to config.

RNFetchBlob.config({
  fileCache: true,
  // by adding this option, the temp files will have a file extension
  appendExt: "png",
})
  .fetch("GET", "http://www.example.com/file/example.zip", {
    //some headers ..
  })
  .then((res) => {
    // the temp file path with file extension `png`
    console.log("The file saved to ", res.path());
    // Beware that when using a file path as Image source on Android,
    // you must prepend "file://"" before the file path
    imageView = (
      <Image
        source={{
          uri:
            Platform.OS === "android"
              ? "file://" + res.path()
              : "" + res.path(),
        }}
      />
    );
  });

Use Specific File Path

If you prefer a particular file path rather than randomly generated one, you can use path option. We've added several constants in v0.5.0 which represents commonly used directories.

let dirs = RNFetchBlob.fs.dirs;
RNFetchBlob.config({
  // response data will be saved to this path if it has access right.
  path: dirs.DocumentDir + "/path-to-file.anything",
})
  .fetch("GET", "http://www.example.com/file/example.zip", {
    //some headers ..
  })
  .then((res) => {
    // the path should be dirs.DocumentDir + 'path-to-file.anything'
    console.log("The file saved to ", res.path());
  });

These files won't be removed automatically, please refer to Cache File Management

Upload example : Dropbox files-upload API

rn-fetch-blob will convert the base64 string in body to binary format using native API, this process is done in a separated thread so that it won't block your GUI.

RNFetchBlob.fetch(
  "POST",
  "https://content.dropboxapi.com/2/files/upload",
  {
    Authorization: "Bearer access-token...",
    "Dropbox-API-Arg": JSON.stringify({
      path: "/img-from-react-native.png",
      mode: "add",
      autorename: true,
      mute: false,
    }),
    "Content-Type": "application/octet-stream",
    // here's the body you're going to send, should be a BASE64 encoded string
    // (you can use "base64"(refer to the library 'mathiasbynens/base64') APIs to make one).
    // The data will be converted to "byte array"(say, blob) before request sent.
  },
  base64ImageString
)
  .then((res) => {
    console.log(res.text());
  })
  .catch((err) => {
    // error handling ..
  });

Upload a file from storage

If you're going to use a file as request body, just wrap the path with wrap API.

RNFetchBlob.fetch(
  "POST",
  "https://content.dropboxapi.com/2/files/upload",
  {
    // dropbox upload headers
    Authorization: "Bearer access-token...",
    "Dropbox-API-Arg": JSON.stringify({
      path: "/img-from-react-native.png",
      mode: "add",
      autorename: true,
      mute: false,
    }),
    "Content-Type": "application/octet-stream",
    // Change BASE64 encoded data to a file path with prefix `RNFetchBlob-file://`.
    // Or simply wrap the file path with RNFetchBlob.wrap().
  },
  RNFetchBlob.wrap(PATH_TO_THE_FILE)
)
  .then((res) => {
    console.log(res.text());
  })
  .catch((err) => {
    // error handling ..
  });

Multipart/form-data example: Post form data with file and data

In version >= 0.3.0 you can also post files with form data, just put an array in body, with elements have property name, data, and filename(optional).

Elements have property filename will be transformed into binary format, otherwise, it turns into utf8 string.

RNFetchBlob.fetch(
  "POST",
  "http://www.example.com/upload-form",
  {
    Authorization: "Bearer access-token",
    otherHeader: "foo",
    "Content-Type": "multipart/form-data",
  },
  [
    // element with property `filename` will be transformed into `file` in form data
    { name: "avatar", filename: "avatar.png", data: binaryDataInBase64 },
    // custom content type
    {
      name: "avatar-png",
      filename: "avatar-png.png",
      type: "image/png",
      data: binaryDataInBase64,
    },
    // part file from storage
    {
      name: "avatar-foo",
      filename: "avatar-foo.png",
      type: "image/foo",
      data: RNFetchBlob.wrap(path_to_a_file),
    },
    // elements without property `filename` will be sent as plain text
    { name: "name", data: "user" },
    {
      name: "info",
      data: JSON.stringify({
        mail: "[email protected]",
        tel: "12345678",
      }),
    },
  ]
)
  .then((resp) => {
    // ...
  })
  .catch((err) => {
    // ...
  });

What if you want to append a file to form data? Just like upload a file from storage example, wrap data by wrap API (this feature is only available for version >= v0.5.0). On version >= 0.6.2, it is possible to set custom MIME type when appending a file to form data. But keep in mind when the file is large it's likely to crash your app. Please consider use other strategy (see #94).

  RNFetchBlob.fetch('POST', 'http://www.example.com/upload-form', {
    Authorization : "Bearer access-token",
    otherHeader : "foo",
    // this is required, otherwise it won't be process as a multipart/form-data request
    'Content-Type' : 'multipart/form-data',
  }, [
    // append field data from file path
    {
      name : 'avatar',
      filename : 'avatar.png',
      // Change BASE64 encoded data to a file path with prefix `RNFetchBlob-file://`.
      // Or simply wrap the file path with RNFetchBlob.wrap().
      data: RNFetchBlob.wrap(PATH_TO_THE_FILE)
    },
    {
      name : 'ringtone',
      filename : 'ring.mp3',
      // use custom MIME type
      type : 'application/mp3',
      // upload a file from asset is also possible in version >= 0.6.2
      data : RNFetchBlob.wrap(RNFetchBlob.fs.asset('default-ringtone.mp3'))
    }
    // elements without property `filename` will be sent as plain text
    { name : 'name', data : 'user'},
    { name : 'info', data : JSON.stringify({
      mail : '[email protected]',
      tel : '12345678'
    })},
  ]).then((resp) => {
    // ...
  }).catch((err) => {
    // ...
  })

Upload/Download progress

In version >= 0.4.2 it is possible to know the upload/download progress. After 0.7.0 IOS and Android upload progress are also supported.

RNFetchBlob.fetch(
  "POST",
  "http://www.example.com/upload",
  {
    //... some headers,
    "Content-Type": "octet-stream",
  },
  base64DataString
)
  // listen to upload progress event
  .uploadProgress((written, total) => {
    console.log("uploaded", written / total);
  })
  // listen to download progress event
  .progress((received, total) => {
    console.log("progress", received / total);
  })
  .then((resp) => {
    // ...
  })
  .catch((err) => {
    // ...
  });

In 0.9.6, you can specify an object as the first argument which contains count and interval, to the frequency of progress event (this will be done in the native context a reduce RCT bridge overhead). Notice that count argument will not work if the server does not provide response content length.

RNFetchBlob.fetch(
  "POST",
  "http://www.example.com/upload",
  {
    //... some headers,
    "Content-Type": "octet-stream",
  },
  base64DataString
)
  // listen to upload progress event, emit every 250ms
  .uploadProgress({ interval: 250 }, (written, total) => {
    console.log("uploaded", written / total);
  })
  // listen to download progress event, every 10%
  .progress({ count: 10 }, (received, total) => {
    console.log("progress", received / total);
  })
  .then((resp) => {
    // ...
  })
  .catch((err) => {
    // ...
  });

Cancel Request

After 0.7.0 it is possible to cancel an HTTP request. Upon cancellation, it throws a promise rejection, be sure to catch it.

let task = RNFetchBlob.fetch('GET', 'http://example.com/file/1')

task.then(() => { ... })
    // handle request cancelled rejection
    .catch((err) => {
        console.log(err)
    })
// cancel the request, the callback function is optional
task.cancel((err) => { ... })

Drop-in Fetch Replacement

0.9.0

If you have existing code that uses whatwg-fetch(the official fetch), it's not necessary to replace them with RNFetchblob.fetch, you can simply use our Fetch Replacement. The difference between Official them is official fetch uses whatwg-fetch which wraps XMLHttpRequest polyfill under the hood. It's a great library for web developers, but does not play very well with RN. Our implementation is simply a wrapper of our fetch and fs APIs, so you can access all the features we provided.

See document and examples

Android Media Scanner, and Download Manager Support

If you want to make a file in External Storage becomes visible in Picture, Downloads, or other built-in apps, you will have to use Media Scanner or Download Manager.

Media Scanner

Media scanner scans the file and categorizes by given MIME type, if MIME type not specified, it will try to resolve the file using its file extension.

RNFetchBlob.config({
  // DCIMDir is in external storage
  path: dirs.DCIMDir + "/music.mp3",
})
  .fetch("GET", "http://example.com/music.mp3")
  .then((res) =>
    RNFetchBlob.fs.scanFile([{ path: res.path(), mime: "audio/mpeg" }])
  )
  .then(() => {
    // scan file success
  })
  .catch((err) => {
    // scan file error
  });

Download Manager

When downloading large files on Android it is recommended to use Download Manager, it supports a lot of native features like the progress bar, and notification, also the download task will be handled by OS, and more efficient.

When using DownloadManager, fileCache and path properties in config will not take effect, because Android DownloadManager can only store files to external storage, also notice that Download Manager can only support GET method, which means the request body will be ignored.

When download complete, DownloadManager will generate a file path so that you can deal with it.

RNFetchBlob.config({
  addAndroidDownloads: {
    useDownloadManager: true, // <-- this is the only thing required
    // Optional, override notification setting (default to true)
    notification: false,
    // Optional, but recommended since android DownloadManager will fail when
    // the url does not contains a file extension, by default the mime type will be text/plain
    mime: "text/plain",
    description: "File downloaded by download manager.",
  },
})
  .fetch("GET", "http://example.com/file/somefile")
  .then((resp) => {
    // the path of downloaded file
    resp.path();
  });

Your app might not have right to remove/change the file created by Download Manager, therefore you might need to set custom location to the download task.

Download Notification and Visibility in Download App (Android Only)

If you need to display a notification upon the file is downloaded to storage (as the above) or make the downloaded file visible in "Downloads" app. You have to add some options to config.

RNFetchBlob.config({
  fileCache : true,
  // android only options, these options be a no-op on IOS
  addAndroidDownloads : {
    // Show notification when response data transmitted
    notification : true,
    // Title of download notification
    title : 'Great ! Download Success ! :O ',
    // File description (not notification description)
    description : 'An image file.',
    mime : 'image/png',
    // Make the file scannable  by media scanner
    mediaScannable : true,
  }
})
.fetch('GET', 'http://example.com/image1.png')
.then(...)

Open Downloaded File with Intent

This is a new feature added in 0.9.0 if you're going to open a file path using official Linking API that might not work as expected, also, if you're going to install an APK in Downloads app, that will not function too. As an alternative, you can try actionViewIntent API, which will send an ACTION_VIEW intent for you which uses the given MIME type.

Download and install an APK programmatically

const android = RNFetchBlob.android;

RNFetchBlob.config({
  addAndroidDownloads: {
    useDownloadManager: true,
    title: "awesome.apk",
    description: "An APK that will be installed",
    mime: "application/vnd.android.package-archive",
    mediaScannable: true,
    notification: true,
  },
})
  .fetch("GET", `http://www.example.com/awesome.apk`)
  .then((res) => {
    android.actionViewIntent(
      res.path(),
      "application/vnd.android.package-archive"
    );
  });

Or show an image in image viewer

android.actionViewIntent(PATH_OF_IMG, "image/png");

File System

File Access

File access APIs were made when developing v0.5.0, which helping us write tests, and was not planned to be a part of this module. However, we realized that it's hard to find a great solution to manage cached files, everyone who uses this module may need these APIs for their cases.

Before start using file APIs, we recommend read Differences between File Source first.

File Access APIs

See File API for more information

File Stream

In v0.5.0 we've added writeStream and readStream, which allows your app read/write data from the file path. This API creates a file stream, rather than convert entire data into BASE64 encoded string. It's handy when processing large files.

When calling readStream method, you have to open the stream, and start to read data. When the file is large, consider using an appropriate bufferSize and interval to reduce the native event dispatching overhead (see Performance Tips)

The file stream event has a default throttle(10ms) and buffer size which preventing it cause too much overhead to main thread, yo can also tweak these values.

let data = ''
RNFetchBlob.fs.readStream(
    // file path
    PATH_TO_THE_FILE,
    // encoding, should be one of `base64`, `utf8`, `ascii`
    'base64',
    // (optional) buffer size, default to 4096 (4095 for BASE64 encoded data)
    // when reading file in BASE64 encoding, buffer size must be multiples of 3.
    4095)
.then((ifstream) => {
    ifstream.open()
    ifstream.onData((chunk) => {
      // when encoding is `ascii`, chunk will be an array contains numbers
      // otherwise it will be a string
      data += chunk
    })
    ifstream.onError((err) => {
      console.log('oops', err)
    })
    ifstream.onEnd(() => {
      <Image source={{ uri : 'data:image/png,base64' + data }}
    })
})

When using writeStream, the stream object becomes writable, and you can then perform operations like write and close.

Since version 0.10.9 write() resolves with the RNFetchBlob instance so you can promise-chain write calls:

RNFetchBlob.fs
  .writeStream(
    PATH_TO_FILE,
    // encoding, should be one of `base64`, `utf8`, `ascii`
    "utf8",
    // should data append to existing content ?
    true
  )
  .then((ofstream) => ofstream.write("foo"))
  .then((ofstream) => ofstream.write("bar"))
  .then((ofstream) => ofstream.write("foobar"))
  .then((ofstream) => ofstream.close())
  .catch(console.error);

or

RNFetchBlob.fs
  .writeStream(
    PATH_TO_FILE,
    // encoding, should be one of `base64`, `utf8`, `ascii`
    "utf8",
    // should data append to existing content ?
    true
  )
  .then((stream) =>
    Promise.all([
      stream.write("foo"),
      stream.write("bar"),
      stream.write("foobar"),
    ])
  )
  // Use array destructuring to get the stream object from the first item of the array we get from Promise.all()
  .then(([stream]) => stream.close())
  .catch(console.error);

You should NOT do something like this:

RNFetchBlob.fs
  .writeStream(
    PATH_TO_FILE,
    // encoding, should be one of `base64`, `utf8`, `ascii`
    "utf8",
    // should data append to existing content ?
    true
  )
  .then((ofstream) => {
    // BAD IDEA - Don't do this, those writes are unchecked:
    ofstream.write("foo");
    ofstream.write("bar");
    ofstream.close();
  })
  .catch(console.error); // Cannot catch any write() errors!

The problem with the above code is that the promises from the ofstream.write() calls are detached and "Lost". That means the entire promise chain A) resolves without waiting for the writes to finish and B) any errors caused by them are lost. That code may seem to work if there are no errors, but those writes are of the type "fire and forget": You start them and then turn away and never know if they really succeeded.

Cache File Management

When using fileCache or path options along with fetch API, response data will automatically store into the file system. The files will NOT removed unless you unlink it. There're several ways to remove the files

// remove file using RNFetchblobResponse.flush() object method
RNFetchblob.config({
  fileCache: true,
})
  .fetch("GET", "http://example.com/download/file")
  .then((res) => {
    // remove cached file from storage
    res.flush();
  });

// remove file by specifying a path
RNFetchBlob.fs.unlink("some-file-path").then(() => {
  // ...
});

You can also group requests by using session API and use dispose to remove them all when needed.

  RNFetchblob.config({
    fileCache : true
  })
  .fetch('GET', 'http://example.com/download/file')
  .then((res) => {
    // set session of a response
    res.session('foo')
  })

  RNFetchblob.config({
    // you can also set session beforehand
    session : 'foo'
    fileCache : true
  })
  .fetch('GET', 'http://example.com/download/file')
  .then((res) => {
    // ...
  })

  // or put an existing file path to the session
  RNFetchBlob.session('foo').add('some-file-path')
  // remove a file path from the session
  RNFetchBlob.session('foo').remove('some-file-path')
  // list paths of a session
  RNFetchBlob.session('foo').list()
  // remove all files in a session
  RNFetchBlob.session('foo').dispose().then(() => { ... })

Transfer Encoding

After 0.9.4, the Chunked transfer encoding is disabled by default due to some service provider may not support chunked transfer. To enable it, set Transfer-Encoding header to Chunked.

RNFetchBlob.fetch(
  "POST",
  "http://example.com/upload",
  { "Transfer-Encoding": "Chunked" },
  bodyData
);

Self-Signed SSL Server

By default, rn-fetch-blob does NOT allow connection to unknown certification provider since it's dangerous. To connect a server with self-signed certification, you need to add trusty to config explicitly. This function is available for version >= 0.5.3

RNFetchBlob.config({
  trusty: true,
})
  .fetch("GET", "https://mysite.com")
  .then((resp) => {
    // ...
  });

WiFi only requests

If you wish to only route requests through the Wifi interface, set the below configuration. Note: On Android, the ACCESS_NETWORK_STATE permission must be set, and this flag will only work on API version 21 (Lollipop, Android 5.0) or above. APIs below 21 will ignore this flag.

RNFetchBlob.config({
  wifiOnly: true,
})
  .fetch("GET", "https://mysite.com")
  .then((resp) => {
    // ...
  });

Web API Polyfills

After 0.8.0 we've made some Web API polyfills that makes some browser-based library available in RN.

  • Blob
  • XMLHttpRequest (Use our implementation if you're going to use it with Blob)

Here's a sample app that uses polyfills to upload files to FireBase.

Performance Tips

Read Stream and Progress Event Overhead

If the process seems to block JS thread when file is large when reading data via fs.readStream. It might because the default buffer size is quite small (4kb) which result in a lot of events triggered from JS thread. Try to increase the buffer size (for example 100kb = 102400) and set a larger interval (available for 0.9.4+, the default value is 10ms) to limit the frequency.

Reduce RCT Bridge and BASE64 Overhead

React Native connects JS and Native context by passing JSON around React Native bridge, and there will be an overhead to convert data before they sent to each side. When data is large, this will be quite a performance impact to your app. It's recommended to use file storage instead of BASE64 if possible.The following chart shows how much faster when loading data from storage than BASE64 encoded string on iPhone 6.

ASCII Encoding has /terrible Performance

Due to the lack of typed array implementation in JavascriptCore, and limitation of React Native structure, to convert data to JS byte array spends lot of time. Use it only when needed, the following chart shows how much time it takes when reading a file with different encoding.

Concat and Replacing Files

If you're going to concatenate files, you don't have to read the data to JS context anymore! In 0.8.0 we introduced new encoding uri for writeFile and appendFile API, which make it possible to handle the whole process in native.

Caveats

  • This library does not urlencode unicode characters in URL automatically, see #146.
  • When you create a Blob , from an existing file, the file WILL BE REMOVED if you close the blob.
  • If you replaced window.XMLHttpRequest for some reason (e.g. make Firebase SDK work), it will also affect how official fetch works (basically it should work just fine).
  • When file stream and upload/download progress event slow down your app, consider an upgrade to 0.9.6+, use additional arguments to limit its frequency.
  • When passing a file path to the library, remove file:// prefix.

when you got a problem, have a look at Trouble Shooting or issues labeled Trouble Shooting, there'd be some helpful information.

Changes

See release notes

Development

If you're interested in hacking this module, check our development guide, there might be some helpful information. Please feel free to make a PR or file an issue.

rn-fetch-blob's People

Contributors

adbl avatar alaskalany avatar alpha0010 avatar ankit-eclat avatar ataillefer avatar atlanteh avatar bcpclone avatar cristianocca avatar ericmorgan1 avatar follower avatar gla5001 avatar hhravn avatar ihavenoface5 avatar jbrodriguez avatar jrapala avatar kejinliang avatar lionesstester avatar lll000111 avatar maxpowa avatar mbarbon avatar milesmatthias avatar mjmasn avatar nadav2051 avatar nluzzato avatar pedramsaleh avatar rpenfold avatar smartt avatar traviskn avatar vunyunt avatar wkh237 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rn-fetch-blob's Issues

`react-native link` hangs when react-native-fetch-blob is a dependency

Hello!

  • please provide the version of installed library and RN project.

[email protected]
[email protected]

I've tried this on both node 6 and 8.

  • a sample code snippet/repository
✗ react-native link
Scanning folders for symlinks in /home/brandon/src/DocentReact/node_modules (5ms)
rnpm-install info Platform 'ios' module react-native-background-timer is already linked
rnpm-install info Platform 'android' module react-native-background-timer is already linked
rnpm-install info Platform 'android' module react-native-billing is already linked
rnpm-install info Platform 'ios' module react-native-blur is already linked
rnpm-install info Platform 'android' module react-native-blur is already linked
rnpm-install info Platform 'ios' module react-native-device-info is already linked
rnpm-install info Platform 'android' module react-native-device-info is already linked
RNFetchBlob checking app version ..
RNFetchBlob detected app version => 0.55
Add Android permissions => false
react-native-fetch-blob will not automatically add Android permissions after 0.9.4 please run the following command if you want to add default permissions :

        RNFB_ANDROID_PERMISSIONS=true react-native link

rnpm-install info Platform 'ios' module react-native-fetch-blob is already linked
rnpm-install info Platform 'android' module react-native-fetch-blob is already linked
rnpm-install info Platform 'ios' module react-native-maps is already linked
rnpm-install info Platform 'android' module react-native-maps is already linked
rnpm-install info Platform 'ios' module react-native-sound is already linked
rnpm-install info Platform 'android' module react-native-sound is already linked
rnpm-install info Platform 'ios' module react-native-svg is already linked
rnpm-install info Platform 'android' module react-native-svg is already linked
rnpm-install info Platform 'ios' module react-native-view-overflow is already linked
rnpm-install info Platform 'android' module react-native-view-overflow is already linked
rnpm-install info Linking assets to ios project
rnpm-install info Linking assets to android project
rnpm-install info Assets have been successfully linked to your project
<--- must press enter here to continue

Removing react-native-fetch-blob as a dependency does not produce this behavior.

How can I get the content file?

Using react-native-document-picker I'm getting the file and trying do upload to my api. So I would like to know how can I read the file, convert to do base64 and send it.

This is how I'm trying to read the file, but i always return only the path, not the content.

// const file = base64.encode(RNFetchBlob.fs.asset(filename))
// const file = base64.encode(filename)
// const file = await RNFetchBlob.fs.readFile(filename, 'base64')
// const file = base64.encode(await RNFetchBlob.fs.readFile(filename, 'binary'))

const { fs, fetch, wrap } = RNFetchBlob
const file = fs.asset(filename)
bundle-assets://content://com.android.providers.downloads.documents/document/431/pexels-photo-267151.jpeg

Wha could I be missing?

"base-64": "^0.1.0",
"react-native": "^0.48.4",
"react-native-fetch-blob": "^0.10.8",
"react-native-document-picker": "^2.1.0",

Redundant switch cases in polyfill/Fetch.js

For example Link

function readText(resp, info):Promise<string> {
  switch (info.rnfbEncode) {
    **case 'base64':**
      return Promise.resolve(resp.text())
      break
    case 'path':
      return resp.text()
      break
    default:
      return Promise.resolve(resp.text())
      break
  }
}

The base64 case is not special and can be treated as default. Is there any special reason to make it a standalone case?

How to upload PDF file to dropbox or google drive in React Native?

Hi,

First of all thanks for creating this plugin. I have integrated this plugin and now the thing is I want to upload PDF file to Dropbox as well as Google Drive.

I am able to get access token. But not able to upload pdf file to google drive or Dropbox. I know I am missing some steps. Below is my code that I have implemented.

REQUEST :-
RNFetchBlob.fetch('POST', 'https://www.googleapis.com/upload/drive/v3?uploadType=media', {
Authorization : user.accessToken,
'data': JSON.stringify({
path : "http://xyz.com/" + this.state.pdf,
mode : 'add',
autorename : true,
mute : false
}),
'Content-Type' : 'application/pdf',
})
.then((res) => {
console.log("response in success " + JSON.stringify(res));

  })
  .catch((err) => {
    console.log("response in error " + JSON.stringify(err));
    // error handling ..
  })

It will give below response inside success.

RESPONSE :-

response in success {"data":"Not Found","taskId":"njehngge5xm4hl33iynfog","type":"utf8","respInfo":{"respType":"","headers":{"alt-svc":"hq=":443"; ma=2592000; quic=51303432; quic=51303431; quic=51303339; quic=51303335,quic=":443"; ma=2592000; v="42,41,39,35"","server":"UploadServer","date":"Fri, 23 Mar 2018 06:50:13 GMT","content-length":"9","content-type":"text/html; charset=UTF-8","vary":"X-Origin","x-guploader-uploadid":"AEnB2UrlSTCFYVYabN_dzHqqr55dBKjosk8u0IQ3D4bcysJyp_KkaYSW4yrE2P4gziHgfKOUrZpfAxaSpBwV6D4-a0142hiYhA"},"redirects":["https://www.googleapis.com/upload/drive/v3?uploadType=media"],"timeout":false,"taskId":"njehngge5xm4hl33iynfog","state":"2","status":404,"rnfbEncode":"utf8"}}

Pleas help. I am stuck in this from past few days. Let me know if this is not sufficient information for you.

Thanks

The SDK Build Tools revision (23.0.1) is too low for project ':react-native-fetch-blob'. Minimum required is 25.0.0

Hi!
i would like to report this problem and ans know how solve it.

"dependencies": {
"expo": "^25.0.0",
"react": "16.2.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-25.0.0.tar.gz",
"react-native-fetch-blob": "^0.10.8",
"humps": "^2.0.1",
"react-native-image-preview": "^0.3.1",
"react-native-keyboard-aware-scroll-view": "^0.4.1",
"react-native-modal-datetime-picker": "^4.13.0",
"react-native-modal-selector": "^0.0.21",
"react-navigation": "^1.0.0-beta.19",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-logic": "^0.12.3",
"redux-persist": "^5.4.0"
}

when I execute my project it gives this error.

  • What went wrong:
    A problem occurred configuring project ':app'.

Could not resolve all dependencies for configuration ':app:_devRemoteKernelDebugApk'.
A problem occurred configuring project ':react-native-fetch-blob'.
> The SDK Build Tools revision (23.0.1) is too low for project ':react-native-fetch-blob'. Minimum required is 25.0.0

compileSdkVersion 25
buildToolsVersion "25.0.0"

and i get this error.

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':react-native-fetch-blob:compileDebugJavaWithJavac'.

Compilation failed; see the compiler error output for details.

Thank you very much in advance.

With the plugin upload files on Android, leading the entire page operation becomes is too laggy

Hi ! Thank you for reporting an issue, but we would like to remind you, we have a trouble shooting page in our wiki.
You may want to take a look on that page or find issues tagged "trouble shooting" :p

  • please provide the version of installed library and RN project.
  • a sample code snippet/repository is very helpful to spotting the problem.
  • issues which have been tagged as 'needs feedback', will be closed after 2 weeks if receive no feedbacks.
  • issues lack of detailed information will be closed without any feedback

iOS:App Store

After updating and installing from the App Store, the pictures downloaded to the local area are missing and cannot be displayed.

Android: error: package okhttp3 does not exist import okhttp3.MediaType;

My android build is failing with this error.

/node_modules/react-native-fetch-blob/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobDefaultResp.java:14: error: package okhttp3 does not exist
import okhttp3.MediaType;

Environment:
OS: macOS Sierra 10.12.6
Node: 8.1.4
Yarn: 1.7.0
npm: 5.8.0
Watchman: 4.7.0
Xcode: Xcode 9.2 Build version 9C40b
Android Studio: 2.3 AI-162.4069837

Packages: (wanted => installed)
react: 16.3.0 => 16.3.0
react-native: 0.54.4 => 0.54.4

"react-native-fetch-blob": "^0.10.8",

How do I get this building again? Thanks!

error: duplicate declaration of method 'requiresMainQueueSetup'

On version 0.10.9, requiresMainQueueSetup is declared twice in this file and will throw the error

error: duplicate declaration of method 'requiresMainQueueSetup'

Seems this was introduced on the latest commit for 0.10.9 branch.
614ef56#diff-0b97a2df65bc9a2753599b4d88da3475R45

Lines in question:

https://github.com/joltup/react-native-fetch-blob/blob/614ef561dda7b837e896e175f8719fb42232bede/ios/RNFetchBlob/RNFetchBlob.m#L45

https://github.com/joltup/react-native-fetch-blob/blob/614ef561dda7b837e896e175f8719fb42232bede/ios/RNFetchBlob/RNFetchBlob.m#L77

File size reported from fs.stat does not match uploaded file size

It seems that RNFetchBlob is uploading an uncompressed version of the file. Is there a way to make RNFetchBlob either report the uncompressed size or better yet, upload the file that was stat'ed?

RN: 0.54
RNFB: 0.10.8
iOS 11 (Simulator and device)

let clip.uri = assets-library://asset/asset.JPG?id=9DC79222-EC93-45CA-9891-5D91AEDC5F7C&ext=JPG

let fd = new FormData()
let stats = await RNFetchBlob.fs.stat(clip.uri)
fileSize = stats.size
fileObj = {
	uri: clip.uri,
	type: clip.type,
	name: clip.name,
	filename: clip.name,
	data: RNFetchBlob.wrap(clip.uri),
}
fileuploadlist.push(fileObj)
fd.append(fileSize + "_" + timestamp, fileObj)

let localOptions = {
	method: "POST",
	headers: {
		"Content-Type": undefined,
		Accept: "application/json",
	},
	body: fd,
	file: fileuploadlist
}
try {
	return fetch(url, localOptions, callback)
} catch (e) {}

}

reported file size from fs.stat === 178,849 bytes
actual uploaded file size === 395,394 bytes

"The file does not downloaded to destination"

Hi there,

I am using the npm installed version of RN Fetch Blob - 0.10.8, and react native 0.51.

I am doing a download from firebase cloud storage using the generated links (meaning there is no cookies/auth headers etc required, it's just an anonymized URL, that looks something like: https://firebasestorage.googleapis.com/v0/b/{APP_NAME}.appspot.com/o/{DIR}%2F{SUB_DIR}%2F{SUB_DIR}%2F{SOME_FILENAME}.{EXTENSION}?alt=media&token={SOME_TOKEN}). The file in question is a pdf, for what it is worth.

The code I am using to download the file on android looks like so (typescript):

function download(url: string,
                  fileName: string,
                  mime?: string,
                  options?: Partial<RNFetchBlobConfig>,
                  androidDownloadOptions?: Partial<AddAndroidDownloads>): StatefulPromise<FetchBlobResponse> {
  const path: string = withTrailingSlash(fetchBlob.fs.dirs.DownloadDir) + fileName;

  console.log('download path: ', path);

  return fetchBlob
    .config({
      addAndroidDownloads: {
        useDownloadManager: true,
        notification: true,
        title: fileName,
        description: 'PDF Download',
        mediaScannable: true,
        path: path,
        mime,
        ...androidDownloadOptions
      },
      ...options
    }).fetch('GET', url);
}

The file name passed into the download function is generated with (new Date()).toISOString() to prevent collisions, so the logged download path ends up looking like: /storage/emulated/0/Download/FileName-2018-04-12T01:24:31.219Z.pdf

This works fine on my emulator (Android 7.0), but on one of my colleagues physical devices, it exhibits a strange behaviour:

It downloads fine (the file exists and can be seen and opened either with a file management app or the download manager), however it also throws the exception from https://github.com/joltup/react-native-fetch-blob/blob/master/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java#L675 . From my understanding of the context of this code, it is checking after the download if the file now exists, so I guess for some reason it is not showing up even if it is there?

The device this occurs with is a LG-H860, also running Android 7.0.

Any thoughts? Apparently I am the only one in the world experiencing this issue at this point, so I must have done something pretty boneheaded in my implementation XD

Can't download from https source on Adnroid

Do I do something wrong? When I use the same code for https://www.rhodeshouse.ox.ac.uk/media/1002/sample-pdf-file.pdf or whatever else pdf on https I have 0,00b/0,00b on my notifications panel and download is stopped and connection is in progress all the time.

var url  = "http://www.africau.edu/images/default/sample.pdf";
    const { config, fs } = RNFetchBlob
    let PictureDir = fs.dirs.PictureDir
    let options = {
      fileCache: true,
      addAndroidDownloads : {
        useDownloadManager : true,
        notification : true,
        path:  PictureDir + "/example.pdf",
      }
    }
    config(options).fetch('GET', url).then((res) => {
      Alert.alert("Done");
    });

"react": "16.2.0",
"react-native": "0.54.2",
"react-native-fetch-blob": "^0.10.8"

The result text is cut off

I have open file with size 1 MB with readstream. Actually its content have more than thousand of words, but the text displayed is only 518 words. How to solve this? Thanks ^^

Android: App crashes when getExternalFilesDir() returns null

Hi,

I noticed that sometimes getExternalFilesDir() returns null, and then the app crashes.

Java exception in 'NativeModules' java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File java.io.File.getParentFile()' on a null object reference, stack: com.RNFetchBlob.RNFetchBlobFS.getSystemfolders@216 com.RNFetchBlob.RNFetchBlob.getConstants@84 com.facebook.react.bridge.JavaModuleWrapper.getConstants@140 android.os.Handler.handleCallback@751 android.os.Handler.dispatchMessage@95 com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage@31

I can reproduce it when I'm on Android 4.3 or below, but in production (we have an app with +/- 1 million installs) we hit this error on all kind of Android versions.

Best,
Nicolas

ios method 'excludeFromBackupKey' is missing from documentation and types

The method still exists (https://github.com/joltup/react-native-fetch-blob/blob/master/ios.js#L41), it's just missing from the wiki documentation (https://github.com/joltup/react-native-fetch-blob/wiki/iOS-API) and the typescript definitions (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-native-fetch-blob/index.d.ts).

Since there's already a jsdoc comment I'm assuming adding docs wouldn't be too arduous, but I'm not sure I'm the best person to fix it - I'm running across it being used in some old code but don't quite understand why it would be used.

Upload error: data missing although data is being passed in?

Version: ^0.10.8
react-native-audio : ^4.1.3
react-native : 0.55.3
react : 16.3.1

In trying to upload a native sound file from storage, I encounter the following error:

code: '106'
detail: 'The required parameter, data, is missing.'
status: '400'
title: 'Missing Parameter'

I'm making my request like so:

export function uploadRecording(filePath, email, token) {
  return (dispatch) => {
   
    const audioPath = filePath.replace('file://', '');

    RNFetchBlob.fetch('POST', `${Endpoints.host}/${Endpoints.root}/attachments`, {
      'X-USER-EMAIL': email,
      'X-USER-TOKEN': token,
      'Content-Type': 'multipart/form-data',
    }, [
     
      {
        name: 'soundfile', filename: 'test.aac', type: 'audio', data: RNFetchBlob.wrap(audioPath),
      },
    ]).then((resp) => {
      console.log(resp.json());
    }).catch((err) => {
      handleApiError(err, dispatch);
    });
  };
}

When I log out the audioPath, the file path displays. Is this error referring to data that should be passed in elsewhere?

Edit: I am trying to post this in JSON format, as that is what my server requires. I modified the request to reflect that, but the app crashes and no error is provided when I do that:

RNFetchBlob.fetch('POST', `${Endpoints.host}/${Endpoints.root}/attachments`, {
      type: 'attachments',
      'Content-Type': 'multipart/form-data',
      headers: {
        'X-USER-EMAIL': email,
        'X-USER-TOKEN': token,
        'Content-Type': 'multipart/form-data',
      },
      attributes: {
        attachable_type: 'audio',
        attachment_data: RNFetchBlob.wrap(audioPath),
      },
    }, [
      // element with property `filename` will be transformed into `file` in form data
      {
        name: 'attachment', filename: 'test.aac', type: 'audio', data: RNFetchBlob.wrap(audioPath),
      },
    ]).then((resp) => {
      console.log({ resp });
      recordingUploaded();
    }).catch((err) => {
      handleApiError(err, dispatch);
    });

Please return to the error code when `catch`

Thank you guys for bringing us such a good tool, but I hope that some places can be improved. When I entered catch, I found that no standard statusCode returned when there was no network and canceled requests, so I hoped that if it was a HTTP error, it would return the error code of the HTTP error, if it was to cancel a request and return a statusCode to distinguish what was wrong, thank you guys, most. Good blessings.

For example

RNFetchBlob.fetch("GET","http://test.test",{},{})
    .catch(function(err,statusCode){
        //I hope that the `statusCode` here returns every time and returns the wrong code according to the different errors.
    })

Is the project active?

The project was taken from @wkh237 over two months ago but to be honest it seems as inactive as the parent project - no response on issues, no new commits, no merged pull requests.

Are there any plans to actually improve the project?

RNFetchBlob.fs.stat size of directory is incorrect

Hi ! I met an error When in use RNFetchBlob.fs.stat couldn't get correct size of directory. I want to get whole directory RNFetchBlob.fs.dirs.CacheDir's size, which contain cached images by react-native-img-cache. But get wrong data, directory size smaller than file or sub-directory.

Versions

"react": "^16.0.0",
"react-native": "^0.50.0",
"react-native-fetch-blob": "^0.10.8",

Code

    RNFetchBlob.fs.stat(RNFetchBlob.fs.dirs.CacheDir)
      .then((stats) => {
        console.log(stats);
        if (stats && stats.size) {
          this.setState({ cacheSize: stats.size });
        }
      })
      .catch(() => { });
    RNFetchBlob.fs.stat(`${RNFetchBlob.fs.dirs.CacheDir}/react-native-img-cache`)
      .then((stats) => {
        console.log(stats);
      })
      .catch(() => { });
    RNFetchBlob.fs.stat(`${RNFetchBlob.fs.dirs.CacheDir}/react-native-img-cache/7393ba9b6f2f1b0e379e2c7ebf219b515d85f666.jpg`)
      .then((stats) => {
        console.log(stats);
      })
      .catch(() => { });

But Print Result

image

Anything wrong in my code? Or I need traverse all cache sub-directory and calculate directory and files' size?

logging/ debugging

Hi ! Thank you for reporting an issue, but we would like to remind you, we have a trouble shooting page in our wiki.
You may want to take a look on that page or find issues tagged "trouble shooting" :p

  • please provide the version of installed library and RN project.
    0.10.8

Is there a simple way to log request and responses? what I am looking for is kind of debugging information where I can output requests as curl and also easily show responses perhaps ?

Invoke would be called more than once during cp call

RNFetchBlob version: 0.10.8
The code raises a java.lang.RuntimeException: Illegal callback invocation from native module. This callback type only permits a single invocation from native code. when cp errors but successfully closes its streams.
That is already existed in the old repository and had a PR: wkh237#408
But now it is still here.

plan for npm publishing?

Now that this has been officially forked, is there a plan to publish updates on npm? Is there a way to gain collaborator access on npm to publish under the same package name?

Performance for older android phones

I am wondering if anyone else is experiencing performance issues on older android devices (more than likely 2015 and older). it seems to take forever to upload blobs with these devices and no time at all with more modern ones and especially no issues with iPhones.

Just wondering if we can look into general performance.

Thank you!

ES6 import breaks, but dynamic require during runtime works

Hi there! I've also posted this issue at the main repo.

I've installed RNFetchBlob in my first RN project, and have encountered a weird issue. To install, I did:

1. yarn add react-native-fetch-blob
2. react-native link react-native-fetch-blob

I then removed my Pods and build dirs out of ios, did a fresh install, and launched the simulator. I got this yellowbox warning, but besides that everything seemed alright.

My use case is this: checking image file size after a Share Extension calls back to the main application with an image URI.

In short, this code does not work:

import RNFetchBlob from 'react-native-fetch-blob'

export default async (images) => {

  images.forEach(async (image) => {

    RNFetchBlob.fs.stat(image.value)
      .then((stats) => console.log('stats: ', stats))
      .catch((err) => { })

  ...etc

But, this code does:

export default async (images) => {

  const RNFetchBlob = require('react-native-fetch-blob').default

  images.forEach(async (image) => {

    RNFetchBlob.fs.stat(image.value)
      .then((stats) => console.log('stats: ', stats))
      .catch((err) => { })

Any idea why this would be the case? It seems the RNFetchBlob module is available at runtime but not app startup, or something like that? For the first snippet of code, my ShareExtension itself crashes, and the main app is not even opened. The error messages are not verbose enough to be helpful:

: assertion failed: 17D102: launchd_sim + 63203 [73626DE2-C6D1-3394-9991-3E928BFE8F25]: 0x16

I assume this is down to some incorrect installation, but I have no idea why I can only import the module during runtime.

Crucially, this is not down to ES6/ES5 import style. If I move const RNFetchBlob = require('react-native-fetch-blob').default above the function scope so that it is run immediately and not when the function is invoked, again the entire application breaks.

Outdated classes description in Wiki page

Example 1:
The documentation for RNFetchBlobResponse states:

FetchBlobResponse object has the following methods (these method are synchronous, so you might take quite a performance impact if the file is big)

But in fact, the code clearly says that the text() function can return a Promise when the rnfbEncode is 'path'.
This line
text : () => string | Promise<any>;

Example 2:
The documentation for RNFetchBlobResponseInfo has rnfbEncode rnfbEncode : 'path' | 'base64' | 'utf8'
But in code, the rnfbEncode can also have 'ascii'.
This line
rnfbEncode : 'path' | 'base64' | 'ascii' | 'utf8'

I'm not sure if the Wiki is outdated or text function should actually be a sync function.
Thanks.

Provide better documentation for accessing asset files

In my quest to access files I bundle with my app I have read the documentation here and here and found this SO article here. I think the lack of answers to that article

The documentation only supplies an example for Android and their assets. On what level do I insert aaptOptions in build.gradle? What about iOS? What about accessing regular files the usual way through require('<myapp/myassets/...')? Is it impossible? Bad practice? I would love to find the answers to these questions in the wiki

Advice on Embedding PDF content to HTML

Hello,

I need to fetch the application/pdf content returned by a rest service and embed the content in React Frame.

When I invoked rest call using fetch I get a 403 (forbidden). I just happened to see this open source project.

Could you please provide me a sample fetch API code that processes data received from rest api which produced "application/pdf"

Thanks
Sara

Hi ! Thank you for reporting an issue, but we would like to remind you, we have a trouble shooting page in our wiki.
You may want to take a look on that page or find issues tagged "trouble shooting" :p

  • please provide the version of installed library and RN project.
  • a sample code snippet/repository is very helpful to spotting the problem.
  • issues which have been tagged as 'needs feedback', will be closed after 2 weeks if receive no feedbacks.
  • issues lack of detailed information will be closed without any feedback

file downloads, but it shows 0 byte size using "Download Notification and Visibility in Download App (Android Only)"

Hi ! Thank you for reporting an issue, but we would like to remind you, we have a trouble shooting page in our wiki.
You may want to take a look on that page or find issues tagged "trouble shooting" :p

  • please provide the version of installed library and RN project.
  • a sample code snippet/repository is very helpful to spotting the problem.
  • issues which have been tagged as 'needs feedback', will be closed after 2 weeks if receive no feedbacks.
  • issues lack of detailed information will be closed without any feedback

RNFetchBlob error when sending request: timeout

Hi ,
When I am trying to download file using below code:

RNFetchBlob.config({
  path: tmpPath
})
.fetch('GET', url, { Range: 'bytes=' + previousFileSize + '-' })
.then((resp) => {

  return this.appendFile(resp.path(), PicPath, 'nostats').then((stats1) => {  <<== This function appends data to the old file as it used for resumable download
  })
})
.then(() => {
  resolve({ path: 'file://' + PicPath });
})
.catch((e) => {
  resolve(false);
})

But when network is slow, the time out occurs. And it shows the error message in the application screen.

untitled

So my question is how to handle this error in code.
And I think all such exceptions should be handled in code.

@wkh237 Please help

Can't get stats about a video saved in the camera roll ios

Hi,

After recording a video I save it in the camera roll using CameraRoll.saveToCameraRoll. Using the response from CameraRoll.saveToCameraRoll (the response looks like this on ios: asset-library://asset/asset.mov) I'm trying to get information about the file with RNFetchBlob.fs.stat(response), but on ios it give an error (Error: failed to stat path, could not resolve URI). On android it works perfectly.

How can I fix this?

Environment

OS: mac OS High Sierra 10.13.4
Node: 10.0.0
Yarn: 1.6.0
npm: 5.6.0
Watchman: 4.9.0
Xcode: Xcode 9.3 Build version 9E145
Android Studio: 3.0 AI-171.4443003
react: 16.2.0
react-native: 0.52.0
react-native-fetch-blob: 0.10.8

Podfile version is 0.10.6

Hi, I just noticed that podspec specifies 0.10.6 while package is 0.10.8.
Does it have any consequences or podspec version doesn't matter?

URI - No such file or directory

I am using react-native-fetch-blob with a detached Expo app. I get this error: RNFetchBlob failed to create single content request body :error when getting request stream: No such file or directory.

I only get this problem in my expo version of the project

My file path is:

RNFetchBlob-file://file:///data/user/0/com.flyreel.underwriterbot/cache/ExperienceData/%2540darkwata%252Fflyreel/Camera/967785f9-064f-44e2-9277-6d6650d76fe7.mp4

I'm on Android btw.

package.json:

"react-native-fetch-blob": "^0.10.8",

Seems like its a problem with the %2540 and %252F encoding in the file path which Expo uses.

what's the use of this class RNFetchBlobFS in android application??

Hi ! Thank you for reporting an issue, but we would like to remind you, we have a trouble shooting page in our wiki.
You may want to take a look on that page or find issues tagged "trouble shooting" :p

  • please provide the version of installed library and RN project.
  • a sample code snippet/repository is very helpful to spotting the problem.
  • issues which have been tagged as 'needs feedback', will be closed after 2 weeks if receive no feedbacks.
  • issues lack of detailed information will be closed without any feedback

Inconsistent behavior when cancelling request with range header (ios vs. android)

react-native-cli: 2.0.1
react-native: 0.51.0
RNFetchBlob: 0.10.8

So when downloading something like so:

task = RNFetchBlob.config({
      path: dest,
      overwrite: false,
      IOSBackgroundTask: true,
      indicator: true,
    }).fetch('GET', url, {
      Range: `bytes=${size}-`,
    });
task.then(handleSuccess)
  .catch(handleError)

and then calling task.cancel(), I observe different behavior on iOS vs android.

iOS:
handleError(err) gets called where err.message === 'cancelled'. So this is nicely catcheable.

android:
handleSuccess(success) is called, where success has a HTTP code 206, which suggests that the range request was satisfied? It looks exactly like the response I get when the request finished successfully. Here is the content of respInfo, and it is the same whether I cancel the task or not:

headers: [
Accept-Ranges: "bytes"
Content-Length: "20177379"
Content-Range: "bytes 0-20177378/20177379"
Content-Type: "audio/mp3"
Date: "Fri, 04 May 2018 08:39:03 GMT"
ETag: ""...""
Last-Modified: "Tue, 12 Dec 2017 13:36:08 GMT"
Server: "AmazonS3"
x-amz-id-2: "..."
x-amz-request-id: "..."
]
redirects: ["https://s3-eu-west-1.amazonaws.com/.../efaaa2177b5f494390896e70d5444837.mp3"]
respType:  ""
rnfbEncode: "path"
state: "2"
status: 206
taskId: "jwy3rlqv5rkr1deb205f4p"
timeout: false

Any takes on why this happens?

RNFetchBlob.wrap(image.path) uploads JSON not file

I'm using

var blob = new Blob( [RNFetchBlob.wrap(image.path)] , {
type: 'image'
});

To upload to Amazon S3 from iOS. But this uploads JSON data rather than the file itself (i.e. 160 bytes!). Any ideas?

{"_data":{"blobId":"3dce8216-b17a-4423-beda-ecf4f189ad14","offset":0,"size":160,"type":"binary/octet-stream"}}

not able to create new directory in the device

hello,
i am newbie to RN , And I want to create a new directory and a file with in directory on devices to store my app information .
i have written the below code but but i couldn't find any DIR in the device.

kindly response on this, thanks in advance.
// TO CREATE DIR
const { config, fs } = RNFetchBlob;
const PElogs = "PElogs"; // dir name to create
RNFetchBlob.fs.mkdir(PElogs) .then(() => console.log(" Dir Created "))

// TO CREATE A FILE IN DIR
fs.createFile(PElogs + "/LogsFromHome" + ".txt", 'foo', 'utf8');
RNFetchBlob.fs.writeFile(PElogs + "/LogsFromHome" + ".txt", 'Created Dir And File ', 'utf8')
.then(() => { })

// MY SYSTEM CONFIGS
version of RN is: 0.50.3
react-native-cli: 2.0.1
os: windows-7, 64-bit , 8GB RAM.

Read file in node_modules

Hi,

I'm trying to read a file from node_modules to be able to inject it to a webview.
But I am not able to get the right path from fs.readFile() to access node_modules.

I tried a relative or absolute path but it is not working:

RNFetchBlob.fs
      .readFile("./node_modules/epubjs/dist/epub.min.js", "utf8")
      .then(data => { // handle data })
RNFetchBlob.fs
      .readFile(__dirname + "/node_modules/epubjs/dist/epub.min.js", "utf8")
      .then(data => { // handle data })

RN: 0.55.4
RNFetchBlob: 0.10.8

Thanks!

Failed to open target file, no such file or directory when file exists on directory

I'm downloading a file from a server and saving it to the downloads directory on Android with the name test.bin. On a File Manager app, I can see the file was successfully saved to the directory. Also, when using the File System API to check if the file exists with
RNFetchBlob.fs.exists('storage/emulated/0/Download/test.bin').then(exist => console.log(`file${exist ? '' : ' not'} exists`));, it returns that the file indeed exists.

The problem is when trying to make a request to send this file to another place with a multipart/form, like:

RNFetchBlob.fetch('POST', SERVER_URL, {
            'Content-Type': 'multipart/form-data'
        }, [
            {
                name: 'name',
                data: 'test'
            },
            {
                name: 'filename',
                data: 'tmp/test.bin'
            },
            {
                name: 'filedata',
                type: 'application/macbinary',
                data: RNFetchBlob.wrap(storage/emulated/0/Download/test.bin)
            }
        ])
            .then(res => {
                console.log('response => ', res);
            })
            .catch(e => console.log('ERROR => ', e));

I got an error on the response with a message: Failed to open target file, No such file or directory.

react-native: 0.51.0
react-native-fetch-blob: ^0.10.8

Android: Deprecation warnings about SDCardDir and SDCardApplicationDir

Branch: 0.10.9

Just calling the following code:

import RNFetchBlob from 'react-native-fetch-blob';

const url = http://my.server.com/my/upload/API;
const headers = { Authorization: 'Bearer xxxxxxxxx' };
const body = RNFetchBlob.wrap('file:///storage/emulated/0/Android/data/some/local/file');
const res = await RNFetchBlob.fetch('POST', url, headers, body);

generates the following warnings in the Android logs:

W ReactNativeJS: SDCardDir as a constant is deprecated and will be removed in feature release. Use RNFetchBlob.android.getSDCardDir():Promise instead.
W ReactNativeJS: SDCardApplicationDir as a constant is deprecated and will be removed in feature release. Use RNFetchBlob.android.getSDCardApplicationDir():Promise instead. This variable can be empty on error in native code.

These warnings have been added by 22fd32a but apparently there are still some occurrences of SDCardDir and SDCardApplicationDir in the code of the 0.10.9 branch.

I'm aware that the 0.10.9 branch isn't stable yet but it is intended to be released with a bunch of bug fixes so I believe that these warnings should be fixed before the release.

Thanks

RNFB_ANDROID_PERMISSIONS=true react-native link

RNFB_ANDROID_PERMISSIONS=true react-native link
When I enter this command then getting this error.

RNFB_ANDROID_PERMISSIONS=true : The term 'RNFB_ANDROID_PERMISSIONS=true' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1

  • RNFB_ANDROID_PERMISSIONS=true
  •   + CategoryInfo          : ObjectNotFound: (RNFB_ANDROID_PERMISSIONS=true:String) [], CommandNotFoundException
      + FullyQualifiedErrorId : CommandNotFoundException
    

Thanks in advance.

Crash when downloading large file, even when downloading directly to file

Not sure if this is a bug or if I'm doing something wrong but I'm getting the following crash when downloading a large file (96MB)

04-30 12:00:18.972 13006 13059 E AndroidRuntime: FATAL EXCEPTION: pool-1-thread-1
04-30 12:00:18.972 13006 13059 E AndroidRuntime: Process: net.cozic.joplin, PID: 13006
04-30 12:00:18.972 13006 13059 E AndroidRuntime: java.lang.OutOfMemoryError: Failed to allocate a 257944612 byte allocation with 4190304 free bytes and 160MB until OOM
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at java.lang.StringFactory.newStringFromBytes(StringFactory.java:185)
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at java.lang.StringFactory.newStringFromBytes(StringFactory.java:63)
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at android.util.Base64.encodeToString(Base64.java:456)
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at com.RNFetchBlob.RNFetchBlobFS.readFile(RNFetchBlobFS.java:174)
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at com.RNFetchBlob.RNFetchBlob$6.run(RNFetchBlob.java:208)
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
04-30 12:00:18.972 13006 13059 E AndroidRuntime:        at java.lang.Thread.run(Thread.java:761)
04-30 12:00:18.975  1705  3755 W ActivityManager:   Force finishing activity net.cozic.joplin/.MainActivity

It seems to crash on Base64 decoding which appears to be expected, however I'm setting the config so that it downloads directly to a file, so my understanding is that base64 decoding should not happen:

return RNFetchBlob.config({
	path: localFilePath
}).fetch(method, url, headers);

Any idea what am I might be doing wrong or how to avoid this crash?

I'm using fetch-blob 0.10.6 and RN 0.49.

Tried to access a JS module before the React instance was fully set up

  • please provide the version of installed library and RN project.

[email protected] through [email protected].
[email protected]

Our app use react-native-cached-image to cache a bunch of images. Some are proloaded early on, when the app is rendered the first time.

Sometimes when the app starts, perhaps after a code-push, we get the error message below logged to Fabric. The app crashes.

I am pretty sure it only happens after a code-push is downloaded and the new js-app is restarted, but I'm not sure. It does not happen every time though, seems pretty rare, like 1/100 times a code-push is applied.

(https://github.com/Microsoft/react-native-code-push)

Fatal Exception: java.lang.RuntimeExceptionTried to access a JS module before the React instance was fully set up. Calls to ReactContext#getJSModule should only happen once initialize() has been called on your native module. Raw Text
--
  | com.facebook.react.bridge.ReactContext.getJSModule (ReactContext.java:105)
  | com.RNFetchBlob.RNFetchBlobReq.emitStateEvent (RNFetchBlobReq.java:627)
  | com.RNFetchBlob.RNFetchBlobReq.done (RNFetchBlobReq.java:455)
  | com.RNFetchBlob.RNFetchBlobReq.access$100 (RNFetchBlobReq.java:60)
  | com.RNFetchBlob.RNFetchBlobReq$3.onResponse (RNFetchBlobReq.java:423)
  | okhttp3.RealCall$AsyncCall.execute (RealCall.java:135)
  | okhttp3.internal.NamedRunnable.run (NamedRunnable.java:32)
  | java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1133)
  | java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:607)
  | java.lang.Thread.run (Thread.java:776)

Any ideas?

File sometimes empty when using `fileCache: true`

We use the library to retrieve authenticated images like this:

import RNFetchBlob from 'react-native-fetch-blob'

RNFetchBlob
  .config({ fileCache: true })
  .fetch('GET', url, { Authorization: `Bearer ${token}` })
  .then(res => {
      console.log('path: ', res.path())
  })

Usually this works fine but sometimes the path which is returned leads to a 0 byte file instead of the actual file (for the same URL). I have confirmed on the local filesystem with the simulator but this seems to be happening on physical devices as well.

Using version 0.10.8 on React/RN 16.2/0.53

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.