Browse Source

Merge pull request #497 from cristianoccazinsp/wifiOnly

wifi only option, and missing typings.
Travis Nuttall 5 years ago
parent
commit
84d5312a72
No account linked to committer's email address

+ 35
- 11
README.md View File

41
 
41
 
42
 ## About
42
 ## About
43
 
43
 
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.
45
 
45
 
46
 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.
46
 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.
47
 
47
 
116
 
116
 
117
     <uses-permission android:name="android.permission.INTERNET" />
117
     <uses-permission android:name="android.permission.INTERNET" />
118
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
118
     <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" />
121
 +   <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
121
 +   <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
122
     ...
122
     ...
123
 
123
 
129
     <intent-filter>
129
     <intent-filter>
130
             <action android:name="android.intent.action.MAIN" />
130
             <action android:name="android.intent.action.MAIN" />
131
             <category android:name="android.intent.category.LAUNCHER" />
131
             <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"/>
133
     </intent-filter>
133
     </intent-filter>
134
 ```
134
 ```
135
 
135
 
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
+
136
 **Grant Access Permission for Android 6.0**
144
 **Grant Access Permission for Android 6.0**
137
 
145
 
138
 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).
146
 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
 
176
 
169
 - 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.
177
 - 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.
170
 - To send binary data, you have two choices, use BASE64 encoded string or path points to a file contains the body.
178
 - 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.
172
  - 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.
180
  - 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.
173
 - To send the body as-is, simply use a `Content-Type` header not containing `;BASE64` or `application/octet`.
181
 - To send the body as-is, simply use a `Content-Type` header not containing `;BASE64` or `application/octet`.
174
 
182
 
189
   })
197
   })
