Skip to content

Commit 206f86e

Browse files
committed
Merge commit '3ea8218fbfe9aa4986ced4c722e4b9265fa96657'
# Conflicts: # android/src/main/java/com/RNFetchBlob/RNFetchBlob.java
2 parents 7f8ec94 + 3ea8218 commit 206f86e

24 files changed

+501
-182
lines changed

README.md

+38-14
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ rn-fetch-blob version 0.10.16 is only compatible with react native 0.60 and up.
2020
* [Installation](#user-content-installation)
2121
* [HTTP Data Transfer](#user-content-http-data-transfer)
2222
* [Regular Request](#user-content-regular-request)
23-
* [Download file](#user-content-download-example--fetch-files-that-needs-authorization-token)
23+
* [Download file](#download-example-fetch-files-that-need-authorization-token)
2424
* [Upload file](#user-content-upload-example--dropbox-files-upload-api)
2525
* [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data)
2626
* [Upload/Download progress](#user-content-uploaddownload-progress)
@@ -41,7 +41,7 @@ rn-fetch-blob version 0.10.16 is only compatible with react native 0.60 and up.
4141

4242
## About
4343

44-
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.
44+
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.
4545

4646
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.
4747

@@ -79,7 +79,7 @@ If automatically linking doesn't work for you, see instructions on [manually lin
7979
For 0.29.2+ projects, simply link native packages via the following command (note: rnpm has been merged into react-native)
8080

8181
```
82-
react-native link
82+
react-native link rn-fetch-blob
8383
```
8484

8585
As for projects < 0.29 you need `rnpm` to link native packages
@@ -91,7 +91,7 @@ rnpm link
9191
Optionally, use the following command to add Android permissions to `AndroidManifest.xml` automatically
9292

9393
```sh
94-
RNFB_ANDROID_PERMISSIONS=true react-native link
94+
RNFB_ANDROID_PERMISSIONS=true react-native link rn-fetch-blob
9595
```
9696

9797
pre 0.29 projects
@@ -116,8 +116,8 @@ If you're going to access external storage (say, SD card storage) for `Android 5
116116

117117
<uses-permission android:name="android.permission.INTERNET" />
118118
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
119-
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
120-
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
119+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
120+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
121121
+ <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
122122
...
123123

@@ -129,10 +129,18 @@ Also, if you're going to use `Android Download Manager` you have to add this to
129129
<intent-filter>
130130
<action android:name="android.intent.action.MAIN" />
131131
<category android:name="android.intent.category.LAUNCHER" />
132-
+ <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
132+
+ <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
133133
</intent-filter>
134134
```
135135

136+
If you are going to use the `wifiOnly` flag, you need to add this to `AndroidManifest.xml`
137+
138+
```diff
139+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
140+
...
141+
142+
```
143+
136144
**Grant Access Permission for Android 6.0**
137145

138146
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).
@@ -168,7 +176,7 @@ To sum up:
168176

169177
- 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.
170178
- To send binary data, you have two choices, use BASE64 encoded string or path points to a file contains the body.
171-
- 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.
179+
- 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.
172180
- 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.
173181
- To send the body as-is, simply use a `Content-Type` header not containing `;BASE64` or `application/octet`.
174182

@@ -189,7 +197,7 @@ RNFetchBlob.fetch('GET', 'http://www.example.com/images/img1.png', {
189197
})
190198
.then((res) => {
191199
let status = res.info().status;
192-
200+
193201
if(status == 200) {
194202
// the conversion is done in native code
195203
let base64Str = res.base64()
@@ -290,7 +298,7 @@ RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
290298
'Content-Type' : 'application/octet-stream',
291299
// here's the body you're going to send, should be a BASE64 encoded string
292300
// (you can use "base64"(refer to the library 'mathiasbynens/base64') APIs to make one).
293-
// The data will be converted to "byte array"(say, blob) before request sent.
301+
// The data will be converted to "byte array"(say, blob) before request sent.
294302
}, base64ImageString)
295303
.then((res) => {
296304
console.log(res.text())
@@ -648,7 +656,7 @@ RNFetchBlob.fs.readStream(
648656
ifstream.onError((err) => {
649657
console.log('oops', err)
650658
})
651-
ifstream.onEnd(() => {
659+
ifstream.onEnd(() => {
652660
<Image source={{ uri : 'data:image/png,base64' + data }}
653661
})
654662
})
@@ -673,7 +681,7 @@ RNFetchBlob.fs.writeStream(
673681
.catch(console.error)
674682
```
675683

676-
or
684+
or
677685

678686
```js
679687
RNFetchBlob.fs.writeStream(
@@ -749,7 +757,7 @@ You can also group requests by using `session` API and use `dispose` to remove t
749757
.then((res) => {
750758
// set session of a response
751759
res.session('foo')
752-
})
760+
})
753761

754762
RNFetchblob.config({
755763
// you can also set session beforehand
@@ -759,7 +767,7 @@ You can also group requests by using `session` API and use `dispose` to remove t
759767
.fetch('GET', 'http://example.com/download/file')
760768
.then((res) => {
761769
// ...
762-
})
770+
})
763771

764772
// or put an existing file path to the session
765773
RNFetchBlob.session('foo').add('some-file-path')
@@ -794,6 +802,22 @@ RNFetchBlob.config({
794802
})
795803
```
796804

805+
### WiFi only requests
806+
807+
If you wish to only route requests through the Wifi interface, set the below configuration.
808+
Note: On Android, the `ACCESS_NETWORK_STATE` permission must be set, and this flag will only work
809+
on API version 21 (Lollipop, Android 5.0) or above. APIs below 21 will ignore this flag.
810+
811+
```js
812+
RNFetchBlob.config({
813+
wifiOnly : true
814+
})
815+
.fetch('GET', 'https://mysite.com')
816+
.then((resp) => {
817+
// ...
818+
})
819+
```
820+
797821
## Web API Polyfills
798822

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

android/src/main/java/com/RNFetchBlob/RNFetchBlob.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,14 @@ public void actionViewIntent(String path, String mime, final Promise promise) {
118118

119119
// Set flag to give temporary permission to external app to use FileProvider
120120
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
121-
// All the activity to be opened outside of an activity
121+
// All the activity to be opened outside of an activity
122122
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
123-
// Don't validate that the intent can run, instead, let it throw an exception if it can't.
124-
this.getReactApplicationContext().startActivity(intent);
123+
124+
// Validate that the device can open the file
125+
PackageManager pm = getCurrentActivity().getPackageManager();
126+
if (intent.resolveActivity(pm) != null) {
127+
this.getReactApplicationContext().startActivity(intent);
128+
}
125129

126130
} else {
127131
Intent intent = new Intent(Intent.ACTION_VIEW)

android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class RNFetchBlobConfig {
1010
public String appendExt;
1111
public ReadableMap addAndroidDownloads;
1212
public Boolean trusty;
13+
public Boolean wifiOnly = false;
1314
public String key;
1415
public String mime;
1516
public Boolean auto;
@@ -26,6 +27,7 @@ class RNFetchBlobConfig {
2627
this.path = options.hasKey("path") ? options.getString("path") : null;
2728
this.appendExt = options.hasKey("appendExt") ? options.getString("appendExt") : "";
2829
this.trusty = options.hasKey("trusty") ? options.getBoolean("trusty") : false;
30+
this.wifiOnly = options.hasKey("wifiOnly") ? options.getBoolean("wifiOnly") : false;
2931
if(options.hasKey("addAndroidDownloads")) {
3032
this.addAndroidDownloads = options.getMap("addAndroidDownloads");
3133
}

android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java

+47-23
Original file line numberDiff line numberDiff line change
@@ -69,32 +69,45 @@ static void writeFile(String path, String encoding, String data, final boolean a
6969
}
7070
}
7171

72-
FileOutputStream fout = new FileOutputStream(f, append);
7372
// write data from a file
7473
if(encoding.equalsIgnoreCase(RNFetchBlobConst.DATA_ENCODE_URI)) {
7574
String normalizedData = normalizePath(data);
7675
File src = new File(normalizedData);
7776
if (!src.exists()) {
7877
promise.reject("ENOENT", "No such file '" + path + "' " + "('" + normalizedData + "')");
79-
fout.close();
8078
return;
8179
}
82-
FileInputStream fin = new FileInputStream(src);
8380
byte[] buffer = new byte [10240];
8481
int read;
8582
written = 0;
86-
while((read = fin.read(buffer)) > 0) {
87-
fout.write(buffer, 0, read);
88-
written += read;
83+
FileInputStream fin = null;
84+
FileOutputStream fout = null;
85+
try {
86+
fin = new FileInputStream(src);
87+
fout = new FileOutputStream(f, append);
88+
while ((read = fin.read(buffer)) > 0) {
89+
fout.write(buffer, 0, read);
90+
written += read;
91+
}
92+
} finally {
93+
if (fin != null) {
94+
fin.close();
95+
}
96+
if (fout != null) {
97+
fout.close();
98+
}
8999
}
90-
fin.close();
91100
}
92101
else {
93102
byte[] bytes = stringToBytes(data, encoding);
94-
fout.write(bytes);
95-
written = bytes.length;
103+
FileOutputStream fout = new FileOutputStream(f, append);
104+
try {
105+
fout.write(bytes);
106+
written = bytes.length;
107+
} finally {
108+
fout.close();
109+
}
96110
}
97-
fout.close();
98111
promise.resolve(written);
99112
} catch (FileNotFoundException e) {
100113
// According to https://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
@@ -129,12 +142,15 @@ static void writeFile(String path, ReadableArray data, final boolean append, fin
129142
}
130143

131144
FileOutputStream os = new FileOutputStream(f, append);
132-
byte[] bytes = new byte[data.size()];
133-
for(int i=0;i<data.size();i++) {
134-
bytes[i] = (byte) data.getInt(i);
145+
try {
146+
byte[] bytes = new byte[data.size()];
147+
for (int i = 0; i < data.size(); i++) {
148+
bytes[i] = (byte) data.getInt(i);
149+
}
150+
os.write(bytes);
151+
} finally {
152+
os.close();
135153
}
136-
os.write(bytes);
137-
os.close();
138154
promise.resolve(data.size());
139155
} catch (FileNotFoundException e) {
140156
// According to https://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
@@ -523,7 +539,7 @@ private static void deleteRecursive(File fileOrDirectory) throws IOException {
523539
static void mkdir(String path, Promise promise) {
524540
File dest = new File(path);
525541
if(dest.exists()) {
526-
promise.reject("EEXIST", dest.isDirectory() ? "Folder" : "File" + " '" + path + "' already exists");
542+
promise.reject("EEXIST", (dest.isDirectory() ? "Folder" : "File") + " '" + path + "' already exists");
527543
return;
528544
}
529545
try {
@@ -650,9 +666,14 @@ static void exists(String path, Callback callback) {
650666
}
651667
else {
652668
path = normalizePath(path);
653-
boolean exist = new File(path).exists();
654-
boolean isDir = new File(path).isDirectory();
655-
callback.invoke(exist, isDir);
669+
if (path != null) {
670+
boolean exist = new File(path).exists();
671+
boolean isDir = new File(path).isDirectory();
672+
callback.invoke(exist, isDir);
673+
}
674+
else {
675+
callback.invoke(false, false);
676+
}
656677
}
657678
}
658679

@@ -876,11 +897,14 @@ static void hash(String path, String algorithm, Promise promise) {
876897
MessageDigest md = MessageDigest.getInstance(algorithms.get(algorithm));
877898

878899
FileInputStream inputStream = new FileInputStream(path);
879-
byte[] buffer = new byte[(int)file.length()];
900+
int chunkSize = 4096 * 256; // 1Mb
901+
byte[] buffer = new byte[chunkSize];
880902

881-
int read;
882-
while ((read = inputStream.read(buffer)) != -1) {
883-
md.update(buffer, 0, read);
903+
if(file.length() != 0) {
904+
int bytesRead;
905+
while ((bytesRead = inputStream.read(buffer)) != -1) {
906+
md.update(buffer, 0, bytesRead);
907+
}
884908
}
885909

886910
StringBuilder hexString = new StringBuilder();

0 commit comments

Comments
 (0)