npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-native-blob-courier

v5.0.2

Published

Use this library to efficiently download and upload blobs in React Native

Downloads

214

Readme

react-native-blob-courier

License: MPL 2.0 Build

Use this library to efficiently download and upload data in React Native. The library was inspired by rn-fetch-blob, and is focused strictly on http file transfers.

Installation

Install using yarn

yarn add react-native-blob-courier

Or install using npm

npm install react-native-blob-courier

Requirements

  • Android >= 24
  • Android Gradle Plugin >= 7.5.1
  • iOS >= 13.0
  • JDK >= 11
  • React Native >= 0.69.x

Note: you may have success with earlier versions of React Native but these are neither tested nor supported.

Usage

The library provides both a fluent and a more concise interface. In the examples the concise approach is applied; fluent interface is demonstrated later in this document.

Straightforward down- and upload

import BlobCourier from 'react-native-blob-courier';

// ...

// Download a file
const request0 = {
  filename: '5MB.zip',
  method: 'GET',
  mimeType: 'application/zip',
  url: 'http://ipv4.download.thinkbroadband.com/5MB.zip',
};

const fetchedResult = await BlobCourier.fetchBlob(request0);
console.log(fetchedResult);
// {
//   "data": {
//     "absoluteFilePath": "/path/to/app/cache/5MB.zip",
//     "response": {
//       "code":200,
//       "headers": {
//         "some_header": "some_value",
//         ...
//       }
//     },
//   },
//   "type":"Unmanaged"
// }

// ...

// Upload a file
const absoluteFilePath = fetchedResult.data.absoluteFilePath;

const request1 = {
  absoluteFilePath,
  method: 'POST',
  mimeType: 'application/zip',
  url: 'https://file.io',
};

const uploadResult = await BlobCourier.uploadBlob(request1);

console.log(uploadResult):
// {
//   "response": {
//     "code": {
//     "data": "<some response>",
//     "headers": {
//       "some_header": "some_value",
//        ...
//      }
//   }
// }

// Multipart file upload
const absoluteFilePath = fetchedResult.data.absoluteFilePath;

const request2 = {
  method: 'POST',
  parts: {
    body: {
      payload: 'some_value',
      type: 'string',
    },
    file: {
      payload: {
        absoluteFilePath,
        mimeType: 'application/zip',
      },
      type: 'file',
    },
  },
  url: 'https://file.io',
};

const multipartUploadResult = await BlobCourier.uploadBlob(request1);

console.log(multipartUploadResult):
// {
//   "response": {
//     "code": {
//     "data": "<some response>",
//     "headers": {
//       "some_header": "some_value",
//        ...
//      }
//   }
// }

Transfer progress reporting

import BlobCourier from 'react-native-blob-courier';

// ...

// Download a file
const request0 = {
  // ...
  onProgress: ((e: BlobProgressEvent) => {
    console.log(e)
    // {
    //  "written": <some_number_of_bytes_written>,
    //  "total": <some_total_number_of_bytes>
    // }
  })
};

const fetchedResult = await BlobCourier.fetchBlob(request0);

// ...

// Upload a file
const request1 = {
  // ...
  onProgress: ((e: BlobProgressEvent) => {
    console.log(e)
    // {
    //  "written": <some_number_of_bytes_written>,
    //  "total": <some_total_number_of_bytes>
    // }
  })
};

const uploadResult = await BlobCourier.uploadBlob(request1)

// ...

// Set progress updater interval
const request2 = ...

const someResult =
  await BlobCourier
    .fetchBlob({
      ...request2,
      progressIntervalMilliseconds: 1000,
    });

Managed download on Android (not available on iOS)

import BlobCourier from 'react-native-blob-courier';

// ...

const request = {
  android: {
    useDownloadManager: true // <--- set useDownloadManager to "true"
  },
  filename: '5MB.zip',
  method: 'GET',
  mimeType: 'application/zip',
  url: 'http://ipv4.download.thinkbroadband.com/5MB.zip',
};

const fetchResult = await BlobCourier.fetchBlob(request);

console.log(fetchedResult);
// {
//   "data": {
//     "result": "SUCCESS",
//     "absoluteFilePath": "/path/to/app/cache/5MB.zip"
//   },
//   "type":"Managed"
// }

Multipart upload

Sometimes order of multipart fields matters, and Blob Courier respects the order in which parts are provided. There is a catch though: due to how JavaScript works, when object keys are regular strings they are kept in the order they were added unless the keys are strings containing numbers, e.g.:

Object.keys({
  "b": "some_value1",
  "c": "some_value2",
  "a": "some_value3",
})