190
   .then((res) => {
198
   .then((res) => {
191
     let status = res.info().status;
199
     let status = res.info().status;
192
-    
200
+
193
     if(status == 200) {
201
     if(status == 200) {
194
       // the conversion is done in native code
202
       // the conversion is done in native code
195
       let base64Str = res.base64()
203
       let base64Str = res.base64()
290
     'Content-Type' : 'application/octet-stream',
298
     'Content-Type' : 'application/octet-stream',
291
     // here's the body you're going to send, should be a BASE64 encoded string
299
     // here's the body you're going to send, should be a BASE64 encoded string
292
     // (you can use "base64"(refer to the library 'mathiasbynens/base64') APIs to make one).
300
     // (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.
294
   }, base64ImageString)
302
   }, base64ImageString)
295
   .then((res) => {
303
   .then((res) => {
296
     console.log(res.text())
304
     console.log(res.text())
648
     ifstream.onError((err) => {
656
     ifstream.onError((err) => {
649
       console.log('oops', err)
657
       console.log('oops', err)
650
     })
658
     })
651
-    ifstream.onEnd(() => {  
659
+    ifstream.onEnd(() => {
652
       <Image source={{ uri : 'data:image/png,base64' + data }}
660
       <Image source={{ uri : 'data:image/png,base64' + data }}
653
     })
661
     })
654
 })
662
 })
673
 .catch(console.error)
681
 .catch(console.error)
674
 ```
682
 ```
675
 
683
 
676
-or 
684
+or
677
 
685
 
678
 ```js
686
 ```js
679
 RNFetchBlob.fs.writeStream(
687
 RNFetchBlob.fs.writeStream(
749
   .then((res) => {
757
   .then((res) => {
750
     // set session of a response
758
     // set session of a response
751
     res.session('foo')
759
     res.session('foo')
752
-  })  
760
+  })
753
 
761
 
754
   RNFetchblob.config({
762
   RNFetchblob.config({
755
     // you can also set session beforehand
763
     // you can also set session beforehand
759
   .fetch('GET', 'http://example.com/download/file')
767
   .fetch('GET', 'http://example.com/download/file')
760
   .then((res) => {
768
   .then((res) => {
761
     // ...
769
     // ...
762
-  })  
770
+  })
763
 
771
 
764
   // or put an existing file path to the session
772
   // or put an existing file path to the session
765
   RNFetchBlob.session('foo').add('some-file-path')
773
   RNFetchBlob.session('foo').add('some-file-path')
794
 })
802
 })
795
 ```
803
 ```
796
 
804
 
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
+
797
 ## Web API Polyfills
821
 ## Web API Polyfills
798
 
822
 
799
 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.
823
 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.

+ 2
- 0
android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java View File

10
     public String appendExt;
10
     public String appendExt;
11
     public ReadableMap addAndroidDownloads;
11
     public ReadableMap addAndroidDownloads;
12
     public Boolean trusty;
12
     public Boolean trusty;
13
+    public Boolean wifiOnly = false;
13
     public String key;
14
     public String key;
14
     public String mime;
15
     public String mime;
15
     public Boolean auto;
16
     public Boolean auto;
26
         this.path = options.hasKey("path") ? options.getString("path") : null;
27
         this.path = options.hasKey("path") ? options.getString("path") : null;
27
         this.appendExt = options.hasKey("appendExt") ? options.getString("appendExt") : "";
28
         this.appendExt = options.hasKey("appendExt") ? options.getString("appendExt") : "";
28
         this.trusty = options.hasKey("trusty") ? options.getBoolean("trusty") : false;
29
         this.trusty = options.hasKey("trusty") ? options.getBoolean("trusty") : false;
30
+        this.wifiOnly = options.hasKey("wifiOnly") ? options.getBoolean("wifiOnly") : false;
29
         if(options.hasKey("addAndroidDownloads")) {
31
         if(options.hasKey("addAndroidDownloads")) {
30
             this.addAndroidDownloads = options.getMap("addAndroidDownloads");
32
             this.addAndroidDownloads = options.getMap("addAndroidDownloads");
31
         }
33
         }

+ 54
- 5
android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java View File

9
 import android.net.Uri;
9
 import android.net.Uri;
10
 import android.os.Build;
10
 import android.os.Build;
11
 import androidx.annotation.NonNull;
11
 import androidx.annotation.NonNull;
12
+import android.net.Network;
13
+import android.net.NetworkInfo;
14
+import android.net.NetworkCapabilities;
15
+import android.net.ConnectivityManager;
12
 import android.util.Base64;
16
 import android.util.Base64;
13
 
17
 
14
 import com.RNFetchBlob.Response.RNFetchBlobDefaultResp;
18
 import com.RNFetchBlob.Response.RNFetchBlobDefaultResp;
36
 import java.net.SocketException;
40
 import java.net.SocketException;
37
 import java.net.SocketTimeoutException;
41
 import java.net.SocketTimeoutException;
38
 import java.net.URL;
42
 import java.net.URL;
43
+import java.net.Proxy;
39
 import java.nio.ByteBuffer;
44
 import java.nio.ByteBuffer;
40
 import java.nio.charset.CharacterCodingException;
45
 import java.nio.charset.CharacterCodingException;
41
 import java.nio.charset.Charset;
46
 import java.nio.charset.Charset;
231
                 clientBuilder = client.newBuilder();
236
                 clientBuilder = client.newBuilder();
232
             }
237
             }
233
 
238
 
239
+            // wifi only, need ACCESS_NETWORK_STATE permission
240
+            // and API level >= 21
241
+            if(this.options.wifiOnly){
242
+
243
+                boolean found = false;
244
+
245
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
246
+                    ConnectivityManager connectivityManager = (ConnectivityManager) RNFetchBlob.RCTContext.getSystemService(RNFetchBlob.RCTContext.CONNECTIVITY_SERVICE);
247
+                    Network[] networks = connectivityManager.getAllNetworks();
248
+
249
+                    for (Network network : networks) {
250
+
251
+                        NetworkInfo netInfo = connectivityManager.getNetworkInfo(network);
252
+                        NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(network);
253
+
254
+                        if(caps == null || netInfo == null){
255
+                            continue;
256
+                        }
257
+
258
+                        if(!netInfo.isConnected()){
259
+                            continue;
260
+                        }
261
+
262
+                        if(caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){
263
+                            clientBuilder.proxy(Proxy.NO_PROXY);
264
+                            clientBuilder.socketFactory(network.getSocketFactory());
265
+                            found = true;
266
+                            break;
267
+
268
+                        }
269
+                    }
270
+
271
+                    if(!found){
272
+                        callback.invoke("No available WiFi connections.", null, null);
273
+                        releaseTaskResource();
274
+                        return;
275
+                    }
276
+                }
277
+                else{
278
+                    RNFetchBlobUtils.emitWarningEvent("RNFetchBlob: wifiOnly was set, but SDK < 21. wifiOnly was ignored.");
279
+                }
280
+            }
281
+
234
             final Request.Builder builder = new Request.Builder();
282
             final Request.Builder builder = new Request.Builder();
235
             try {
283
             try {
236
                 builder.url(new URL(url));
284
                 builder.url(new URL(url));
378
                     }
426
                     }
379
                     catch (SocketTimeoutException e ){
427
                     catch (SocketTimeoutException e ){
380
                         timeout = true;
428
                         timeout = true;
381
-                        RNFetchBlobUtils.emitWarningEvent("RNFetchBlob error when sending request : " + e.getLocalizedMessage());
429
+                        //RNFetchBlobUtils.emitWarningEvent("RNFetchBlob error when sending request : " + e.getLocalizedMessage());
382
                     } catch(Exception ex) {
430
                     } catch(Exception ex) {
383
 
431
 
384
                     }
432
                     }
414
                     // check if this error caused by socket timeout
462
                     // check if this error caused by socket timeout
415
                     if(e.getClass().equals(SocketTimeoutException.class)) {
463
                     if(e.getClass().equals(SocketTimeoutException.class)) {
416
                         respInfo.putBoolean("timeout", true);
464
                         respInfo.putBoolean("timeout", true);
417
-                        callback.invoke("request timed out.", null, null);
465
+                        callback.invoke("The request timed out.", null, null);
418
                     }
466
                     }
419
                     else
467
                     else
420
                         callback.invoke(e.getLocalizedMessage(), null, null);
468
                         callback.invoke(e.getLocalizedMessage(), null, null);
545
 
593
 
546
                 RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody;
594
                 RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody;
547
 
595
 
548
-                if(rnFetchBlobFileResp != null && rnFetchBlobFileResp.isDownloadComplete() == false){
549
-                    callback.invoke("RNFetchBlob failed. Download interrupted.", null);
596
+                if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){
597
+                    callback.invoke("Download interrupted.", null);
550
                 }
598
                 }
