Skip to content

wifi only option, and missing typings. #497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ rn-fetch-blob version 0.10.16 is only compatible with react native 0.60 and up.

## About

This project was started in the cause of solving issue [facebook/react-native#854](https://github.com/facebook/react-native/issues/854), React Native's lacks of `Blob` implementation which results into problems when transferring binary data.
This project was started in the cause of solving issue [facebook/react-native#854](https://github.com/facebook/react-native/issues/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.

Expand Down Expand Up @@ -116,8 +116,8 @@ If you're going to access external storage (say, SD card storage) for `Android 5

<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.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
...

Expand All @@ -129,10 +129,18 @@ Also, if you're going to use `Android Download Manager` you have to add this to
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
+ <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`

```diff
+ <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](https://facebook.github.io/react-native/docs/permissionsandroid.html).
Expand Down Expand Up @@ -168,7 +176,7 @@ 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.
- 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`.

Expand All @@ -189,7 +197,7 @@ RNFetchBlob.fetch('GET', 'http://www.example.com/images/img1.png', {
})
.then((res) => {
let status = res.info().status;

if(status == 200) {
// the conversion is done in native code
let base64Str = res.base64()
Expand Down Expand Up @@ -290,7 +298,7 @@ RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
'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.
// The data will be converted to "byte array"(say, blob) before request sent.
}, base64ImageString)
.then((res) => {
console.log(res.text())
Expand Down Expand Up @@ -648,7 +656,7 @@ RNFetchBlob.fs.readStream(
ifstream.onError((err) => {
console.log('oops', err)
})
ifstream.onEnd(() => {
ifstream.onEnd(() => {
<Image source={{ uri : 'data:image/png,base64' + data }}
})
})
Expand All @@ -673,7 +681,7 @@ RNFetchBlob.fs.writeStream(
.catch(console.error)
```

or
or

```js
RNFetchBlob.fs.writeStream(
Expand Down Expand Up @@ -749,7 +757,7 @@ You can also group requests by using `session` API and use `dispose` to remove t
.then((res) => {
// set session of a response
res.session('foo')
})
})

RNFetchblob.config({
// you can also set session beforehand
Expand All @@ -759,7 +767,7 @@ You can also group requests by using `session` API and use `dispose` to remove t
.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')
Expand Down Expand Up @@ -794,6 +802,22 @@ RNFetchBlob.config({
})
```

### 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.

```js
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](https://github.com/joltup/rn-fetch-blob/wiki/Web-API-Polyfills-(experimental)) that makes some browser-based library available in RN.
Expand Down
2 changes: 2 additions & 0 deletions android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class RNFetchBlobConfig {
public String appendExt;
public ReadableMap addAndroidDownloads;
public Boolean trusty;
public Boolean wifiOnly = false;
public String key;
public String mime;
public Boolean auto;
Expand All @@ -26,6 +27,7 @@ class RNFetchBlobConfig {
this.path = options.hasKey("path") ? options.getString("path") : null;
this.appendExt = options.hasKey("appendExt") ? options.getString("appendExt") : "";
this.trusty = options.hasKey("trusty") ? options.getBoolean("trusty") : false;
this.wifiOnly = options.hasKey("wifiOnly") ? options.getBoolean("wifiOnly") : false;
if(options.hasKey("addAndroidDownloads")) {
this.addAndroidDownloads = options.getMap("addAndroidDownloads");
}
Expand Down
59 changes: 54 additions & 5 deletions android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
import android.net.Uri;
import android.os.Build;
import androidx.annotation.NonNull;
import android.net.Network;
import android.net.NetworkInfo;
import android.net.NetworkCapabilities;
import android.net.ConnectivityManager;
import android.util.Base64;

import com.RNFetchBlob.Response.RNFetchBlobDefaultResp;
Expand Down Expand Up @@ -36,6 +40,7 @@
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.Proxy;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -231,6 +236,49 @@ else if(this.options.fileCache)
clientBuilder = client.newBuilder();
}

// wifi only, need ACCESS_NETWORK_STATE permission
// and API level >= 21
if(this.options.wifiOnly){

boolean found = false;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ConnectivityManager connectivityManager = (ConnectivityManager) RNFetchBlob.RCTContext.getSystemService(RNFetchBlob.RCTContext.CONNECTIVITY_SERVICE);
Network[] networks = connectivityManager.getAllNetworks();

for (Network network : networks) {

NetworkInfo netInfo = connectivityManager.getNetworkInfo(network);
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(network);

if(caps == null || netInfo == null){
continue;
}

if(!netInfo.isConnected()){
continue;
}

if(caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){
clientBuilder.proxy(Proxy.NO_PROXY);
clientBuilder.socketFactory(network.getSocketFactory());
found = true;
break;

}
}

if(!found){
callback.invoke("No available WiFi connections.", null, null);
releaseTaskResource();
return;
}
}
else{
RNFetchBlobUtils.emitWarningEvent("RNFetchBlob: wifiOnly was set, but SDK < 21. wifiOnly was ignored.");
}
}

final Request.Builder builder = new Request.Builder();
try {
builder.url(new URL(url));
Expand Down Expand Up @@ -378,7 +426,7 @@ public Response intercept(@NonNull Chain chain) throws IOException {
}
catch (SocketTimeoutException e ){
timeout = true;
RNFetchBlobUtils.emitWarningEvent("RNFetchBlob error when sending request : " + e.getLocalizedMessage());
//RNFetchBlobUtils.emitWarningEvent("RNFetchBlob error when sending request : " + e.getLocalizedMessage());
} catch(Exception ex) {

}
Expand Down Expand Up @@ -414,7 +462,7 @@ public void onFailure(@NonNull Call call, IOException e) {
// check if this error caused by socket timeout
if(e.getClass().equals(SocketTimeoutException.class)) {
respInfo.putBoolean("timeout", true);
callback.invoke("request timed out.", null, null);
callback.invoke("The request timed out.", null, null);
}
else
callback.invoke(e.getLocalizedMessage(), null, null);
Expand Down Expand Up @@ -545,13 +593,14 @@ private void done(Response resp) {

RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody;

if(rnFetchBlobFileResp != null && rnFetchBlobFileResp.isDownloadComplete() == false){
callback.invoke("RNFetchBlob failed. Download interrupted.", null);
if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){
callback.invoke("Download interrupted.", null);
}
else {
this.destPath = this.destPath.replace("?append=true", "");
callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath);
}

break;
default:
try {
Expand Down Expand Up @@ -685,7 +734,7 @@ public void onReceive(Context context, Intent intent) {
}

String filePath = null;
try {
try {
// the file exists in media content database
if (c.moveToFirst()) {
// #297 handle failed request
Expand Down
10 changes: 10 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,16 @@ export interface RNFetchBlobConfig {
*/
trusty?: boolean;

/**
* Set this property to true will only do requests through the WiFi interface, and fail otherwise.
*/
wifiOnly?: boolean;

/**
* Set this property so redirects are not automatically followed.
*/
followRedirect?: boolean;

/**
* Set this property to true will makes response data of the fetch stored in a temp file, by default the temp
* file will stored in App's own root folder with file name template RNFetchBlob_tmp${timestamp}.
Expand Down
6 changes: 6 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ function wrap(path:string):string {
* If it doesn't exist, the file is downloaded as usual
* @property {number} timeout
* Request timeout in millionseconds, by default it's 60000ms.
* @property {boolean} followRedirect
* Follow redirects automatically, default true
* @property {boolean} trusty
* Trust all certificates
* @property {boolean} wifiOnly
* Only do requests through WiFi. Android SDK 21 or above only.
*
* @return {function} This method returns a `fetch` method instance.
*/
Expand Down
4 changes: 3 additions & 1 deletion index.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ export type RNFetchBlobConfig = {
path?: string,
session?: string,
timeout?: number,
trusty?: boolean
trusty?: boolean,
wifiOnly?: boolean,
followRedirect?: boolean
};
export type RNFetchBlobResponseInfo = {
headers: {[fieldName: string]: string},
Expand Down
1 change: 1 addition & 0 deletions ios/RNFetchBlobConst.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern NSString *const CONFIG_USE_TEMP;
extern NSString *const CONFIG_FILE_PATH;
extern NSString *const CONFIG_FILE_EXT;
extern NSString *const CONFIG_TRUSTY;
extern NSString *const CONFIG_WIFI_ONLY;
extern NSString *const CONFIG_INDICATOR;
extern NSString *const CONFIG_KEY;
extern NSString *const CONFIG_EXTRA_BLOB_CTYPE;
Expand Down
1 change: 1 addition & 0 deletions ios/RNFetchBlobConst.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
NSString *const CONFIG_FILE_PATH = @"path";
NSString *const CONFIG_FILE_EXT = @"appendExt";
NSString *const CONFIG_TRUSTY = @"trusty";
NSString *const CONFIG_WIFI_ONLY = @"wifiOnly";
NSString *const CONFIG_INDICATOR = @"indicator";
NSString *const CONFIG_KEY = @"key";
NSString *const CONFIG_EXTRA_BLOB_CTYPE = @"binaryContentTypes";
Expand Down
Loading