// ['b', 'c', 'a']

Object.keys({
  "b": "some_value1",
  "c": "some_value2",
  "a": "some_value3",
  "3": "some_value4",
  "2": "some_value5",
  "1": "some_value6",
});

// ['1', '2', '3', 'b', 'c', 'a']

The way to work around this, is to wrap all keys in a Symbol, by using Symbol.for. Do not use Symbol(<value>), this will not work, e.g.:

Object.getOwnPropertySymbols({
  [Symbol.for("b")]: "some_value1",
  [Symbol.for("c")]: "some_value2",
  [Symbol.for("a")]: "some_value3",
  [Symbol.for("3")]: "some_value4",
  [Symbol.for("2")]: "some_value5",
  [Symbol.for("1")]: "some_value6",
});

// [Symbol('b'), Symbol('c'), Symbol('a'), Symbol('3'), Symbol('2'), Symbol('1')]

Cancel request

import BlobCourier from 'react-native-blob-courier';

// ...

const abortController = new AbortController();

const { signal } = abortController;

const request0 = {
  // ...
  signal,
};

try {
  BlobCourier.fetchBlob(request0);

  abortController.abort();
} catch (e) {
  if (e.code === ERROR_CANCELED_EXCEPTION) {
    // ...
  }
}

// ...

Fluent interface

Blob Courier provides a fluent interface, that both protects you from using impossible setting combinations and arguably improves readability.

const req0 = ...

const someResult =
  await BlobCourier
    .settings({
      progressIntervalMilliseconds: 1000,
    })
    .onProgress((e: BlobProgressEvent) => {
      // ...
    })
    .useDownloadManagerOnAndroid({
      description: "Some file description",
      enableNotification: true,
      title: "Some title"
    })
    .fetchBlob(req0)

Available methods

fetchBlob(input: BlobFetchRequest)

Required

| Field | Type | Description | | ---------- | -------- | ------------------------------------------------------------------- | | filename | string | The name the file will have on disk after fetch. | | mimeType | string | What is the mime type of the blob being transferred? | | url | string | From which url will the blob be fetched? |

Optional

| Field | Type | Description | Default | | ------------ | -------------------------------- | ----------------------------------------- | ---------------------------------------------------- | | android | AndroidSettings | Settings to be used on Android | { downloadManager: {}, target: 'cache', useDownloadManager: false } | | ios | IOSSettings | Settings to be used on iOS | { target: 'cache' } | | headers | { [key: string]: string } | Map of headers to send with the request | {} | | method | string | Representing the HTTP method | GET | | onProgress | (e: BlobProgressEvent) => void | Function handling progress updates | () => { } | | signal | AbortSignal | Request cancellation manager | null |

Response

| Field | Type | Description | | --------- | -------------------------------------- | --------------------------------------------------------------------- | | type | "Managed" \| "Unmanaged" | Was the blob downloaded through Android Download Manager, or without? | | data | BlobManagedData \| BlobUnmanagedData | Either managed or HTTP response data |

uploadBlob(input: BlobUploadRequest)

Alias for:

const someResult =
  await BlobCourier
   // ...
   .uploadParts({
     headers,
     method,
     parts: {
       file:
         payload: {
           absoluteFilePath,
           filename,
           mimeType,
         },
         type: 'file',
       },
     },
     returnResponse,
     url,
   })

Required

| Field | Type | Description | | ------------------ | -------- | -------------------------------------------------------- | | absoluteFilePath | string | Path to the file to be uploaded | | mimeType | string | Mime type of the blob being transferred | | url | string | Url to upload the blob to |

Optional

| Field | Type | Description | Default | | ---------------- | -------------------------------- | ----------------------------------------- | ----------------------------------- | | filename | string | Name of the file on disk | <name part of 'absoluteFilePath'> | | headers | { [key: string]: string } | Map of headers to send with the request | {} | | method | string | The HTTP method to be used in the request | "POST" | | multipartName | string | Name for the file multipart | "file" | | onProgress | (e: BlobProgressEvent) => void | Function handling progress updates | () => { } | | returnResponse | boolean | Return the HTTP response body? | false | | signal | AbortSignal | Request cancellation manager | null |

uploadParts(input: BlobMultipartUploadRequest)

Required

| Field | Type | Description | | ------------------ | ---------------------------------- | --------------------------| | parts | { [key: string]: BlobMultipart } | The parts to be sent | | url | string | Url to upload the blob to |

Optional