551
                 else {
599
                 else {
552
                     this.destPath = this.destPath.replace("?append=true", "");
600
                     this.destPath = this.destPath.replace("?append=true", "");
553
                     callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath);
601
                     callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath);
554
                 }
602
                 }
603
+
555
                 break;
604
                 break;
556
             default:
605
             default:
557
                 try {
606
                 try {
685
                 }
734
                 }
686
 
735
 
687
                 String filePath = null;
736
                 String filePath = null;
688
-                try {    
737
+                try {
689
                     // the file exists in media content database
738
                     // the file exists in media content database
690
                     if (c.moveToFirst()) {
739
                     if (c.moveToFirst()) {
691
                         // #297 handle failed request
740
                         // #297 handle failed request

+ 10
- 0
index.d.ts View File

546
      */
546
      */
547
     trusty?: boolean;
547
     trusty?: boolean;
548
 
548
 
549
+    /**
550
+     * Set this property to true will only do requests through the WiFi interface, and fail otherwise.
551
+     */
552
+    wifiOnly?: boolean;
553
+
554
+    /**
555
+     * Set this property so redirects are not automatically followed.
556
+     */
557
+    followRedirect?: boolean;
558
+
549
     /**
559
     /**
550
      * Set this property to true will makes response data of the fetch stored in a temp file, by default the temp
560
      * Set this property to true will makes response data of the fetch stored in a temp file, by default the temp
551
      * file will stored in App's own root folder with file name template RNFetchBlob_tmp${timestamp}.
561
      * file will stored in App's own root folder with file name template RNFetchBlob_tmp${timestamp}.

+ 6
- 0
index.js View File

105
  *                   If it doesn't exist, the file is downloaded as usual
105
  *                   If it doesn't exist, the file is downloaded as usual
106
  *         @property {number} timeout
106
  *         @property {number} timeout
107
  *                   Request timeout in millionseconds, by default it's 60000ms.
107
  *                   Request timeout in millionseconds, by default it's 60000ms.
108
+ *         @property {boolean} followRedirect
109
+ *                   Follow redirects automatically, default true
110
+ *         @property {boolean} trusty
111
+ *                   Trust all certificates
112
+ *         @property {boolean} wifiOnly
113
+ *                   Only do requests through WiFi. Android SDK 21 or above only.
108
  *
114
  *
109
  * @return {function} This method returns a `fetch` method instance.
115
  * @return {function} This method returns a `fetch` method instance.
110
  */
116
  */

+ 3
- 1
index.js.flow View File

163
   path?: string,
163
   path?: string,
164
   session?: string,
164
   session?: string,
165
   timeout?: number,
165
   timeout?: number,
166
-  trusty?: boolean
166
+  trusty?: boolean,
167
+  wifiOnly?: boolean,
168
+  followRedirect?: boolean
167
 };
169
 };
168
 export type RNFetchBlobResponseInfo = {
170
 export type RNFetchBlobResponseInfo = {
169
   headers: {[fieldName: string]: string},
171
   headers: {[fieldName: string]: string},

+ 1
- 0
ios/RNFetchBlobConst.h View File

32
 extern NSString *const CONFIG_FILE_PATH;
32
 extern NSString *const CONFIG_FILE_PATH;
33
 extern NSString *const CONFIG_FILE_EXT;
33
 extern NSString *const CONFIG_FILE_EXT;
34
 extern NSString *const CONFIG_TRUSTY;
34
 extern NSString *const CONFIG_TRUSTY;
35
+extern NSString *const CONFIG_WIFI_ONLY;
35
 extern NSString *const CONFIG_INDICATOR;
36
 extern NSString *const CONFIG_INDICATOR;
36
 extern NSString *const CONFIG_KEY;
37
 extern NSString *const CONFIG_KEY;
37
 extern NSString *const CONFIG_EXTRA_BLOB_CTYPE;
38
 extern NSString *const CONFIG_EXTRA_BLOB_CTYPE;

+ 1
- 0
ios/RNFetchBlobConst.m View File

16
 NSString *const CONFIG_FILE_PATH = @"path";
16
 NSString *const CONFIG_FILE_PATH = @"path";
17
 NSString *const CONFIG_FILE_EXT = @"appendExt";
17
 NSString *const CONFIG_FILE_EXT = @"appendExt";
18
 NSString *const CONFIG_TRUSTY = @"trusty";
18
 NSString *const CONFIG_TRUSTY = @"trusty";
19
+NSString *const CONFIG_WIFI_ONLY = @"wifiOnly";
19
 NSString *const CONFIG_INDICATOR = @"indicator";
20
 NSString *const CONFIG_INDICATOR = @"indicator";
20
 NSString *const CONFIG_KEY = @"key";
21
 NSString *const CONFIG_KEY = @"key";
21
 NSString *const CONFIG_EXTRA_BLOB_CTYPE = @"binaryContentTypes";
22
 NSString *const CONFIG_EXTRA_BLOB_CTYPE = @"binaryContentTypes";

+ 68
- 61
ios/RNFetchBlobRequest.m View File

56
     const char* str = [input UTF8String];
56
     const char* str = [input UTF8String];
57
     unsigned char result[CC_MD5_DIGEST_LENGTH];
57
     unsigned char result[CC_MD5_DIGEST_LENGTH];
58
     CC_MD5(str, (CC_LONG)strlen(str), result);
58
     CC_MD5(str, (CC_LONG)strlen(str), result);
59
-    
59
+
60
     NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
60
     NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
61
     for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
61
     for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
62
         [ret appendFormat:@"%02x",result[i]];
62
         [ret appendFormat:@"%02x",result[i]];
80
     self.expectedBytes = 0;
80
     self.expectedBytes = 0;
81
     self.receivedBytes = 0;
81
     self.receivedBytes = 0;
82
     self.options = options;
82
     self.options = options;
83
-    
83
+
84
     backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue];
84
     backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue];
85
     // when followRedirect not set in options, defaults to TRUE
85
     // when followRedirect not set in options, defaults to TRUE
86
     followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue];
86
     followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue];
87
     isIncrement = [[options valueForKey:@"increment"] boolValue];
87
     isIncrement = [[options valueForKey:@"increment"] boolValue];
88
     redirects = [[NSMutableArray alloc] init];
88
     redirects = [[NSMutableArray alloc] init];
89
-    
89
+
90
     if (req.URL) {
90
     if (req.URL) {
91
         [redirects addObject:req.URL.absoluteString];
91
         [redirects addObject:req.URL.absoluteString];
92
     }
92
     }
93
-    
93
+
94
     // set response format
94
     // set response format
95
     NSString * rnfbResp = [req.allHTTPHeaderFields valueForKey:@"RNFB-Response"];
95
     NSString * rnfbResp = [req.allHTTPHeaderFields valueForKey:@"RNFB-Response"];
96
-    
96
+
97
     if ([[rnfbResp lowercaseString] isEqualToString:@"base64"]) {
97
     if ([[rnfbResp lowercaseString] isEqualToString:@"base64"]) {
98
         responseFormat = BASE64;
98
         responseFormat = BASE64;
99
     } else if ([[rnfbResp lowercaseString] isEqualToString:@"utf8"]) {
99
     } else if ([[rnfbResp lowercaseString] isEqualToString:@"utf8"]) {
101
     } else {
101
     } else {
102
         responseFormat = AUTO;
102
         responseFormat = AUTO;
103
     }
103
     }