| Field | Type | Description | Default | | ---------------- | -------------------------------- | ----------------------------------------- | ----------- | | headers | { [key: string]: string } | Map of headers to send with the request | {} | | method | string | The HTTP method to be used in the request | "POST" | | onProgress | (e: BlobProgressEvent) => void | Function handling progress updates | () => { } | | returnResponse | boolean | Return the HTTP response body? | false | | signal | AbortSignal | Request cancellation manager | null |

Response

| Field | Type | Description | | --------- | ---------------------------- | ----------------- | | response | BlobUnmanagedHttpResponse | The HTTP response |

AndroidDownloadManagerSettings

| Field | Type | Description | | --------------------- | ----------| -------------------------------------------- | | description? | string | Description of the downloaded file | | enableNotification? | boolean | Display notification when download completes | | title? | string | Title to be displayed with the download |

AndroidSettings

| Field | Type | Description | | -------------------- | -------------------------------- | --------------------------------------- | | downloadManager | AndroidDownloadManagerSettings | Settings to be used on download manager | | target | "cache" \| "data" | Where will the file be stored? | | useDownloadManager | boolean | Enable download manager on Android? |

BlobManagedData

| Field | Type | Description | | ------------------ | ------------------------ | --------------------------------------------------- | | absoluteFilePath | string | The absolute file path to where the file was stored | | result | "SUCCESS" \| "FAILURE" | Was the request successful or did it fail? |

BlobMultipart

Required

| Field | Type | Description | | ---------- | ---------------------------------------------------- | -------------------------------- | | payload | BlobMultipartFormData \| BlobMultipartFormDataFile | Contains the payload of the part | | type | "string" \| "file" | What is the type of the payload? |

BlobMultipartFormData

Type of string | { [key:string] : any }

BlobMultipartFormDataFile

Required

| Field | Type | Description | | ------------------ | -------- | -------------------------------------------------------- | | absoluteFilePath | string | Path to the file to be uploaded | | mimeType | string | Mime type of the blob being transferred |

Optional

| Field | Type | Description | Default | | ---------------- | ---------| ----------------------------------------- | ----------------------------------- | | filename | string | Name of the file on disk | <name part of 'absoluteFilePath'> |

BlobProgressEvent

| Field | Type | Description | | --------- | ---------| ------------------------------------- | | written | number | Number of bytes processed | | total | number | Total number of bytes to be processed |

BlobUnmanagedData

| Field | Type | Description | | ------------------ | --------------------------- | --------------------------------------------------- | | absoluteFilePath | string | The absolute file path to where the file was stored | | response | BlobUnmanagedHttpResponse | HTTP response, including headers and status code |

BlobUnmanagedHttpResponse

| Field | Type | Description | | --------- | --------------------------- | --------------------- | | code | number | HTTP status code | | headers | { [key: string]: string } | HTTP response headers |

IOSSettings

| Field | Type | Description | | -------------------- | -------------------------------- | --------------------------------------- | | target | "cache" \| "data" | Where will the file be stored? |

Example app

You can find an example of how to use the library in the example directory.

Android

Permissions

Android 5.1 and below (API level < 23)

Add the following line to AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" (...)>

+   <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" />
    (...)
    <application (...)>
      <activity (...)>
        <intent-filter>
          (...)
+          <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
        </intent-filter>
    (...)

Android 6.0+ (API level 23+)

Grant permissions using the PermissionAndroid API, like so:

const function App = () => {

  // ...

  React.useEffect(() => {
    const requestPermissionAsync = async () => {
      try {
        await PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
        );

        // ...
      } catch (err) {
        console.error(err);
      }

      // ...
    };

    requestPermissionAsync();
  }, []);

  // ...

iOS

Add to Info.plist of your app:

<key>NSAllowsArbitraryLoads</key>
<true/>

Using the integrated download manager for Android

This library allows you to use the integrated download manager on Android, this option is not available for iOS.

To enable the download manager, simply set the request's useDownloadManager property of field android to true when passing it to fetchBlob, or call the useDownloadManagerOnAndroid method when using the fluent interface.

Shared directories

As this library is focused on transferring files, it only supports storage to the app's cache and data directories. To move files from these app specific directories to other locations on the filesystem, use another library like @react-native-community/cameraroll, e.g.:

import BlobCourier from 'react-native-blob-courier';
import CameraRoll from '@react-native-community/cameraroll';

// ...

const request = {
  filename: 'teh_cage640x360.png',
  method: 'GET',
  mimeType: 'image/png',
  url: 'https://www.placecage.com/640/360',
};

const cageResult = await BlobCourier.fetchBlob(request)

const cageLocalPath = cageResult.data.absoluteFilePath

CameraRoll.save(cageLocalPath);

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

Code of Conduct

Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

License

MPL-2.0