104
-    
104
+
105
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
105
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
106
     NSString * key = [self.options valueForKey:CONFIG_KEY];
106
     NSString * key = [self.options valueForKey:CONFIG_KEY];
107
     NSURLSession * session;
107
     NSURLSession * session;
108
-    
108
+
109
     bodyLength = contentLength;
109
     bodyLength = contentLength;
110
-    
110
+
111
     // the session trust any SSL certification
111
     // the session trust any SSL certification
112
     NSURLSessionConfiguration *defaultConfigObject;
112
     NSURLSessionConfiguration *defaultConfigObject;
113
-    
113
+
114
     defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
114
     defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
115
-    
115
+
116
     if (backgroundTask) {
116
     if (backgroundTask) {
117
         defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId];
117
         defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId];
118
     }
118
     }
119
-    
119
+
120
     // request timeout, -1 if not set in options
120
     // request timeout, -1 if not set in options
121
     float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue];
121
     float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue];
122
-    
122
+
123
     if (timeout > 0) {
123
     if (timeout > 0) {
124
         defaultConfigObject.timeoutIntervalForRequest = timeout/1000;
124
         defaultConfigObject.timeoutIntervalForRequest = timeout/1000;
125
     }
125
     }
126
-    
126
+
127
+    if([options valueForKey:CONFIG_WIFI_ONLY] != nil && ![options[CONFIG_WIFI_ONLY] boolValue]){
128
+        [defaultConfigObject setAllowsCellularAccess:NO];
129
+    }
130
+
127
     defaultConfigObject.HTTPMaximumConnectionsPerHost = 10;
131
     defaultConfigObject.HTTPMaximumConnectionsPerHost = 10;
128
     session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue];
132
     session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue];
129
-    
133
+
130
     if (path || [self.options valueForKey:CONFIG_USE_TEMP]) {
134
     if (path || [self.options valueForKey:CONFIG_USE_TEMP]) {
131
         respFile = YES;
135
         respFile = YES;
132
-        
136
+
133
         NSString* cacheKey = taskId;
137
         NSString* cacheKey = taskId;
134
         if (key) {
138
         if (key) {
135
             cacheKey = [self md5:key];
139
             cacheKey = [self md5:key];
136
-            
140
+
137
             if (!cacheKey) {
141
             if (!cacheKey) {
138
                 cacheKey = taskId;
142
                 cacheKey = taskId;
139
             }
143
             }
140
-            
144
+
141
             destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
145
             destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
142
-            
146
+
143
             if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) {
147
             if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) {
144
                 callback(@[[NSNull null], RESP_TYPE_PATH, destPath]);
148
                 callback(@[[NSNull null], RESP_TYPE_PATH, destPath]);
145
-                
149
+
146
                 return;
150
                 return;
147
             }
151
             }
148
         }
152
         }
149
-        
153
+
150
         if (path) {
154
         if (path) {
151
             destPath = path;
155
             destPath = path;
152
         } else {
156
         } else {
156
         respData = [[NSMutableData alloc] init];
160
         respData = [[NSMutableData alloc] init];
157
         respFile = NO;
161
         respFile = NO;
158
     }
162
     }
159
-    
163
+
160
     self.task = [session dataTaskWithRequest:req];
164
     self.task = [session dataTaskWithRequest:req];
161
     [self.task resume];
165
     [self.task resume];
162
-    
166
+
163
     // network status indicator
167
     // network status indicator
164
     if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
168
     if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
165
         dispatch_async(dispatch_get_main_queue(), ^{
169
         dispatch_async(dispatch_get_main_queue(), ^{
183
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
187
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
184
 {
188
 {
185
     expectedBytes = [response expectedContentLength];
189
     expectedBytes = [response expectedContentLength];
186
-    
190
+
187
     NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
191
     NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
188
     NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
192
     NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
189
     NSString * respType = @"";
193
     NSString * respType = @"";
190
     respStatus = statusCode;
194
     respStatus = statusCode;
191
-    
195
+
192
     if ([response respondsToSelector:@selector(allHeaderFields)])
196
     if ([response respondsToSelector:@selector(allHeaderFields)])
193
     {
197
     {
194
         NSDictionary *headers = [httpResponse allHeaderFields];
198
         NSDictionary *headers = [httpResponse allHeaderFields];
195
         NSString * respCType = [[RNFetchBlobReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString];
199
         NSString * respCType = [[RNFetchBlobReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString];
196
-        
200
+
197
         if (self.isServerPush) {
201
         if (self.isServerPush) {
198
             if (partBuffer) {
202
             if (partBuffer) {
199
                 [self.bridge.eventDispatcher
203
                 [self.bridge.eventDispatcher
204
                         }
208
                         }
205
                  ];
209
                  ];
206
             }
210
             }
207
-            
211
+
208
             partBuffer = [[NSMutableData alloc] init];
212
             partBuffer = [[NSMutableData alloc] init];
209
             completionHandler(NSURLSessionResponseAllow);
213
             completionHandler(NSURLSessionResponseAllow);
210
 
214
 
212
         } else {
216
         } else {
213
             self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"];
217
             self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"];
214
         }
218
         }
215
-        
219
+
216
         if(respCType)
220
         if(respCType)
217
         {
221
         {
218
             NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE];
222
             NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE];
219
-            
223
+
220
             if ([respCType RNFBContainsString:@"text/"]) {
224
             if ([respCType RNFBContainsString:@"text/"]) {
221
                 respType = @"text";
225
                 respType = @"text";
222
             } else if ([respCType RNFBContainsString:@"application/json"]) {
226
             } else if ([respCType RNFBContainsString:@"application/json"]) {
232
                 }
236
                 }
233
             } else {
237
             } else {
234
                 respType = @"blob";
238
                 respType = @"blob";
235
-                
239
+
236
                 // for XMLHttpRequest, switch response data handling strategy automatically
240
                 // for XMLHttpRequest, switch response data handling strategy automatically
237
                 if ([options valueForKey:@"auto"]) {
241
                 if ([options valueForKey:@"auto"]) {
238
                     respFile = YES;
242
                     respFile = YES;
242
         } else {
246
         } else {
243
             respType = @"text";
247
             respType = @"text";
244
         }
248
         }
245
-        
249
+
246
 #pragma mark - handling cookies
250
 #pragma mark - handling cookies
247
         // # 153 get cookies
251
         // # 153 get cookies
248
         if (response.URL) {
252
         if (response.URL) {
252
                 [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil];
256
                 [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil];
253
             }
257
             }
254
         }
258
         }
255
-        
259
+
256
         [self.bridge.eventDispatcher
260
         [self.bridge.eventDispatcher
257
          sendDeviceEventWithName: EVENT_STATE_CHANGE
261
          sendDeviceEventWithName: EVENT_STATE_CHANGE
258
          body:@{
262
          body:@{
268
     } else {
272
     } else {
269
         NSLog(@"oops");
273
         NSLog(@"oops");
270
     }
274
     }
271
-    
275
+
272
     if (respFile)
276
     if (respFile)
273
     {
277
     {
274
         @try{
278
         @try{
275
             NSFileManager * fm = [NSFileManager defaultManager];
279
             NSFileManager * fm = [NSFileManager defaultManager];
276
             NSString * folder = [destPath stringByDeletingLastPathComponent];
280
             NSString * folder = [destPath stringByDeletingLastPathComponent];
277
-            
281
+
278
             if (![fm fileExistsAtPath:folder]) {
282
             if (![fm fileExistsAtPath:folder]) {
279
                 [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
283
                 [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
280
             }
284
             }
281
-            
285
+
282
             // if not set overwrite in options, defaults to TRUE
286
             // if not set overwrite in options, defaults to TRUE
283
             BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue];
287
             BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue];
284
             BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"];
288
             BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"];
285
-            
289
+
286
             appendToExistingFile = !overwrite;
290
             appendToExistingFile = !overwrite;
287
-            
291
+
288
             // For solving #141 append response data if the file already exists
292
             // For solving #141 append response data if the file already exists
289
             // base on PR#139 @kejinliang
293
             // base on PR#139 @kejinliang
290
             if (appendToExistingFile) {
294
             if (appendToExistingFile) {
291
                 destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""];
295
                 destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""];
292
             }
296
             }
293
-            
297
+
294
             if (![fm fileExistsAtPath:destPath]) {
298
             if (![fm fileExistsAtPath:destPath]) {
295
                 [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
299
                 [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
296
             }
300
             }
297
-            
301
+
298
             writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile];
302
             writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile];
299
             [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
303
             [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
300
             [writeStream open];
304
             [writeStream open];
304
             NSLog(@"write file error");
308
             NSLog(@"write file error");
305
         }
309
         }
306
     }
310
     }
307
-    
311
+
308
     completionHandler(NSURLSessionResponseAllow);
312
     completionHandler(NSURLSessionResponseAllow);
309
 }
313
 }
310
 
314
 
316
     if (self.isServerPush)
320
     if (self.isServerPush)
317
     {
321
     {
318
         [partBuffer appendData:data];
322
         [partBuffer appendData:data];
319
-        
323
+
320
         return ;
324
         return ;
321
     }
325
     }
322
-    
326
+
323
     NSNumber * received = [NSNumber numberWithLong:[data length]];
327
     NSNumber * received = [NSNumber numberWithLong:[data length]];
324
     receivedBytes += [received longValue];
328
     receivedBytes += [received longValue];
325
     NSString * chunkString = @"";
329
     NSString * chunkString = @"";
326
-    
330
+
327
     if (isIncrement) {
331
     if (isIncrement) {
328
         chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
332
         chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
329
     }
333
     }
330
-    
334
+
331
     if (respFile) {
335
     if (respFile) {
332
         [writeStream write:[data bytes] maxLength:[data length]];
336
         [writeStream write:[data bytes] maxLength:[data length]];
333
     } else {
337
     } else {
334
         [respData appendData:data];
338
         [respData appendData:data];
335
     }
339
     }
336
-    
340
+
337
     if (expectedBytes == 0) {
341
     if (expectedBytes == 0) {
338
         return;
342
         return;
339
     }
343
     }
340
-    
344
+
341
     NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)];
345
     NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)];
342
-    
346
+
343
     if ([self.progressConfig shouldReport:now]) {
347
     if ([self.progressConfig shouldReport:now]) {
344
         [self.bridge.eventDispatcher
348
         [self.bridge.eventDispatcher
345
          sendDeviceEventWithName:EVENT_PROGRESS
349
          sendDeviceEventWithName:EVENT_PROGRESS
363
 
367
 
364
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
368
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
365
 {
369
 {
366
-    
370
+
367
     self.error = error;
371
     self.error = error;
368
     NSString * errMsg;
372
     NSString * errMsg;
369
     NSString * respStr;
373
     NSString * respStr;
370
     NSString * rnfbRespType;
374
     NSString * rnfbRespType;
371
-    
372
-    dispatch_async(dispatch_get_main_queue(), ^{
373
-        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
374
-    });
375
-    
375
+
376
+    // only run this if we were requested to change it
377
+    if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
378
+        dispatch_async(dispatch_get_main_queue(), ^{
379
+            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
380
+        });
381
+    }
382
+
376
     if (error) {
383
     if (error) {
377
         if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) {
384
         if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) {
378
             errMsg = @"task cancelled";
385
             errMsg = @"task cancelled";
380
             errMsg = [error localizedDescription];
387
             errMsg = [error localizedDescription];
381
         }
388
         }
382
     }
389
     }
383
-    
390
+
384
     if (respFile) {
391
     if (respFile) {
385
         [writeStream close];
392
         [writeStream close];
386
         rnfbRespType = RESP_TYPE_PATH;
393
         rnfbRespType = RESP_TYPE_PATH;
391
         // if it turns out not to be `nil` that means the response data contains valid UTF8 string,
398
         // if it turns out not to be `nil` that means the response data contains valid UTF8 string,
392
         // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding.
399
         // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding.
393
         NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
400
         NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
394
-        
401
+
395
         if (responseFormat == BASE64) {
402
         if (responseFormat == BASE64) {
396
             rnfbRespType = RESP_TYPE_BASE64;
403
             rnfbRespType = RESP_TYPE_BASE64;
397
             respStr = [respData base64EncodedStringWithOptions:0];
404
             respStr = [respData base64EncodedStringWithOptions:0];
408
             }
415
             }
409
         }
416
         }
410
     }
417
     }
411
-    
412
-    
418
+
419
+
413
     callback(@[
420
     callback(@[
414
                errMsg ?: [NSNull null],
421
                errMsg ?: [NSNull null],
415
                rnfbRespType ?: @"",
422
                rnfbRespType ?: @"",
416
                respStr ?: [NSNull null]
423
                respStr ?: [NSNull null]
417
                ]);
424
                ]);
418
-    
425
+
419
     respData = nil;
426
     respData = nil;
420
     receivedBytes = 0;
427
     receivedBytes = 0;
421
     [session finishTasksAndInvalidate];
428
     [session finishTasksAndInvalidate];
422
-    
429
+
423
 }
430
 }
424
 
431
 
425
 // upload progress handler
432
 // upload progress handler
428
     if (totalBytesExpectedToWrite == 0) {
435
     if (totalBytesExpectedToWrite == 0) {
429
         return;
436
         return;
430
     }
437
     }
431
-    
438
+
432
     NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)];
439
     NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)];
433
 
440
 
434
     if ([self.uploadProgressConfig shouldReport:now]) {
441
     if ([self.uploadProgressConfig shouldReport:now]) {
461
 
468
 
462
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler
469
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler
463
 {
470
 {
464
-    
471
+
465
     if (followRedirect) {
472
     if (followRedirect) {
466
         if (request.URL) {
473
         if (request.URL) {
467
             [redirects addObject:[request.URL absoluteString]];
474
             [redirects addObject:[request.URL absoluteString]];
468
         }
475
         }
469
-        
476
+
470
         completionHandler(request);
477
         completionHandler(request);
471
     } else {
478
     } else {
472
         completionHandler(nil);
479
         completionHandler(nil);

+ 4
- 1
types.js View File

5
   appendExt : string,
5
   appendExt : string,
6
   session : string,
6
   session : string,
7
   addAndroidDownloads : any,
7
   addAndroidDownloads : any,
8
-  indicator : bool
8
+  indicator : bool,
9
+  followRedirect : bool,
10
+  trusty : bool,
11
+  wifiOnly : bool
9
 };
12
 };
10
 
13
 
11
 type RNFetchBlobNative = {
14
 type RNFetchBlobNative = {