From 9ab4ebb72e648156b2af60578de112022f856fb4 Mon Sep 17 00:00:00 2001 From: Ben Hsieh Date: Thu, 3 Aug 2017 09:37:08 +0800 Subject: [PATCH 001/182] bump to 0.10.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d88ec178..a93dba81d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-fetch-blob", - "version": "0.10.7", + "version": "0.10.8", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 1336555d79014a181ab79350434e016ea1bc8324 Mon Sep 17 00:00:00 2001 From: Ben Hsieh Date: Thu, 3 Aug 2017 09:42:16 +0800 Subject: [PATCH 002/182] Update PULL_REQUEST_TEMPLATE --- .github/PULL_REQUEST_TEMPLATE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index cef8ed2af..b03e3e8e3 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -1,5 +1,5 @@ Thank you for making a pull request ! Just a gentle reminder :) 1. If the PR is offering a feature please make the request to our "Feature Branch" 0.11.0 -2. Bug fix request to "Bug Fix Branch" 0.10.8 +2. Bug fix request to "Bug Fix Branch" 0.10.9 3. Correct README.md can directly to master From 2aea0b58e99581000d7336697e70b3bba7670a50 Mon Sep 17 00:00:00 2001 From: grylance Date: Wed, 9 Aug 2017 16:12:33 +0100 Subject: [PATCH 003/182] Fix path argument in iOS excludeFromBackupKey (#473) --- ios.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios.js b/ios.js index 566b424e2..340ef04cf 100644 --- a/ios.js +++ b/ios.js @@ -43,7 +43,7 @@ function openDocument(path:string, scheme:string) { * @param {string} url URL of the resource, only file URL is supported * @return {Promise} */ -function excludeFromBackupKey(url:string) { +function excludeFromBackupKey(path:string) { return RNFetchBlob.excludeFromBackupKey('file://' + path); } From 821eeb0f9db1736009ee791c14298ef72144a825 Mon Sep 17 00:00:00 2001 From: Kota Furusawa Date: Thu, 24 Aug 2017 10:02:20 +0800 Subject: [PATCH 004/182] Fix README (#501) remove extra space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7680fab86..3c7d24a59 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ RNFetchBlob 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 = + imageView = }) ``` From 5db2a74b077685666ea70c94c4f92c237cc66aa8 Mon Sep 17 00:00:00 2001 From: Catalin Miron Date: Thu, 12 Oct 2017 22:55:43 +0300 Subject: [PATCH 005/182] Fix README.md Fix example links for Download and Multipart/form-data --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3c7d24a59..7723d1ce7 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ A project committed to making file access and data transfer easier and more effi * [Installation](#user-content-installation) * [HTTP Data Transfer](#user-content-http-data-transfer) * [Regular Request](#user-content-regular-request) - * [Download file](#user-content-download-example--fetch-files-that-needs-authorization-token) + * [Download file](#download-example-fetch-files-that-need-authorization-token) * [Upload file](#user-content-upload-example--dropbox-files-upload-api) - * [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data) + * [Multipart/form upload](#multipartform-data-example-post-form-data-with-file-and-data) * [Upload/Download progress](#user-content-uploaddownload-progress) * [Cancel HTTP request](#user-content-cancel-request) * [Android Media Scanner, and Download Manager Support](#user-content-android-media-scanner-and-download-manager-support) From 22fd32a863343c6378c62d42f769bb58d6598d5b Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 5 Dec 2017 15:26:07 +0100 Subject: [PATCH 006/182] Catch exceptions on sd card directories constants creation. Methods to get sd card directories. sd card directiories as constants deprecated warning --- android.js | 18 +++++++++++- .../java/com/RNFetchBlob/RNFetchBlob.java | 16 +++++++---- .../java/com/RNFetchBlob/RNFetchBlobFS.java | 28 ++++++++++++++++++- fs.js | 13 +++++++-- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/android.js b/android.js index 0b5dbd84b..c9abd283a 100644 --- a/android.js +++ b/android.js @@ -38,9 +38,25 @@ function addCompleteDownload(config) { return Promise.reject('RNFetchBlob.android.addCompleteDownload only supports Android.') } +function getSDCardDir() { + if(Platform.OS === 'android') + return RNFetchBlob.getSDCardDir() + else + return Promise.reject('RNFetchBlob.android.getSDCardDir only supports Android.') +} + +function getSDCardApplicationDir() { + if(Platform.OS === 'android') + return RNFetchBlob.getSDCardApplicationDir() + else + return Promise.reject('RNFetchBlob.android.getSDCardApplicationDir only supports Android.') +} + export default { actionViewIntent, getContentIntent, - addCompleteDownload + addCompleteDownload, + getSDCardDir, + getSDCardApplicationDir, } diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 19e1be435..f5597d3ad 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -92,7 +92,6 @@ public void run() { RNFetchBlobFS.createFile(path, content, encode, callback); } }); - } @ReactMethod @@ -136,7 +135,6 @@ public void run() { RNFetchBlobFS.createFileASCII(path, dataArray, callback); } }); - } @ReactMethod @@ -167,7 +165,6 @@ public void run() { RNFetchBlobFS.cp(path, dest, callback); } }); - } @ReactMethod @@ -228,7 +225,6 @@ public void run() { RNFetchBlobFS.writeFile(path, encoding, data, append, promise); } }); - } @ReactMethod @@ -263,7 +259,6 @@ public void run() { new RNFetchBlobFS(ctx).scanFile(p, m, callback); } }); - } @ReactMethod @@ -324,7 +319,7 @@ public void enableUploadProgressReport(String taskId, int interval, int count) { @ReactMethod public void fetchBlob(ReadableMap options, String taskId, String method, String url, ReadableMap headers, String body, final Callback callback) { new RNFetchBlobReq(options, taskId, method, url, headers, body, null, mClient, callback).run(); -} + } @ReactMethod public void fetchBlobForm(ReadableMap options, String taskId, String method, String url, ReadableMap headers, ReadableArray body, final Callback callback) { @@ -370,4 +365,13 @@ public void addCompleteDownload (ReadableMap config, Promise promise) { } + @ReactMethod + public void getSDCardDir(Promise promise) { + RNFetchBlobFS.getSDCardDir(promise); + } + + @ReactMethod + public void getSDCardApplicationDir(Promise promise) { + RNFetchBlobFS.getSDCardApplicationDir(this.getReactApplicationContext(), promise); + } } diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 7a7910546..0959c4f9f 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -213,12 +213,38 @@ static public Map getSystemfolders(ReactApplicationContext ctx) state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { res.put("SDCardDir", Environment.getExternalStorageDirectory().getAbsolutePath()); - res.put("SDCardApplicationDir", ctx.getExternalFilesDir(null).getParentFile().getAbsolutePath()); + try { + res.put("SDCardApplicationDir", ctx.getExternalFilesDir(null).getParentFile().getAbsolutePath()); + } catch(Exception e) { + res.put("SDCardApplicationDir", ""); + } } res.put("MainBundleDir", ctx.getApplicationInfo().dataDir); return res; } + static public void getSDCardDir(Promise promise) { + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + promise.resolve(Environment.getExternalStorageDirectory().getAbsolutePath()); + } else { + promise.reject("RNFetchBlob.getSDCardDir", "External storage not mounted"); + } + + } + + static public void getSDCardApplicationDir(ReactApplicationContext ctx, Promise promise) { + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + try { + final String path = ctx.getExternalFilesDir(null).getParentFile().getAbsolutePath(); + promise.resolve(path); + } catch (Exception e) { + promise.reject("RNFetchBlob.getSDCardApplicationDir", e.getLocalizedMessage()); + } + } else { + promise.reject("RNFetchBlob.getSDCardApplicationDir", "External storage not mounted"); + } + } + /** * Static method that returns a temp file path * @param ctx React Native application context diff --git a/fs.js b/fs.js index 83e6bdceb..f50691e5e 100644 --- a/fs.js +++ b/fs.js @@ -28,8 +28,17 @@ const dirs = { MovieDir : RNFetchBlob.MovieDir, DownloadDir : RNFetchBlob.DownloadDir, DCIMDir : RNFetchBlob.DCIMDir, - SDCardDir : RNFetchBlob.SDCardDir, - SDCardApplicationDir : RNFetchBlob.SDCardApplicationDir, + get SDCardDir() { + console.warn('SDCardDir as a constant is deprecated and will be removed in feature release. ' + + 'Use RNFetchBlob.android.getSDCardDir():Promise instead.'); + return RNFetchBlob.SDCardDir; + }, + get SDCardApplicationDir() { + console.warn('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.'); + return RNFetchBlob.SDCardApplicationDir; + }, MainBundleDir : RNFetchBlob.MainBundleDir, LibraryDir : RNFetchBlob.LibraryDir } From e39a41b8ebd9182692d5cd876f8111aba5060ce5 Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Wed, 6 Dec 2017 07:51:15 +0100 Subject: [PATCH 007/182] add "maintainer missing" --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 3c7d24a59..dc5b3c5a6 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ A project committed to making file access and data transfer easier and more efficient for React Native developers. > For Firebase Storage solution, please upgrade to the latest version for the best compatibility. +## RNFB MAINTAINER GONE MISSING (Help Wanted) + +wkh237's last Github activity was in September 2017. Since there is a lot of work on issues and PRs that is left, is there anybody who else who could provide a maintained fork in the meantime? Create an issue and address me (@lll000111) and I'll add a link to your maintained repo fork right here. + + ## Features - Transfer data directly from/to storage without BASE64 bridging - File API supports regular files, Asset files, and CameraRoll files From 52c477315d473289f1bede66a51088c366dad643 Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Wed, 6 Dec 2017 07:52:09 +0100 Subject: [PATCH 008/182] add link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc5b3c5a6..c0a3124e3 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A project committed to making file access and data transfer easier and more effi ## RNFB MAINTAINER GONE MISSING (Help Wanted) -wkh237's last Github activity was in September 2017. Since there is a lot of work on issues and PRs that is left, is there anybody who else who could provide a maintained fork in the meantime? Create an issue and address me (@lll000111) and I'll add a link to your maintained repo fork right here. +wkh237's last Github activity was in September 2017. Since there is a lot of work on issues and PRs that is left, is there anybody who else who could provide a maintained fork in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)) and I'll add a link to your maintained repo fork right here. ## Features From 455097db73ccdb9d56426a47ccd1db949809a5b3 Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Wed, 6 Dec 2017 07:54:44 +0100 Subject: [PATCH 009/182] more vertical space around the message --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c0a3124e3..20b08470b 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,13 @@ A project committed to making file access and data transfer easier and more efficient for React Native developers. > For Firebase Storage solution, please upgrade to the latest version for the best compatibility. +
+ ## RNFB MAINTAINER GONE MISSING (Help Wanted) wkh237's last Github activity was in September 2017. Since there is a lot of work on issues and PRs that is left, is there anybody who else who could provide a maintained fork in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)) and I'll add a link to your maintained repo fork right here. +
## Features - Transfer data directly from/to storage without BASE64 bridging From 51f8a19e0960987717ee521aa960a8737b99444b Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Wed, 6 Dec 2017 07:58:07 +0100 Subject: [PATCH 010/182] update the maintainer-missing message --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20b08470b..883f0fd13 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A project committed to making file access and data transfer easier and more effi ## RNFB MAINTAINER GONE MISSING (Help Wanted) -wkh237's last Github activity was in September 2017. Since there is a lot of work on issues and PRs that is left, is there anybody who else who could provide a maintained fork in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)) and I'll add a link to your maintained repo fork right here. +wkh237's last Github activity was in September 2017. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here.
From e46f94e2ce7f135f3e9088c95bbd53cd79481ab5 Mon Sep 17 00:00:00 2001 From: Mattia Barbon Date: Wed, 23 Aug 2017 06:32:52 +0200 Subject: [PATCH 011/182] Fix iOS initialization race condition (#499) We have a crash in our application, and based on our analysis the culprit is a race condition in RNFetchBlobNetwork initialization. Crashing thread: Crashed: com.apple.root.default-qos 0 libobjc.A.dylib 0x10416bacb objc_msgSend + 11 1 Foundation 0x103d3b644 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:usingBlock:] + 153 2 Foundation 0x103c23f8c -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 61 3 Foundation 0x103c23f3a -[NSOperationQueue setMaxConcurrentOperationCount:] + 198 4 prymr 0x100d579aa -[RNFetchBlobNetwork init] (RNFetchBlobNetwork.m:112) 5 prymr 0x100d63a73 __65-[RNFetchBlob fetchBlob:taskId:method:url:headers:body:callback:]_block_invoke (RNFetchBlob.m:131) 6 prymr 0x100d6006b __85+[RNFetchBlobReqBuilder buildOctetRequest:taskId:method:url:headers:body:onComplete:]_block_invoke (RNFetchBlobReqBuilder.m:178) 7 libdispatch.dylib 0x107511585 _dispatch_call_block_and_release + 12 While a second thread is running: com.apple.root.default-qos 0 libsystem_kernel.dylib 0x107891c22 __psynch_mutexwait + 10 1 libsystem_pthread.dylib 0x1078c6dfa _pthread_mutex_lock_wait + 100 2 libsystem_pthread.dylib 0x1078c4519 _pthread_mutex_lock_slow + 285 3 Foundation 0x103d3b615 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:usingBlock:] + 106 4 Foundation 0x103c23f8c -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 61 5 Foundation 0x103c23f3a -[NSOperationQueue setMaxConcurrentOperationCount:] + 198 6 prymr 0x100d579aa -[RNFetchBlobNetwork init] (RNFetchBlobNetwork.m:112) 7 prymr 0x100d63a73 __65-[RNFetchBlob fetchBlob:taskId:method:url:headers:body:callback:]_block_invoke (RNFetchBlob.m:131) 8 prymr 0x100d6006b __85+[RNFetchBlobReqBuilder buildOctetRequest:taskId:method:url:headers:body:onComplete:]_block_invoke (RNFetchBlobReqBuilder.m:178) 9 libdispatch.dylib 0x107511585 _dispatch_call_block_and_release + 12 The patch just adds a dumb double-synchronization to the initialization. --- ios/RNFetchBlobNetwork.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 7be57fc59..c2f6d1680 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -106,8 +106,12 @@ @implementation RNFetchBlobNetwork - (id)init { self = [super init]; if(taskQueue == nil) { - taskQueue = [[NSOperationQueue alloc] init]; - taskQueue.maxConcurrentOperationCount = 10; + @synchronized ([RNFetchBlobNetwork class]) { + if (taskQueue == nil) { + taskQueue = [[NSOperationQueue alloc] init]; + taskQueue.maxConcurrentOperationCount = 10; + } + } } return self; } From 38f4d75eadb1cb7faed34ad613d190562d73c10f Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Fri, 12 Jan 2018 11:47:20 +0100 Subject: [PATCH 012/182] Synchronized dictionaries and tables operations --- ios/RNFetchBlobNetwork.m | 94 +++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 7be57fc59..621f48693 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -105,29 +105,35 @@ @implementation RNFetchBlobNetwork // constructor - (id)init { self = [super init]; - if(taskQueue == nil) { - taskQueue = [[NSOperationQueue alloc] init]; - taskQueue.maxConcurrentOperationCount = 10; + @synchronized ([RNFetchBlobNetwork class]) { + if (taskQueue == nil) { + taskQueue = [[NSOperationQueue alloc] init]; + taskQueue.maxConcurrentOperationCount = 10; + } } return self; } + (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config { - if(progressTable == nil) - { - progressTable = [[NSMutableDictionary alloc] init]; + @synchronized ([RNFetchBlobNetwork class]) { + if(progressTable == nil) + { + progressTable = [[NSMutableDictionary alloc] init]; + } + [progressTable setValue:config forKey:taskId]; } - [progressTable setValue:config forKey:taskId]; } + (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *)config { - if(uploadProgressTable == nil) - { - uploadProgressTable = [[NSMutableDictionary alloc] init]; + @synchronized ([RNFetchBlobNetwork class]) { + if(uploadProgressTable == nil) + { + uploadProgressTable = [[NSMutableDictionary alloc] init]; + } + [uploadProgressTable setValue:config forKey:taskId]; } - [uploadProgressTable setValue:config forKey:taskId]; } // removing case from headers @@ -241,8 +247,10 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options } __block NSURLSessionDataTask * task = [session dataTaskWithRequest:req]; - [taskTable setObject:task forKey:taskId]; - [task resume]; + @synchronized ([RNFetchBlobNetwork class]){ + [taskTable setObject:task forKey:taskId]; + [task resume]; + } // network status indicator if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES) @@ -254,21 +262,22 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options // #115 Invoke fetch.expire event on those expired requests so that the expired event can be handled + (void) emitExpiredTasks { - NSEnumerator * emu = [expirationTable keyEnumerator]; - NSString * key; - - while((key = [emu nextObject])) - { - RCTBridge * bridge = [RNFetchBlob getRCTBridge]; - NSData * args = @{ @"taskId": key }; - [bridge.eventDispatcher sendDeviceEventWithName:EVENT_EXPIRE body:args]; + @synchronized ([RNFetchBlobNetwork class]){ + NSEnumerator * emu = [expirationTable keyEnumerator]; + NSString * key; - } + while((key = [emu nextObject])) + { + RCTBridge * bridge = [RNFetchBlob getRCTBridge]; + NSData * args = @{ @"taskId": key }; + [bridge.eventDispatcher sendDeviceEventWithName:EVENT_EXPIRE body:args]; - // clear expired task entries - [expirationTable removeAllObjects]; - expirationTable = [[NSMapTable alloc] init]; + } + // clear expired task entries + [expirationTable removeAllObjects]; + expirationTable = [[NSMapTable alloc] init]; + } } //////////////////////////////////////// @@ -448,10 +457,18 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat { [writeStream write:[data bytes] maxLength:[data length]]; } - RNFetchBlobProgress * pconfig = [progressTable valueForKey:taskId]; + if(expectedBytes == 0) return; + + RNFetchBlobProgress * pconfig; + + @synchronized ([RNFetchBlobNetwork class]){ + pconfig = [progressTable valueForKey:taskId]; + } + NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)]; + if(pconfig != nil && [pconfig shouldReport:now]) { [self.bridge.eventDispatcher @@ -461,11 +478,9 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat @"written": [NSString stringWithFormat:@"%d", receivedBytes], @"total": [NSString stringWithFormat:@"%d", expectedBytes], @"chunk": chunkString - } + } ]; } - received = nil; - } - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error @@ -537,7 +552,7 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom callback(@[ errMsg, rnfbRespType, respStr]); - @synchronized(taskTable, uploadProgressTable, progressTable) + @synchronized ([RNFetchBlobNetwork class]) { if([taskTable objectForKey:taskId] == nil) NSLog(@"object released by ARC."); @@ -556,17 +571,23 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom // upload progress handler - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite { - RNFetchBlobProgress * pconfig = [uploadProgressTable valueForKey:taskId]; if(totalBytesExpectedToWrite == 0) return; + + RNFetchBlobProgress * pconfig; + + @synchronized ([RNFetchBlobNetwork class]) { + pconfig = [uploadProgressTable valueForKey:taskId]; + } + NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; if(pconfig != nil && [pconfig shouldReport:now]) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD body:@{ @"taskId": taskId, - @"written": [NSString stringWithFormat:@"%d", totalBytesWritten], - @"total": [NSString stringWithFormat:@"%d", totalBytesExpectedToWrite] + @"written": [NSString stringWithFormat:@"%ld", (long) totalBytesWritten], + @"total": [NSString stringWithFormat:@"%ld", (long) totalBytesExpectedToWrite] } ]; } @@ -574,7 +595,12 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen + (void) cancelRequest:(NSString *)taskId { - NSURLSessionDataTask * task = [taskTable objectForKey:taskId]; + NSURLSessionDataTask * task; + + @synchronized ([RNFetchBlobNetwork class]) { + task = [taskTable objectForKey:taskId]; + } + if(task != nil && task.state == NSURLSessionTaskStateRunning) [task cancel]; } From 17cc8b0f7031888692a9743338f7bf95c323b079 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Fri, 12 Jan 2018 11:47:20 +0100 Subject: [PATCH 013/182] Synchronized dictionaries and tables operations --- ios/RNFetchBlobNetwork.m | 96 ++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index c2f6d1680..621f48693 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -105,12 +105,10 @@ @implementation RNFetchBlobNetwork // constructor - (id)init { self = [super init]; - if(taskQueue == nil) { - @synchronized ([RNFetchBlobNetwork class]) { - if (taskQueue == nil) { - taskQueue = [[NSOperationQueue alloc] init]; - taskQueue.maxConcurrentOperationCount = 10; - } + @synchronized ([RNFetchBlobNetwork class]) { + if (taskQueue == nil) { + taskQueue = [[NSOperationQueue alloc] init]; + taskQueue.maxConcurrentOperationCount = 10; } } return self; @@ -118,20 +116,24 @@ - (id)init { + (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config { - if(progressTable == nil) - { - progressTable = [[NSMutableDictionary alloc] init]; + @synchronized ([RNFetchBlobNetwork class]) { + if(progressTable == nil) + { + progressTable = [[NSMutableDictionary alloc] init]; + } + [progressTable setValue:config forKey:taskId]; } - [progressTable setValue:config forKey:taskId]; } + (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *)config { - if(uploadProgressTable == nil) - { - uploadProgressTable = [[NSMutableDictionary alloc] init]; + @synchronized ([RNFetchBlobNetwork class]) { + if(uploadProgressTable == nil) + { + uploadProgressTable = [[NSMutableDictionary alloc] init]; + } + [uploadProgressTable setValue:config forKey:taskId]; } - [uploadProgressTable setValue:config forKey:taskId]; } // removing case from headers @@ -245,8 +247,10 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options } __block NSURLSessionDataTask * task = [session dataTaskWithRequest:req]; - [taskTable setObject:task forKey:taskId]; - [task resume]; + @synchronized ([RNFetchBlobNetwork class]){ + [taskTable setObject:task forKey:taskId]; + [task resume]; + } // network status indicator if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES) @@ -258,21 +262,22 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options // #115 Invoke fetch.expire event on those expired requests so that the expired event can be handled + (void) emitExpiredTasks { - NSEnumerator * emu = [expirationTable keyEnumerator]; - NSString * key; - - while((key = [emu nextObject])) - { - RCTBridge * bridge = [RNFetchBlob getRCTBridge]; - NSData * args = @{ @"taskId": key }; - [bridge.eventDispatcher sendDeviceEventWithName:EVENT_EXPIRE body:args]; + @synchronized ([RNFetchBlobNetwork class]){ + NSEnumerator * emu = [expirationTable keyEnumerator]; + NSString * key; - } + while((key = [emu nextObject])) + { + RCTBridge * bridge = [RNFetchBlob getRCTBridge]; + NSData * args = @{ @"taskId": key }; + [bridge.eventDispatcher sendDeviceEventWithName:EVENT_EXPIRE body:args]; - // clear expired task entries - [expirationTable removeAllObjects]; - expirationTable = [[NSMapTable alloc] init]; + } + // clear expired task entries + [expirationTable removeAllObjects]; + expirationTable = [[NSMapTable alloc] init]; + } } //////////////////////////////////////// @@ -452,10 +457,18 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat { [writeStream write:[data bytes] maxLength:[data length]]; } - RNFetchBlobProgress * pconfig = [progressTable valueForKey:taskId]; + if(expectedBytes == 0) return; + + RNFetchBlobProgress * pconfig; + + @synchronized ([RNFetchBlobNetwork class]){ + pconfig = [progressTable valueForKey:taskId]; + } + NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)]; + if(pconfig != nil && [pconfig shouldReport:now]) { [self.bridge.eventDispatcher @@ -465,11 +478,9 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat @"written": [NSString stringWithFormat:@"%d", receivedBytes], @"total": [NSString stringWithFormat:@"%d", expectedBytes], @"chunk": chunkString - } + } ]; } - received = nil; - } - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error @@ -541,7 +552,7 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom callback(@[ errMsg, rnfbRespType, respStr]); - @synchronized(taskTable, uploadProgressTable, progressTable) + @synchronized ([RNFetchBlobNetwork class]) { if([taskTable objectForKey:taskId] == nil) NSLog(@"object released by ARC."); @@ -560,17 +571,23 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom // upload progress handler - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite { - RNFetchBlobProgress * pconfig = [uploadProgressTable valueForKey:taskId]; if(totalBytesExpectedToWrite == 0) return; + + RNFetchBlobProgress * pconfig; + + @synchronized ([RNFetchBlobNetwork class]) { + pconfig = [uploadProgressTable valueForKey:taskId]; + } + NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; if(pconfig != nil && [pconfig shouldReport:now]) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD body:@{ @"taskId": taskId, - @"written": [NSString stringWithFormat:@"%d", totalBytesWritten], - @"total": [NSString stringWithFormat:@"%d", totalBytesExpectedToWrite] + @"written": [NSString stringWithFormat:@"%ld", (long) totalBytesWritten], + @"total": [NSString stringWithFormat:@"%ld", (long) totalBytesExpectedToWrite] } ]; } @@ -578,7 +595,12 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen + (void) cancelRequest:(NSString *)taskId { - NSURLSessionDataTask * task = [taskTable objectForKey:taskId]; + NSURLSessionDataTask * task; + + @synchronized ([RNFetchBlobNetwork class]) { + task = [taskTable objectForKey:taskId]; + } + if(task != nil && task.state == NSURLSessionTaskStateRunning) [task cancel]; } From 905ab1c2da7f138e6b37f52ac23d4a2bc77851fa Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Mon, 15 Jan 2018 14:16:19 +0100 Subject: [PATCH 014/182] Mostly RNFetchBlobNetwork cleanup --- ios/RNFetchBlob/RNFetchBlob.h | 1 - ios/RNFetchBlob/RNFetchBlob.m | 4 +- ios/RNFetchBlobConst.m | 56 +++++++++++++------------- ios/RNFetchBlobFS.h | 4 +- ios/RNFetchBlobNetwork.h | 20 +++------- ios/RNFetchBlobNetwork.m | 74 +++++++++++++++-------------------- ios/RNFetchBlobReqBuilder.h | 2 +- ios/RNFetchBlobReqBuilder.m | 2 +- 8 files changed, 72 insertions(+), 91 deletions(-) diff --git a/ios/RNFetchBlob/RNFetchBlob.h b/ios/RNFetchBlob/RNFetchBlob.h index e6385114f..669a093b5 100644 --- a/ios/RNFetchBlob/RNFetchBlob.h +++ b/ios/RNFetchBlob/RNFetchBlob.h @@ -39,7 +39,6 @@ @property (retain) UIDocumentInteractionController * documentController; + (RCTBridge *)getRCTBridge; -+ (void) checkExpiredSessions; @end diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index 246d6707c..40fc4c502 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -38,7 +38,7 @@ - (dispatch_queue_t) methodQueue { + (RCTBridge *)getRCTBridge { - RCTRootView * rootView = [[UIApplication sharedApplication] keyWindow].rootViewController.view; + RCTRootView * rootView = (RCTRootView*) [[UIApplication sharedApplication] keyWindow].rootViewController.view; return rootView.bridge; } @@ -128,7 +128,7 @@ - (NSDictionary *)constantsToExport // send HTTP request else { - __block RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init]; + RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init]; [utils sendRequest:options contentLength:bodyLength bridge:self.bridge taskId:taskId withRequest:req callback:callback]; } }]; diff --git a/ios/RNFetchBlobConst.m b/ios/RNFetchBlobConst.m index 6f7fef4b2..bc9b793a5 100644 --- a/ios/RNFetchBlobConst.m +++ b/ios/RNFetchBlobConst.m @@ -7,38 +7,38 @@ // #import "RNFetchBlobConst.h" -extern NSString *const FILE_PREFIX = @"RNFetchBlob-file://"; -extern NSString *const ASSET_PREFIX = @"bundle-assets://"; -extern NSString *const AL_PREFIX = @"assets-library://"; +NSString *const FILE_PREFIX = @"RNFetchBlob-file://"; +NSString *const ASSET_PREFIX = @"bundle-assets://"; +NSString *const AL_PREFIX = @"assets-library://"; // fetch configs -extern NSString *const CONFIG_USE_TEMP = @"fileCache"; -extern NSString *const CONFIG_FILE_PATH = @"path"; -extern NSString *const CONFIG_FILE_EXT = @"appendExt"; -extern NSString *const CONFIG_TRUSTY = @"trusty"; -extern NSString *const CONFIG_INDICATOR = @"indicator"; -extern NSString *const CONFIG_KEY = @"key"; -extern NSString *const CONFIG_EXTRA_BLOB_CTYPE = @"binaryContentTypes"; +NSString *const CONFIG_USE_TEMP = @"fileCache"; +NSString *const CONFIG_FILE_PATH = @"path"; +NSString *const CONFIG_FILE_EXT = @"appendExt"; +NSString *const CONFIG_TRUSTY = @"trusty"; +NSString *const CONFIG_INDICATOR = @"indicator"; +NSString *const CONFIG_KEY = @"key"; +NSString *const CONFIG_EXTRA_BLOB_CTYPE = @"binaryContentTypes"; -extern NSString *const EVENT_STATE_CHANGE = @"RNFetchBlobState"; -extern NSString *const EVENT_SERVER_PUSH = @"RNFetchBlobServerPush"; -extern NSString *const EVENT_PROGRESS = @"RNFetchBlobProgress"; -extern NSString *const EVENT_PROGRESS_UPLOAD = @"RNFetchBlobProgress-upload"; -extern NSString *const EVENT_EXPIRE = @"RNFetchBlobExpire"; +NSString *const EVENT_STATE_CHANGE = @"RNFetchBlobState"; +NSString *const EVENT_SERVER_PUSH = @"RNFetchBlobServerPush"; +NSString *const EVENT_PROGRESS = @"RNFetchBlobProgress"; +NSString *const EVENT_PROGRESS_UPLOAD = @"RNFetchBlobProgress-upload"; +NSString *const EVENT_EXPIRE = @"RNFetchBlobExpire"; -extern NSString *const MSG_EVENT = @"RNFetchBlobMessage"; -extern NSString *const MSG_EVENT_LOG = @"log"; -extern NSString *const MSG_EVENT_WARN = @"warn"; -extern NSString *const MSG_EVENT_ERROR = @"error"; -extern NSString *const FS_EVENT_DATA = @"data"; -extern NSString *const FS_EVENT_END = @"end"; -extern NSString *const FS_EVENT_WARN = @"warn"; -extern NSString *const FS_EVENT_ERROR = @"error"; +NSString *const MSG_EVENT = @"RNFetchBlobMessage"; +NSString *const MSG_EVENT_LOG = @"log"; +NSString *const MSG_EVENT_WARN = @"warn"; +NSString *const MSG_EVENT_ERROR = @"error"; +NSString *const FS_EVENT_DATA = @"data"; +NSString *const FS_EVENT_END = @"end"; +NSString *const FS_EVENT_WARN = @"warn"; +NSString *const FS_EVENT_ERROR = @"error"; -extern NSString *const KEY_REPORT_PROGRESS = @"reportProgress"; -extern NSString *const KEY_REPORT_UPLOAD_PROGRESS = @"reportUploadProgress"; +NSString *const KEY_REPORT_PROGRESS = @"reportProgress"; +NSString *const KEY_REPORT_UPLOAD_PROGRESS = @"reportUploadProgress"; // response type -extern NSString *const RESP_TYPE_BASE64 = @"base64"; -extern NSString *const RESP_TYPE_UTF8 = @"utf8"; -extern NSString *const RESP_TYPE_PATH = @"path"; +NSString *const RESP_TYPE_BASE64 = @"base64"; +NSString *const RESP_TYPE_UTF8 = @"utf8"; +NSString *const RESP_TYPE_PATH = @"path"; diff --git a/ios/RNFetchBlobFS.h b/ios/RNFetchBlobFS.h index 97386ef9d..c714fa66c 100644 --- a/ios/RNFetchBlobFS.h +++ b/ios/RNFetchBlobFS.h @@ -34,8 +34,8 @@ NSString * streamId; } -@property (nonatomic) NSOutputStream * outStream; -@property (nonatomic) NSInputStream * inStream; +@property (nonatomic) NSOutputStream * _Nullable outStream; +@property (nonatomic) NSInputStream * _Nullable inStream; @property (strong, nonatomic) RCTResponseSenderBlock callback; @property (nonatomic) RCTBridge * bridge; @property (nonatomic) NSString * encoding; diff --git a/ios/RNFetchBlobNetwork.h b/ios/RNFetchBlobNetwork.h index d3b4654a5..ef9e85ea7 100644 --- a/ios/RNFetchBlobNetwork.h +++ b/ios/RNFetchBlobNetwork.h @@ -20,39 +20,31 @@ #define RNFetchBlobNetwork_h - typedef void(^CompletionHander)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error); typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error); @interface RNFetchBlobNetwork : NSObject @property (nullable, nonatomic) NSString * taskId; -@property (nonatomic) int expectedBytes; -@property (nonatomic) int receivedBytes; +@property (nonatomic) long long expectedBytes; +@property (nonatomic) long long receivedBytes; @property (nonatomic) BOOL isServerPush; @property (nullable, nonatomic) NSMutableData * respData; -@property (strong, nonatomic) RCTResponseSenderBlock callback; +@property (nullable, strong, nonatomic) RCTResponseSenderBlock callback; @property (nullable, nonatomic) RCTBridge * bridge; @property (nullable, nonatomic) NSDictionary * options; @property (nullable, nonatomic) RNFetchBlobFS * fileStream; -@property (strong, nonatomic) CompletionHander fileTaskCompletionHandler; -@property (strong, nonatomic) DataTaskCompletionHander dataTaskCompletionHandler; @property (nullable, nonatomic) NSError * error; + (NSMutableDictionary * _Nullable ) normalizeHeaders:(NSDictionary * _Nullable)headers; -+ (void) cancelRequest:(NSString *)taskId; -+ (void) enableProgressReport:(NSString *) taskId; -+ (void) enableUploadProgress:(NSString *) taskId; ++ (void) cancelRequest:(NSString * _Nonnull)taskId; + (void) emitExpiredTasks; ++ (void) enableProgressReport:(NSString * _Nonnull) taskId config:(RNFetchBlobProgress * _Nullable)config; ++ (void) enableUploadProgress:(NSString * _Nonnull) taskId config:(RNFetchBlobProgress * _Nullable)config; - (nullable id) init; -- (void) sendRequest; - (void) sendRequest:(NSDictionary * _Nullable )options contentLength:(long)contentLength bridge:(RCTBridge * _Nullable)bridgeRef taskId:(NSString * _Nullable)taskId withRequest:(NSURLRequest * _Nullable)req callback:(_Nullable RCTResponseSenderBlock) callback; -+ (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config; -+ (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *)config; - - @end diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 621f48693..88fde5752 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -70,18 +70,17 @@ typedef NS_ENUM(NSUInteger, ResponseFormat) { @interface RNFetchBlobNetwork () { - BOOL * respFile; + BOOL respFile; BOOL isNewPart; - BOOL * isIncrement; + BOOL isIncrement; NSMutableData * partBuffer; NSString * destPath; NSOutputStream * writeStream; long bodyLength; - NSMutableDictionary * respInfo; NSInteger respStatus; NSMutableArray * redirects; ResponseFormat responseFormat; - BOOL * followRedirect; + BOOL followRedirect; BOOL backgroundTask; } @@ -97,8 +96,6 @@ @implementation RNFetchBlobNetwork @synthesize callback; @synthesize bridge; @synthesize options; -@synthesize fileTaskCompletionHandler; -@synthesize dataTaskCompletionHandler; @synthesize error; @@ -121,7 +118,7 @@ + (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *) { progressTable = [[NSMutableDictionary alloc] init]; } - [progressTable setValue:config forKey:taskId]; + if (config) [progressTable setValue:config forKey:taskId]; } } @@ -132,7 +129,7 @@ + (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *) { uploadProgressTable = [[NSMutableDictionary alloc] init]; } - [uploadProgressTable setValue:config forKey:taskId]; + if (config) [uploadProgressTable setValue:config forKey:taskId]; } } @@ -193,9 +190,8 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options responseFormat = AUTO; NSString * path = [self.options valueForKey:CONFIG_FILE_PATH]; - NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT]; NSString * key = [self.options valueForKey:CONFIG_KEY]; - __block NSURLSession * session; + NSURLSession * session; bodyLength = contentLength; @@ -246,16 +242,15 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options respFile = NO; } - __block NSURLSessionDataTask * task = [session dataTaskWithRequest:req]; + NSURLSessionDataTask * task = [session dataTaskWithRequest:req]; @synchronized ([RNFetchBlobNetwork class]){ [taskTable setObject:task forKey:taskId]; - [task resume]; } + [task resume]; // network status indicator if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES) [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; - __block UIApplication * app = [UIApplication sharedApplication]; } @@ -269,7 +264,7 @@ + (void) emitExpiredTasks while((key = [emu nextObject])) { RCTBridge * bridge = [RNFetchBlob getRCTBridge]; - NSData * args = @{ @"taskId": key }; + id args = @{ @"taskId": key }; [bridge.eventDispatcher sendDeviceEventWithName:EVENT_EXPIRE body:args]; } @@ -352,23 +347,14 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat { respType = @"blob"; // for XMLHttpRequest, switch response data handling strategy automatically - if([options valueForKey:@"auto"] == YES) { + if([options valueForKey:@"auto"]) { respFile = YES; destPath = [RNFetchBlobFS getTempPath:taskId withExtension:@""]; } } - } - else + } else { respType = @"text"; - respInfo = @{ - @"taskId": taskId, - @"state": @"2", - @"headers": headers, - @"redirects": redirects, - @"respType" : respType, - @"timeout" : @NO, - @"status": [NSNumber numberWithInteger:statusCode] - }; + } #pragma mark - handling cookies // # 153 get cookies @@ -383,11 +369,16 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat [self.bridge.eventDispatcher sendDeviceEventWithName: EVENT_STATE_CHANGE - body:respInfo + body:@{ + @"taskId": taskId, + @"state": @"2", + @"headers": headers, + @"redirects": redirects, + @"respType" : respType, + @"timeout" : @NO, + @"status": [NSNumber numberWithInteger:statusCode] + } ]; - headers = nil; - respInfo = nil; - } else NSLog(@"oops"); @@ -475,8 +466,8 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat sendDeviceEventWithName:EVENT_PROGRESS body:@{ @"taskId": taskId, - @"written": [NSString stringWithFormat:@"%d", receivedBytes], - @"total": [NSString stringWithFormat:@"%d", expectedBytes], + @"written": [NSString stringWithFormat:@"%ld", (long) receivedBytes], + @"total": [NSString stringWithFormat:@"%ld", (long) expectedBytes], @"chunk": chunkString } ]; @@ -494,17 +485,12 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom { self.error = error; - NSString * errMsg = [NSNull null]; - NSString * respStr = [NSNull null]; - NSString * rnfbRespType = @""; + NSString * errMsg; + NSString * respStr; + NSString * rnfbRespType; [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - if(respInfo == nil) - { - respInfo = [NSNull null]; - } - if(error != nil) { errMsg = [error localizedDescription]; @@ -550,7 +536,11 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom } - callback(@[ errMsg, rnfbRespType, respStr]); + callback(@[ + errMsg ?: [NSNull null], + rnfbRespType ?: @"", + respStr ?: [NSNull null] + ]); @synchronized ([RNFetchBlobNetwork class]) { @@ -608,7 +598,7 @@ + (void) cancelRequest:(NSString *)taskId - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler { - BOOL trusty = [options valueForKey:CONFIG_TRUSTY]; + BOOL trusty = [[options valueForKey:CONFIG_TRUSTY] boolValue]; if(!trusty) { completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); diff --git a/ios/RNFetchBlobReqBuilder.h b/ios/RNFetchBlobReqBuilder.h index e7abeb9c7..1edc3ff50 100644 --- a/ios/RNFetchBlobReqBuilder.h +++ b/ios/RNFetchBlobReqBuilder.h @@ -29,7 +29,7 @@ body:(NSString *)body onComplete:(void(^)(NSURLRequest * req, long bodyLength))onComplete; -+(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSMutableArray *) headers; ++(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSDictionary *) headers; @end diff --git a/ios/RNFetchBlobReqBuilder.m b/ios/RNFetchBlobReqBuilder.m index 15465a1ae..e9eced6c4 100644 --- a/ios/RNFetchBlobReqBuilder.m +++ b/ios/RNFetchBlobReqBuilder.m @@ -277,7 +277,7 @@ void __block (^getFieldData)(id field) = ^(id field) } } -+(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSMutableDictionary *) headers { ++(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSDictionary *) headers { NSString * normalCase = [headers valueForKey:field]; NSString * ignoredCase = [headers valueForKey:[field lowercaseString]]; From 11f674c88b1c2b6d0d93141a2d5011f104e2d7e1 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Mon, 15 Jan 2018 15:13:44 +0100 Subject: [PATCH 015/182] QOS level for task queue --- ios/RNFetchBlobNetwork.m | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 88fde5752..37490fdc7 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -105,6 +105,7 @@ - (id)init { @synchronized ([RNFetchBlobNetwork class]) { if (taskQueue == nil) { taskQueue = [[NSOperationQueue alloc] init]; + taskQueue.qualityOfService = NSQualityOfServiceUtility; taskQueue.maxConcurrentOperationCount = 10; } } From f0301db36ce6b54e2a9f942173523ad1a94e33ae Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Mon, 15 Jan 2018 15:46:31 +0100 Subject: [PATCH 016/182] Unused completion handlers leftovers removed --- ios/RNFetchBlobNetwork.h | 3 --- ios/RNFetchBlobNetwork.m | 1 - 2 files changed, 4 deletions(-) diff --git a/ios/RNFetchBlobNetwork.h b/ios/RNFetchBlobNetwork.h index ef9e85ea7..dcc5b99c5 100644 --- a/ios/RNFetchBlobNetwork.h +++ b/ios/RNFetchBlobNetwork.h @@ -20,9 +20,6 @@ #define RNFetchBlobNetwork_h -typedef void(^CompletionHander)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error); -typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error); - @interface RNFetchBlobNetwork : NSObject @property (nullable, nonatomic) NSString * taskId; diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 37490fdc7..ae22b37b8 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -137,7 +137,6 @@ + (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *) // removing case from headers + (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers { - NSMutableDictionary * mheaders = [[NSMutableDictionary alloc]init]; for(NSString * key in headers) { [mheaders setValue:[headers valueForKey:key] forKey:[key lowercaseString]]; From 8dd310d9f62979b77b39ddfb11ef6287fcf71bae Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Mon, 15 Jan 2018 17:16:46 +0100 Subject: [PATCH 017/182] Separate requests from network logic --- ios/RNFetchBlob.xcodeproj/project.pbxproj | 8 +- ios/RNFetchBlob/RNFetchBlob.m | 16 +- ios/RNFetchBlobNetwork.h | 14 +- ios/RNFetchBlobNetwork.m | 580 ++-------------------- ios/RNFetchBlobRequest.h | 47 ++ ios/RNFetchBlobRequest.m | 495 ++++++++++++++++++ 6 files changed, 616 insertions(+), 544 deletions(-) create mode 100644 ios/RNFetchBlobRequest.h create mode 100644 ios/RNFetchBlobRequest.m diff --git a/ios/RNFetchBlob.xcodeproj/project.pbxproj b/ios/RNFetchBlob.xcodeproj/project.pbxproj index acd524413..070fcabb1 100644 --- a/ios/RNFetchBlob.xcodeproj/project.pbxproj +++ b/ios/RNFetchBlob.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 8C4801A6200CF71700FED7ED /* RNFetchBlobRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C4801A5200CF71700FED7ED /* RNFetchBlobRequest.m */; }; A158F4271D052E49006FFD38 /* RNFetchBlobFS.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F4261D052E49006FFD38 /* RNFetchBlobFS.m */; }; A158F42D1D0535BB006FFD38 /* RNFetchBlobConst.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42C1D0535BB006FFD38 /* RNFetchBlobConst.m */; }; A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */; }; @@ -29,6 +30,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 8C4801A4200CF71700FED7ED /* RNFetchBlobRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobRequest.h; sourceTree = ""; }; + 8C4801A5200CF71700FED7ED /* RNFetchBlobRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobRequest.m; sourceTree = ""; }; A158F4261D052E49006FFD38 /* RNFetchBlobFS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobFS.m; sourceTree = ""; }; A158F4281D052E57006FFD38 /* RNFetchBlobFS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobFS.h; sourceTree = ""; }; A158F4291D0534A9006FFD38 /* RNFetchBlobConst.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobConst.h; sourceTree = ""; }; @@ -71,8 +74,10 @@ A1F950181D7E9134002A95A6 /* IOS7Polyfill.h */, A1AAE2981D300E4D0051D11C /* RNFetchBlobReqBuilder.m */, A1AAE2971D300E3E0051D11C /* RNFetchBlobReqBuilder.h */, - A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */, A158F42E1D0539CE006FFD38 /* RNFetchBlobNetwork.h */, + A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */, + 8C4801A4200CF71700FED7ED /* RNFetchBlobRequest.h */, + 8C4801A5200CF71700FED7ED /* RNFetchBlobRequest.m */, A158F42C1D0535BB006FFD38 /* RNFetchBlobConst.m */, A158F4291D0534A9006FFD38 /* RNFetchBlobConst.h */, A158F4281D052E57006FFD38 /* RNFetchBlobFS.h */, @@ -149,6 +154,7 @@ buildActionMask = 2147483647; files = ( A166D1AA1CE0647A00273590 /* RNFetchBlob.h in Sources */, + 8C4801A6200CF71700FED7ED /* RNFetchBlobRequest.m in Sources */, A158F42D1D0535BB006FFD38 /* RNFetchBlobConst.m in Sources */, A158F4271D052E49006FFD38 /* RNFetchBlobFS.m in Sources */, A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */, diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index 40fc4c502..6e8141f9e 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -96,8 +96,12 @@ - (NSDictionary *)constantsToExport // send HTTP request else { - RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init]; - [utils sendRequest:options contentLength:bodyLength bridge:self.bridge taskId:taskId withRequest:req callback:callback]; + [RNFetchBlobNetwork sendRequest:options + contentLength:bodyLength + bridge:self.bridge + taskId:taskId + withRequest:req + callback:callback]; } }]; @@ -128,8 +132,12 @@ - (NSDictionary *)constantsToExport // send HTTP request else { - RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init]; - [utils sendRequest:options contentLength:bodyLength bridge:self.bridge taskId:taskId withRequest:req callback:callback]; + [RNFetchBlobNetwork sendRequest:options + contentLength:bodyLength + bridge:self.bridge + taskId:taskId + withRequest:req + callback:callback]; } }]; } diff --git a/ios/RNFetchBlobNetwork.h b/ios/RNFetchBlobNetwork.h index dcc5b99c5..b93541267 100644 --- a/ios/RNFetchBlobNetwork.h +++ b/ios/RNFetchBlobNetwork.h @@ -22,18 +22,8 @@ @interface RNFetchBlobNetwork : NSObject -@property (nullable, nonatomic) NSString * taskId; -@property (nonatomic) long long expectedBytes; -@property (nonatomic) long long receivedBytes; -@property (nonatomic) BOOL isServerPush; -@property (nullable, nonatomic) NSMutableData * respData; -@property (nullable, strong, nonatomic) RCTResponseSenderBlock callback; -@property (nullable, nonatomic) RCTBridge * bridge; -@property (nullable, nonatomic) NSDictionary * options; -@property (nullable, nonatomic) RNFetchBlobFS * fileStream; -@property (nullable, nonatomic) NSError * error; - ++ (_Nullable instancetype)sharedInstance; + (NSMutableDictionary * _Nullable ) normalizeHeaders:(NSDictionary * _Nullable)headers; + (void) cancelRequest:(NSString * _Nonnull)taskId; + (void) emitExpiredTasks; @@ -41,7 +31,7 @@ + (void) enableUploadProgress:(NSString * _Nonnull) taskId config:(RNFetchBlobProgress * _Nullable)config; - (nullable id) init; -- (void) sendRequest:(NSDictionary * _Nullable )options contentLength:(long)contentLength bridge:(RCTBridge * _Nullable)bridgeRef taskId:(NSString * _Nullable)taskId withRequest:(NSURLRequest * _Nullable)req callback:(_Nullable RCTResponseSenderBlock) callback; ++ (void) sendRequest:(NSDictionary * _Nullable )options contentLength:(long)contentLength bridge:(RCTBridge * _Nullable)bridgeRef taskId:(NSString * _Nullable)taskId withRequest:(NSURLRequest * _Nullable)req callback:(_Nullable RCTResponseSenderBlock) callback; @end diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index ae22b37b8..5b3a32966 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -8,14 +8,12 @@ #import -#import "RNFetchBlob.h" -#import "RNFetchBlobFS.h" #import "RNFetchBlobNetwork.h" + +#import "RNFetchBlob.h" #import "RNFetchBlobConst.h" -#import "RNFetchBlobReqBuilder.h" -#import "IOS7Polyfill.h" -#import #import "RNFetchBlobProgress.h" +#import "RNFetchBlobRequest.h" #if __has_include() #import @@ -35,10 +33,7 @@ // //////////////////////////////////////// -NSMapTable * taskTable; NSMapTable * expirationTable; -NSMutableDictionary * progressTable; -NSMutableDictionary * uploadProgressTable; __attribute__((constructor)) static void initialize_tables() { @@ -46,91 +41,73 @@ static void initialize_tables() { { expirationTable = [[NSMapTable alloc] init]; } - if(taskTable == nil) - { - taskTable = [[NSMapTable alloc] init]; - } - if(progressTable == nil) - { - progressTable = [[NSMutableDictionary alloc] init]; - } - if(uploadProgressTable == nil) - { - uploadProgressTable = [[NSMutableDictionary alloc] init]; - } } -typedef NS_ENUM(NSUInteger, ResponseFormat) { - UTF8, - BASE64, - AUTO -}; - - -@interface RNFetchBlobNetwork () -{ - BOOL respFile; - BOOL isNewPart; - BOOL isIncrement; - NSMutableData * partBuffer; - NSString * destPath; - NSOutputStream * writeStream; - long bodyLength; - NSInteger respStatus; - NSMutableArray * redirects; - ResponseFormat responseFormat; - BOOL followRedirect; - BOOL backgroundTask; -} - -@end - @implementation RNFetchBlobNetwork NSOperationQueue *taskQueue; -@synthesize taskId; -@synthesize expectedBytes; -@synthesize receivedBytes; -@synthesize respData; -@synthesize callback; -@synthesize bridge; -@synthesize options; -@synthesize error; +NSMapTable * requestsTable; - -// constructor - (id)init { self = [super init]; - @synchronized ([RNFetchBlobNetwork class]) { - if (taskQueue == nil) { - taskQueue = [[NSOperationQueue alloc] init]; - taskQueue.qualityOfService = NSQualityOfServiceUtility; - taskQueue.maxConcurrentOperationCount = 10; - } + if (self) { + requestsTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory]; + + taskQueue = [[NSOperationQueue alloc] init]; + taskQueue.qualityOfService = NSQualityOfServiceUtility; + taskQueue.maxConcurrentOperationCount = 10; } + return self; } ++ (instancetype)sharedInstance { + static id _sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _sharedInstance = [[self alloc] init]; + }); + + return _sharedInstance; +} + ++ (void) sendRequest:(__weak NSDictionary * _Nullable )options + contentLength:(long) contentLength + bridge:(RCTBridge * _Nullable)bridgeRef + taskId:(NSString * _Nullable)taskId + withRequest:(__weak NSURLRequest * _Nullable)req + callback:(_Nullable RCTResponseSenderBlock) callback +{ + RNFetchBlobRequest *request = [[RNFetchBlobRequest alloc] init]; + [request sendRequest:options + contentLength:contentLength + bridge:bridgeRef + taskId:taskId + withRequest:req + taskOperationQueue:taskQueue + callback:callback]; + + @synchronized([RNFetchBlobNetwork class]) { + [requestsTable setObject:request forKey:taskId]; + } +} + + (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config { - @synchronized ([RNFetchBlobNetwork class]) { - if(progressTable == nil) - { - progressTable = [[NSMutableDictionary alloc] init]; + if (config) { + @synchronized ([RNFetchBlobNetwork class]) { + [requestsTable objectForKey:taskId].progressConfig = config; } - if (config) [progressTable setValue:config forKey:taskId]; } } + (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *)config { - @synchronized ([RNFetchBlobNetwork class]) { - if(uploadProgressTable == nil) - { - uploadProgressTable = [[NSMutableDictionary alloc] init]; + if (config) { + @synchronized ([RNFetchBlobNetwork class]) { + [requestsTable objectForKey:taskId].uploadProgressConfig = config; } - if (config) [uploadProgressTable setValue:config forKey:taskId]; } } @@ -145,488 +122,37 @@ + (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers return mheaders; } -- (NSString *)md5:(NSString *)input { - const char* str = [input UTF8String]; - unsigned char result[CC_MD5_DIGEST_LENGTH]; - CC_MD5(str, (CC_LONG)strlen(str), result); - - NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; - for(int i = 0; i 0) - { - defaultConfigObject.timeoutIntervalForRequest = timeout/1000; - } - defaultConfigObject.HTTPMaximumConnectionsPerHost = 10; - session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:taskQueue]; - if(path != nil || [self.options valueForKey:CONFIG_USE_TEMP]!= nil) - { - respFile = YES; - - NSString* cacheKey = taskId; - if (key != nil) { - cacheKey = [self md5:key]; - if (cacheKey == nil) { - cacheKey = taskId; - } - - destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]]; - if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) { - callback(@[[NSNull null], RESP_TYPE_PATH, destPath]); - return; - } - } - - if(path != nil) - destPath = path; - else - destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]]; - } - else - { - respData = [[NSMutableData alloc] init]; - respFile = NO; - } - - NSURLSessionDataTask * task = [session dataTaskWithRequest:req]; - @synchronized ([RNFetchBlobNetwork class]){ - [taskTable setObject:task forKey:taskId]; - } - [task resume]; - - // network status indicator - if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES) - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; - -} - // #115 Invoke fetch.expire event on those expired requests so that the expired event can be handled + (void) emitExpiredTasks { @synchronized ([RNFetchBlobNetwork class]){ NSEnumerator * emu = [expirationTable keyEnumerator]; NSString * key; - + while((key = [emu nextObject])) { RCTBridge * bridge = [RNFetchBlob getRCTBridge]; id args = @{ @"taskId": key }; [bridge.eventDispatcher sendDeviceEventWithName:EVENT_EXPIRE body:args]; - + } - + // clear expired task entries [expirationTable removeAllObjects]; expirationTable = [[NSMapTable alloc] init]; } } -//////////////////////////////////////// -// -// NSURLSession delegates -// -//////////////////////////////////////// - - -#pragma mark NSURLSession delegate methods - - -#pragma mark - Received Response -// set expected content length on response received -- (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler -{ - expectedBytes = [response expectedContentLength]; - - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; - NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; - NSString * respType = @""; - respStatus = statusCode; - if ([response respondsToSelector:@selector(allHeaderFields)]) - { - NSDictionary *headers = [httpResponse allHeaderFields]; - NSString * respCType = [[RNFetchBlobReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString]; - if(self.isServerPush == NO) - { - self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; - } - if(self.isServerPush) - { - if(partBuffer != nil) - { - [self.bridge.eventDispatcher - sendDeviceEventWithName:EVENT_SERVER_PUSH - body:@{ - @"taskId": taskId, - @"chunk": [partBuffer base64EncodedStringWithOptions:0], - } - ]; - } - partBuffer = [[NSMutableData alloc] init]; - completionHandler(NSURLSessionResponseAllow); - return; - } - if(respCType != nil) - { - NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE]; - if([respCType RNFBContainsString:@"text/"]) - { - respType = @"text"; - } - else if([respCType RNFBContainsString:@"application/json"]) - { - respType = @"json"; - } - // If extra blob content type is not empty, check if response type matches - else if( extraBlobCTypes != nil) { - for(NSString * substr in extraBlobCTypes) - { - if([respCType RNFBContainsString:[substr lowercaseString]]) - { - respType = @"blob"; - respFile = YES; - destPath = [RNFetchBlobFS getTempPath:taskId withExtension:nil]; - break; - } - } - } - else - { - respType = @"blob"; - // for XMLHttpRequest, switch response data handling strategy automatically - if([options valueForKey:@"auto"]) { - respFile = YES; - destPath = [RNFetchBlobFS getTempPath:taskId withExtension:@""]; - } - } - } else { - respType = @"text"; - } - -#pragma mark - handling cookies - // # 153 get cookies - if(response.URL != nil) - { - NSHTTPCookieStorage * cookieStore = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - NSArray * cookies = [NSHTTPCookie cookiesWithResponseHeaderFields: headers forURL:response.URL]; - if(cookies != nil && [cookies count] > 0) { - [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil]; - } - } - - [self.bridge.eventDispatcher - sendDeviceEventWithName: EVENT_STATE_CHANGE - body:@{ - @"taskId": taskId, - @"state": @"2", - @"headers": headers, - @"redirects": redirects, - @"respType" : respType, - @"timeout" : @NO, - @"status": [NSNumber numberWithInteger:statusCode] - } - ]; - } - else - NSLog(@"oops"); - - if(respFile == YES) - { - @try{ - NSFileManager * fm = [NSFileManager defaultManager]; - NSString * folder = [destPath stringByDeletingLastPathComponent]; - if(![fm fileExistsAtPath:folder]) - { - [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil]; - } - BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue]; - BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"]; - - appendToExistingFile = !overwrite; - - // For solving #141 append response data if the file already exists - // base on PR#139 @kejinliang - if(appendToExistingFile) - { - destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""]; - } - if (![fm fileExistsAtPath:destPath]) - { - [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil]; - } - writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile]; - [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; - [writeStream open]; - } - @catch(NSException * ex) - { - NSLog(@"write file error"); - } - } - - completionHandler(NSURLSessionResponseAllow); -} - - -// download progress handler -- (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data -{ - // For #143 handling multipart/x-mixed-replace response - if(self.isServerPush) - { - [partBuffer appendData:data]; - return ; - } - - NSNumber * received = [NSNumber numberWithLong:[data length]]; - receivedBytes += [received longValue]; - NSString * chunkString = @""; - - if(isIncrement == YES) - { - chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - } - - if(respFile == NO) - { - [respData appendData:data]; - } - else - { - [writeStream write:[data bytes] maxLength:[data length]]; - } - - if(expectedBytes == 0) - return; - - RNFetchBlobProgress * pconfig; - - @synchronized ([RNFetchBlobNetwork class]){ - pconfig = [progressTable valueForKey:taskId]; - } - - NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)]; - - if(pconfig != nil && [pconfig shouldReport:now]) - { - [self.bridge.eventDispatcher - sendDeviceEventWithName:EVENT_PROGRESS - body:@{ - @"taskId": taskId, - @"written": [NSString stringWithFormat:@"%ld", (long) receivedBytes], - @"total": [NSString stringWithFormat:@"%ld", (long) expectedBytes], - @"chunk": chunkString - } - ]; - } -} - -- (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error -{ - if([session isEqual:session]) - session = nil; -} - - -- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error -{ - - self.error = error; - NSString * errMsg; - NSString * respStr; - NSString * rnfbRespType; - - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - - if(error != nil) - { - errMsg = [error localizedDescription]; - } - - if(respFile == YES) - { - [writeStream close]; - rnfbRespType = RESP_TYPE_PATH; - respStr = destPath; - } - // base64 response - else { - // #73 fix unicode data encoding issue : - // when response type is BASE64, we should first try to encode the response data to UTF8 format - // if it turns out not to be `nil` that means the response data contains valid UTF8 string, - // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding. - NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding]; - - if(responseFormat == BASE64) - { - rnfbRespType = RESP_TYPE_BASE64; - respStr = [respData base64EncodedStringWithOptions:0]; - } - else if (responseFormat == UTF8) - { - rnfbRespType = RESP_TYPE_UTF8; - respStr = utf8; - } - else - { - if(utf8 != nil) - { - rnfbRespType = RESP_TYPE_UTF8; - respStr = utf8; - } - else - { - rnfbRespType = RESP_TYPE_BASE64; - respStr = [respData base64EncodedStringWithOptions:0]; - } - } - } - - - callback(@[ - errMsg ?: [NSNull null], - rnfbRespType ?: @"", - respStr ?: [NSNull null] - ]); - - @synchronized ([RNFetchBlobNetwork class]) - { - if([taskTable objectForKey:taskId] == nil) - NSLog(@"object released by ARC."); - else - [taskTable removeObjectForKey:taskId]; - [uploadProgressTable removeObjectForKey:taskId]; - [progressTable removeObjectForKey:taskId]; - } - - respData = nil; - receivedBytes = 0; - [session finishTasksAndInvalidate]; - -} - -// upload progress handler -- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite -{ - if(totalBytesExpectedToWrite == 0) - return; - - RNFetchBlobProgress * pconfig; - - @synchronized ([RNFetchBlobNetwork class]) { - pconfig = [uploadProgressTable valueForKey:taskId]; - } - - NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; - if(pconfig != nil && [pconfig shouldReport:now]) { - [self.bridge.eventDispatcher - sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD - body:@{ - @"taskId": taskId, - @"written": [NSString stringWithFormat:@"%ld", (long) totalBytesWritten], - @"total": [NSString stringWithFormat:@"%ld", (long) totalBytesExpectedToWrite] - } - ]; - } -} - + (void) cancelRequest:(NSString *)taskId { NSURLSessionDataTask * task; @synchronized ([RNFetchBlobNetwork class]) { - task = [taskTable objectForKey:taskId]; + task = [requestsTable objectForKey:taskId].task; } - if(task != nil && task.state == NSURLSessionTaskStateRunning) + if(task && task.state == NSURLSessionTaskStateRunning) { [task cancel]; -} - - -- (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler -{ - BOOL trusty = [[options valueForKey:CONFIG_TRUSTY] boolValue]; - if(!trusty) - { - completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - } - else - { - completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - } -} - - -- (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session -{ - NSLog(@"sess done in background"); -} - -- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler -{ - - if(followRedirect) - { - if(request.URL != nil) - [redirects addObject:[request.URL absoluteString]]; - completionHandler(request); - } - else - { - completionHandler(nil); } } diff --git a/ios/RNFetchBlobRequest.h b/ios/RNFetchBlobRequest.h new file mode 100644 index 000000000..a88ff05f6 --- /dev/null +++ b/ios/RNFetchBlobRequest.h @@ -0,0 +1,47 @@ +// +// RNFetchBlobRequest.h +// RNFetchBlob +// +// Created by Artur Chrusciel on 15.01.18. +// Copyright © 2018 wkh237.github.io. All rights reserved. +// + +#import + +#import "RNFetchBlobProgress.h" + +#if __has_include() +#import +#else +#import "RCTBridgeModule.h" +#endif + +#ifndef RNFetchBlobRequest_h +#define RNFetchBlobRequest_h + +@interface RNFetchBlobRequest : NSObject + +@property (nullable, nonatomic) NSString * taskId; +@property (nonatomic) long long expectedBytes; +@property (nonatomic) long long receivedBytes; +@property (nonatomic) BOOL isServerPush; +@property (nullable, nonatomic) NSMutableData * respData; +@property (nullable, strong, nonatomic) RCTResponseSenderBlock callback; +@property (nullable, nonatomic) RCTBridge * bridge; +@property (nullable, nonatomic) NSDictionary * options; +@property (nullable, nonatomic) NSError * error; +@property (nullable, nonatomic) RNFetchBlobProgress *progressConfig; +@property (nullable, nonatomic) RNFetchBlobProgress *uploadProgressConfig; +@property (nullable, nonatomic, weak) NSURLSessionDataTask *task; + +- (void) sendRequest:(NSDictionary * _Nullable )options + contentLength:(long)contentLength + bridge:(RCTBridge * _Nullable)bridgeRef + taskId:(NSString * _Nullable)taskId + withRequest:(NSURLRequest * _Nullable)req + taskOperationQueue:(NSOperationQueue * _Nonnull)operationQueue + callback:(_Nullable RCTResponseSenderBlock) callback; + +@end + +#endif /* RNFetchBlobRequest_h */ diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m new file mode 100644 index 000000000..73b562cc7 --- /dev/null +++ b/ios/RNFetchBlobRequest.m @@ -0,0 +1,495 @@ +// +// RNFetchBlobRequest.m +// RNFetchBlob +// +// Created by Artur Chrusciel on 15.01.18. +// Copyright © 2018 wkh237.github.io. All rights reserved. +// + +#import "RNFetchBlobRequest.h" + +#import "RNFetchBlobFS.h" +#import "RNFetchBlobConst.h" +#import "RNFetchBlobReqBuilder.h" + +#import "IOS7Polyfill.h" +#import + + +typedef NS_ENUM(NSUInteger, ResponseFormat) { + UTF8, + BASE64, + AUTO +}; + +@interface RNFetchBlobRequest () +{ + BOOL respFile; + BOOL isNewPart; + BOOL isIncrement; + NSMutableData * partBuffer; + NSString * destPath; + NSOutputStream * writeStream; + long bodyLength; + NSInteger respStatus; + NSMutableArray * redirects; + ResponseFormat responseFormat; + BOOL followRedirect; + BOOL backgroundTask; +} + +@end + +@implementation RNFetchBlobRequest + +@synthesize taskId; +@synthesize expectedBytes; +@synthesize receivedBytes; +@synthesize respData; +@synthesize callback; +@synthesize bridge; +@synthesize options; +@synthesize error; + + +- (NSString *)md5:(NSString *)input { + const char* str = [input UTF8String]; + unsigned char result[CC_MD5_DIGEST_LENGTH]; + CC_MD5(str, (CC_LONG)strlen(str), result); + + NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; + for(int i = 0; i 0) + { + defaultConfigObject.timeoutIntervalForRequest = timeout/1000; + } + defaultConfigObject.HTTPMaximumConnectionsPerHost = 10; + session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; + if(path != nil || [self.options valueForKey:CONFIG_USE_TEMP]!= nil) + { + respFile = YES; + + NSString* cacheKey = taskId; + if (key != nil) { + cacheKey = [self md5:key]; + if (cacheKey == nil) { + cacheKey = taskId; + } + + destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]]; + if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) { + callback(@[[NSNull null], RESP_TYPE_PATH, destPath]); + return; + } + } + + if(path != nil) + destPath = path; + else + destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]]; + } + else + { + respData = [[NSMutableData alloc] init]; + respFile = NO; + } + + self.task = [session dataTaskWithRequest:req]; + [self.task resume]; + + // network status indicator + if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES) + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; + +} + +//////////////////////////////////////// +// +// NSURLSession delegates +// +//////////////////////////////////////// + + +#pragma mark NSURLSession delegate methods + + +#pragma mark - Received Response +// set expected content length on response received +- (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler +{ + expectedBytes = [response expectedContentLength]; + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; + NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; + NSString * respType = @""; + respStatus = statusCode; + if ([response respondsToSelector:@selector(allHeaderFields)]) + { + NSDictionary *headers = [httpResponse allHeaderFields]; + NSString * respCType = [[RNFetchBlobReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString]; + if(self.isServerPush == NO) + { + self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; + } + if(self.isServerPush) + { + if(partBuffer != nil) + { + [self.bridge.eventDispatcher + sendDeviceEventWithName:EVENT_SERVER_PUSH + body:@{ + @"taskId": taskId, + @"chunk": [partBuffer base64EncodedStringWithOptions:0], + } + ]; + } + partBuffer = [[NSMutableData alloc] init]; + completionHandler(NSURLSessionResponseAllow); + return; + } + if(respCType != nil) + { + NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE]; + if([respCType RNFBContainsString:@"text/"]) + { + respType = @"text"; + } + else if([respCType RNFBContainsString:@"application/json"]) + { + respType = @"json"; + } + // If extra blob content type is not empty, check if response type matches + else if( extraBlobCTypes != nil) { + for(NSString * substr in extraBlobCTypes) + { + if([respCType RNFBContainsString:[substr lowercaseString]]) + { + respType = @"blob"; + respFile = YES; + destPath = [RNFetchBlobFS getTempPath:taskId withExtension:nil]; + break; + } + } + } + else + { + respType = @"blob"; + // for XMLHttpRequest, switch response data handling strategy automatically + if([options valueForKey:@"auto"]) { + respFile = YES; + destPath = [RNFetchBlobFS getTempPath:taskId withExtension:@""]; + } + } + } else { + respType = @"text"; + } + +#pragma mark - handling cookies + // # 153 get cookies + if(response.URL != nil) + { + NSHTTPCookieStorage * cookieStore = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray * cookies = [NSHTTPCookie cookiesWithResponseHeaderFields: headers forURL:response.URL]; + if(cookies != nil && [cookies count] > 0) { + [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil]; + } + } + + [self.bridge.eventDispatcher + sendDeviceEventWithName: EVENT_STATE_CHANGE + body:@{ + @"taskId": taskId, + @"state": @"2", + @"headers": headers, + @"redirects": redirects, + @"respType" : respType, + @"timeout" : @NO, + @"status": [NSNumber numberWithInteger:statusCode] + } + ]; + } + else + NSLog(@"oops"); + + if(respFile == YES) + { + @try{ + NSFileManager * fm = [NSFileManager defaultManager]; + NSString * folder = [destPath stringByDeletingLastPathComponent]; + if(![fm fileExistsAtPath:folder]) + { + [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil]; + } + BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue]; + BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"]; + + appendToExistingFile = !overwrite; + + // For solving #141 append response data if the file already exists + // base on PR#139 @kejinliang + if(appendToExistingFile) + { + destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""]; + } + if (![fm fileExistsAtPath:destPath]) + { + [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil]; + } + writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile]; + [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + [writeStream open]; + } + @catch(NSException * ex) + { + NSLog(@"write file error"); + } + } + + completionHandler(NSURLSessionResponseAllow); +} + + +// download progress handler +- (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data +{ + // For #143 handling multipart/x-mixed-replace response + if(self.isServerPush) + { + [partBuffer appendData:data]; + return ; + } + + NSNumber * received = [NSNumber numberWithLong:[data length]]; + receivedBytes += [received longValue]; + NSString * chunkString = @""; + + if(isIncrement == YES) + { + chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + + if(respFile == NO) + { + [respData appendData:data]; + } + else + { + [writeStream write:[data bytes] maxLength:[data length]]; + } + + if(expectedBytes == 0) + return; + + NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)]; + + if([self.progressConfig shouldReport:now]) + { + [self.bridge.eventDispatcher + sendDeviceEventWithName:EVENT_PROGRESS + body:@{ + @"taskId": taskId, + @"written": [NSString stringWithFormat:@"%ld", (long) receivedBytes], + @"total": [NSString stringWithFormat:@"%ld", (long) expectedBytes], + @"chunk": chunkString + } + ]; + } +} + +- (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error +{ + if([session isEqual:session]) + session = nil; +} + + +- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error +{ + + self.error = error; + NSString * errMsg; + NSString * respStr; + NSString * rnfbRespType; + + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + + if(error != nil) + { + errMsg = [error localizedDescription]; + } + + if(respFile == YES) + { + [writeStream close]; + rnfbRespType = RESP_TYPE_PATH; + respStr = destPath; + } + // base64 response + else { + // #73 fix unicode data encoding issue : + // when response type is BASE64, we should first try to encode the response data to UTF8 format + // if it turns out not to be `nil` that means the response data contains valid UTF8 string, + // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding. + NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding]; + + if(responseFormat == BASE64) + { + rnfbRespType = RESP_TYPE_BASE64; + respStr = [respData base64EncodedStringWithOptions:0]; + } + else if (responseFormat == UTF8) + { + rnfbRespType = RESP_TYPE_UTF8; + respStr = utf8; + } + else + { + if(utf8 != nil) + { + rnfbRespType = RESP_TYPE_UTF8; + respStr = utf8; + } + else + { + rnfbRespType = RESP_TYPE_BASE64; + respStr = [respData base64EncodedStringWithOptions:0]; + } + } + } + + + callback(@[ + errMsg ?: [NSNull null], + rnfbRespType ?: @"", + respStr ?: [NSNull null] + ]); + /* + @synchronized ([RNFetchBlobNetwork class]) + { + if([taskTable objectForKey:taskId] == nil) + NSLog(@"object released by ARC."); + else + [taskTable removeObjectForKey:taskId]; + [uploadProgressTable removeObjectForKey:taskId]; + [progressTable removeObjectForKey:taskId]; + }*/ + + respData = nil; + receivedBytes = 0; + [session finishTasksAndInvalidate]; + +} + +// upload progress handler +- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite +{ + if(totalBytesExpectedToWrite == 0) + return; + + NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; + + if([self.uploadProgressConfig shouldReport:now]) { + [self.bridge.eventDispatcher + sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD + body:@{ + @"taskId": taskId, + @"written": [NSString stringWithFormat:@"%ld", (long) totalBytesWritten], + @"total": [NSString stringWithFormat:@"%ld", (long) totalBytesExpectedToWrite] + } + ]; + } +} + + +- (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler +{ + BOOL trusty = [[options valueForKey:CONFIG_TRUSTY] boolValue]; + if(!trusty) + { + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + } + else + { + completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + } +} + + +- (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session +{ + NSLog(@"sess done in background"); +} + +- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler +{ + + if(followRedirect) + { + if(request.URL != nil) + [redirects addObject:[request.URL absoluteString]]; + completionHandler(request); + } + else + { + completionHandler(nil); + } +} + + +@end From db688751468496ffb4592ec000787597f96184ae Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 16 Jan 2018 08:22:00 +0100 Subject: [PATCH 018/182] Shared instance used --- ios/RNFetchBlobNetwork.h | 5 ++++- ios/RNFetchBlobNetwork.m | 23 ++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ios/RNFetchBlobNetwork.h b/ios/RNFetchBlobNetwork.h index b93541267..743d51e03 100644 --- a/ios/RNFetchBlobNetwork.h +++ b/ios/RNFetchBlobNetwork.h @@ -9,6 +9,7 @@ #import #import "RNFetchBlobProgress.h" #import "RNFetchBlobFS.h" +#import "RNFetchBlobRequest.h" #if __has_include() #import @@ -22,8 +23,10 @@ @interface RNFetchBlobNetwork : NSObject +@property(nonnull, nonatomic) NSOperationQueue *taskQueue; +@property(nonnull, nonatomic) NSMapTable * requestsTable; -+ (_Nullable instancetype)sharedInstance; ++ (RNFetchBlobNetwork* _Nullable)sharedInstance; + (NSMutableDictionary * _Nullable ) normalizeHeaders:(NSDictionary * _Nullable)headers; + (void) cancelRequest:(NSString * _Nonnull)taskId; + (void) emitExpiredTasks; diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 5b3a32966..1b4181959 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -13,7 +13,6 @@ #import "RNFetchBlob.h" #import "RNFetchBlobConst.h" #import "RNFetchBlobProgress.h" -#import "RNFetchBlobRequest.h" #if __has_include() #import @@ -46,23 +45,21 @@ static void initialize_tables() { @implementation RNFetchBlobNetwork -NSOperationQueue *taskQueue; -NSMapTable * requestsTable; - (id)init { self = [super init]; if (self) { - requestsTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory]; + self.requestsTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableWeakMemory]; - taskQueue = [[NSOperationQueue alloc] init]; - taskQueue.qualityOfService = NSQualityOfServiceUtility; - taskQueue.maxConcurrentOperationCount = 10; + self.taskQueue = [[NSOperationQueue alloc] init]; + self.taskQueue.qualityOfService = NSQualityOfServiceUtility; + self.taskQueue.maxConcurrentOperationCount = 10; } return self; } -+ (instancetype)sharedInstance { ++ (RNFetchBlobNetwork* _Nullable)sharedInstance { static id _sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -85,11 +82,11 @@ + (void) sendRequest:(__weak NSDictionary * _Nullable )options bridge:bridgeRef taskId:taskId withRequest:req - taskOperationQueue:taskQueue + taskOperationQueue:[self sharedInstance].taskQueue callback:callback]; @synchronized([RNFetchBlobNetwork class]) { - [requestsTable setObject:request forKey:taskId]; + [[self sharedInstance].requestsTable setObject:request forKey:taskId]; } } @@ -97,7 +94,7 @@ + (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *) { if (config) { @synchronized ([RNFetchBlobNetwork class]) { - [requestsTable objectForKey:taskId].progressConfig = config; + [[self sharedInstance].requestsTable objectForKey:taskId].progressConfig = config; } } } @@ -106,7 +103,7 @@ + (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *) { if (config) { @synchronized ([RNFetchBlobNetwork class]) { - [requestsTable objectForKey:taskId].uploadProgressConfig = config; + [[self sharedInstance].requestsTable objectForKey:taskId].uploadProgressConfig = config; } } } @@ -148,7 +145,7 @@ + (void) cancelRequest:(NSString *)taskId NSURLSessionDataTask * task; @synchronized ([RNFetchBlobNetwork class]) { - task = [requestsTable objectForKey:taskId].task; + task = [[self sharedInstance].requestsTable objectForKey:taskId].task; } if(task && task.state == NSURLSessionTaskStateRunning) { From ad657634283173a7ae3ce19e3fceb5dfa0b85910 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 16 Jan 2018 08:31:49 +0100 Subject: [PATCH 019/182] Proper usage of shared instance --- ios/RNFetchBlob/RNFetchBlob.m | 30 ++++++++++++------------- ios/RNFetchBlobNetwork.h | 14 ++++++++---- ios/RNFetchBlobNetwork.m | 42 +++++++++++++++++------------------ 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index 6e8141f9e..8b92431e9 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -96,12 +96,12 @@ - (NSDictionary *)constantsToExport // send HTTP request else { - [RNFetchBlobNetwork sendRequest:options - contentLength:bodyLength - bridge:self.bridge - taskId:taskId - withRequest:req - callback:callback]; + [[RNFetchBlobNetwork sharedInstance] sendRequest:options + contentLength:bodyLength + bridge:self.bridge + taskId:taskId + withRequest:req + callback:callback]; } }]; @@ -132,12 +132,12 @@ - (NSDictionary *)constantsToExport // send HTTP request else { - [RNFetchBlobNetwork sendRequest:options - contentLength:bodyLength - bridge:self.bridge - taskId:taskId - withRequest:req - callback:callback]; + [[RNFetchBlobNetwork sharedInstance] sendRequest:options + contentLength:bodyLength + bridge:self.bridge + taskId:taskId + withRequest:req + callback:callback]; } }]; } @@ -496,7 +496,7 @@ - (NSDictionary *)constantsToExport #pragma mark - net.cancelRequest RCT_EXPORT_METHOD(cancelRequest:(NSString *)taskId callback:(RCTResponseSenderBlock)callback) { - [RNFetchBlobNetwork cancelRequest:taskId]; + [[RNFetchBlobNetwork sharedInstance] cancelRequest:taskId]; callback(@[[NSNull null], taskId]); } @@ -506,14 +506,14 @@ - (NSDictionary *)constantsToExport { RNFetchBlobProgress * cfg = [[RNFetchBlobProgress alloc] initWithType:Download interval:interval count:count]; - [RNFetchBlobNetwork enableProgressReport:taskId config:cfg]; + [[RNFetchBlobNetwork sharedInstance] enableProgressReport:taskId config:cfg]; } #pragma mark - net.enableUploadProgressReport RCT_EXPORT_METHOD(enableUploadProgressReport:(NSString *)taskId interval:(nonnull NSNumber*)interval count:(nonnull NSNumber*)count) { RNFetchBlobProgress * cfg = [[RNFetchBlobProgress alloc] initWithType:Upload interval:interval count:count]; - [RNFetchBlobNetwork enableUploadProgress:taskId config:cfg]; + [[RNFetchBlobNetwork sharedInstance] enableUploadProgress:taskId config:cfg]; } #pragma mark - fs.slice diff --git a/ios/RNFetchBlobNetwork.h b/ios/RNFetchBlobNetwork.h index 743d51e03..ecee93761 100644 --- a/ios/RNFetchBlobNetwork.h +++ b/ios/RNFetchBlobNetwork.h @@ -28,13 +28,19 @@ + (RNFetchBlobNetwork* _Nullable)sharedInstance; + (NSMutableDictionary * _Nullable ) normalizeHeaders:(NSDictionary * _Nullable)headers; -+ (void) cancelRequest:(NSString * _Nonnull)taskId; + (void) emitExpiredTasks; -+ (void) enableProgressReport:(NSString * _Nonnull) taskId config:(RNFetchBlobProgress * _Nullable)config; -+ (void) enableUploadProgress:(NSString * _Nonnull) taskId config:(RNFetchBlobProgress * _Nullable)config; - (nullable id) init; -+ (void) sendRequest:(NSDictionary * _Nullable )options contentLength:(long)contentLength bridge:(RCTBridge * _Nullable)bridgeRef taskId:(NSString * _Nullable)taskId withRequest:(NSURLRequest * _Nullable)req callback:(_Nullable RCTResponseSenderBlock) callback; +- (void) sendRequest:(NSDictionary * _Nullable )options + contentLength:(long)contentLength + bridge:(RCTBridge * _Nullable)bridgeRef + taskId:(NSString * _Nullable)taskId + withRequest:(NSURLRequest * _Nullable)req + callback:(_Nullable RCTResponseSenderBlock) callback; +- (void) cancelRequest:(NSString * _Nonnull)taskId; +- (void) enableProgressReport:(NSString * _Nonnull) taskId config:(RNFetchBlobProgress * _Nullable)config; +- (void) enableUploadProgress:(NSString * _Nonnull) taskId config:(RNFetchBlobProgress * _Nullable)config; + @end diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 1b4181959..1cd9e93b3 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -69,7 +69,7 @@ + (RNFetchBlobNetwork* _Nullable)sharedInstance { return _sharedInstance; } -+ (void) sendRequest:(__weak NSDictionary * _Nullable )options +- (void) sendRequest:(__weak NSDictionary * _Nullable )options contentLength:(long) contentLength bridge:(RCTBridge * _Nullable)bridgeRef taskId:(NSString * _Nullable)taskId @@ -82,32 +82,45 @@ + (void) sendRequest:(__weak NSDictionary * _Nullable )options bridge:bridgeRef taskId:taskId withRequest:req - taskOperationQueue:[self sharedInstance].taskQueue + taskOperationQueue:self.taskQueue callback:callback]; @synchronized([RNFetchBlobNetwork class]) { - [[self sharedInstance].requestsTable setObject:request forKey:taskId]; + [self.requestsTable setObject:request forKey:taskId]; } } -+ (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config +- (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config { if (config) { @synchronized ([RNFetchBlobNetwork class]) { - [[self sharedInstance].requestsTable objectForKey:taskId].progressConfig = config; + [self.requestsTable objectForKey:taskId].progressConfig = config; } } } -+ (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *)config +- (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *)config { if (config) { @synchronized ([RNFetchBlobNetwork class]) { - [[self sharedInstance].requestsTable objectForKey:taskId].uploadProgressConfig = config; + [self.requestsTable objectForKey:taskId].uploadProgressConfig = config; } } } +- (void) cancelRequest:(NSString *)taskId +{ + NSURLSessionDataTask * task; + + @synchronized ([RNFetchBlobNetwork class]) { + task = [self.requestsTable objectForKey:taskId].task; + } + + if(task && task.state == NSURLSessionTaskStateRunning) { + [task cancel]; + } +} + // removing case from headers + (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers { @@ -115,7 +128,7 @@ + (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers for(NSString * key in headers) { [mheaders setValue:[headers valueForKey:key] forKey:[key lowercaseString]]; } - + return mheaders; } @@ -140,17 +153,4 @@ + (void) emitExpiredTasks } } -+ (void) cancelRequest:(NSString *)taskId -{ - NSURLSessionDataTask * task; - - @synchronized ([RNFetchBlobNetwork class]) { - task = [[self sharedInstance].requestsTable objectForKey:taskId].task; - } - - if(task && task.state == NSURLSessionTaskStateRunning) { - [task cancel]; - } -} - @end From 1d19f984ea4464298334587e4b57eb499489f509 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 16 Jan 2018 08:33:47 +0100 Subject: [PATCH 020/182] Commented code removed --- ios/RNFetchBlobRequest.m | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 73b562cc7..8ebdd8d19 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -419,16 +419,6 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom rnfbRespType ?: @"", respStr ?: [NSNull null] ]); - /* - @synchronized ([RNFetchBlobNetwork class]) - { - if([taskTable objectForKey:taskId] == nil) - NSLog(@"object released by ARC."); - else - [taskTable removeObjectForKey:taskId]; - [uploadProgressTable removeObjectForKey:taskId]; - [progressTable removeObjectForKey:taskId]; - }*/ respData = nil; receivedBytes = 0; From d4b465a366603a90b50a3a46323183e7e6795e7d Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 16 Jan 2018 09:06:57 +0100 Subject: [PATCH 021/182] Fixed header import defines --- ios/RNFetchBlobNetwork.h | 6 +++--- ios/RNFetchBlobRequest.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ios/RNFetchBlobNetwork.h b/ios/RNFetchBlobNetwork.h index ecee93761..1512712af 100644 --- a/ios/RNFetchBlobNetwork.h +++ b/ios/RNFetchBlobNetwork.h @@ -6,6 +6,9 @@ // Copyright © 2016 wkh237. All rights reserved. // +#ifndef RNFetchBlobNetwork_h +#define RNFetchBlobNetwork_h + #import #import "RNFetchBlobProgress.h" #import "RNFetchBlobFS.h" @@ -17,9 +20,6 @@ #import "RCTBridgeModule.h" #endif -#ifndef RNFetchBlobNetwork_h -#define RNFetchBlobNetwork_h - @interface RNFetchBlobNetwork : NSObject diff --git a/ios/RNFetchBlobRequest.h b/ios/RNFetchBlobRequest.h index a88ff05f6..b550ac22e 100644 --- a/ios/RNFetchBlobRequest.h +++ b/ios/RNFetchBlobRequest.h @@ -6,6 +6,9 @@ // Copyright © 2018 wkh237.github.io. All rights reserved. // +#ifndef RNFetchBlobRequest_h +#define RNFetchBlobRequest_h + #import #import "RNFetchBlobProgress.h" @@ -16,9 +19,6 @@ #import "RCTBridgeModule.h" #endif -#ifndef RNFetchBlobRequest_h -#define RNFetchBlobRequest_h - @interface RNFetchBlobRequest : NSObject @property (nullable, nonatomic) NSString * taskId; From 57102f4d1e9b2e3c59739acadb7b870066eaa903 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 16 Jan 2018 12:50:18 +0100 Subject: [PATCH 022/182] Some code guidelines for network classes --- ios/RNFetchBlobNetwork.m | 10 +- ios/RNFetchBlobRequest.m | 200 ++++++++++++++++++--------------------- 2 files changed, 97 insertions(+), 113 deletions(-) diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 1cd9e93b3..4531bf35e 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -36,8 +36,7 @@ __attribute__((constructor)) static void initialize_tables() { - if(expirationTable == nil) - { + if (expirationTable == nil) { expirationTable = [[NSMapTable alloc] init]; } } @@ -62,6 +61,7 @@ - (id)init { + (RNFetchBlobNetwork* _Nullable)sharedInstance { static id _sharedInstance = nil; static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ _sharedInstance = [[self alloc] init]; }); @@ -116,7 +116,7 @@ - (void) cancelRequest:(NSString *)taskId task = [self.requestsTable objectForKey:taskId].task; } - if(task && task.state == NSURLSessionTaskStateRunning) { + if (task && task.state == NSURLSessionTaskStateRunning) { [task cancel]; } } @@ -125,7 +125,7 @@ - (void) cancelRequest:(NSString *)taskId + (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers { NSMutableDictionary * mheaders = [[NSMutableDictionary alloc]init]; - for(NSString * key in headers) { + for (NSString * key in headers) { [mheaders setValue:[headers valueForKey:key] forKey:[key lowercaseString]]; } @@ -139,7 +139,7 @@ + (void) emitExpiredTasks NSEnumerator * emu = [expirationTable keyEnumerator]; NSString * key; - while((key = [emu nextObject])) + while ((key = [emu nextObject])) { RCTBridge * bridge = [RNFetchBlob getRCTBridge]; id args = @{ @"taskId": key }; diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 8ebdd8d19..10b5e660f 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -58,7 +58,7 @@ - (NSString *)md5:(NSString *)input { CC_MD5(str, (CC_LONG)strlen(str), result); NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; - for(int i = 0; i 0) - { + + if (timeout > 0) { defaultConfigObject.timeoutIntervalForRequest = timeout/1000; } + defaultConfigObject.HTTPMaximumConnectionsPerHost = 10; session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; - if(path != nil || [self.options valueForKey:CONFIG_USE_TEMP]!= nil) - { + + if (path || [self.options valueForKey:CONFIG_USE_TEMP]) { respFile = YES; NSString* cacheKey = taskId; - if (key != nil) { + if (key) { cacheKey = [self md5:key]; - if (cacheKey == nil) { + + if (!cacheKey) { cacheKey = taskId; } destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]]; + if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) { callback(@[[NSNull null], RESP_TYPE_PATH, destPath]); + return; } } - if(path != nil) + if (path) { destPath = path; - else + } else { destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]]; - } - else - { + } + } else { respData = [[NSMutableData alloc] init]; respFile = NO; } @@ -154,9 +161,9 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options [self.task resume]; // network status indicator - if([[options objectForKey:CONFIG_INDICATOR] boolValue] == YES) + if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; - + } } //////////////////////////////////////// @@ -179,18 +186,14 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; NSString * respType = @""; respStatus = statusCode; + if ([response respondsToSelector:@selector(allHeaderFields)]) { NSDictionary *headers = [httpResponse allHeaderFields]; NSString * respCType = [[RNFetchBlobReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString]; - if(self.isServerPush == NO) - { - self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; - } - if(self.isServerPush) - { - if(partBuffer != nil) - { + + if (self.isServerPush) { + if (partBuffer) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_SERVER_PUSH body:@{ @@ -199,39 +202,37 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } ]; } + partBuffer = [[NSMutableData alloc] init]; completionHandler(NSURLSessionResponseAllow); + return; + } else { + self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; } - if(respCType != nil) + + if(respCType) { NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE]; - if([respCType RNFBContainsString:@"text/"]) - { + + if ([respCType RNFBContainsString:@"text/"]) { respType = @"text"; - } - else if([respCType RNFBContainsString:@"application/json"]) - { + } else if ([respCType RNFBContainsString:@"application/json"]) { respType = @"json"; - } - // If extra blob content type is not empty, check if response type matches - else if( extraBlobCTypes != nil) { - for(NSString * substr in extraBlobCTypes) - { - if([respCType RNFBContainsString:[substr lowercaseString]]) - { + } else if(extraBlobCTypes) { // If extra blob content type is not empty, check if response type matches + for (NSString * substr in extraBlobCTypes) { + if ([respCType RNFBContainsString:[substr lowercaseString]]) { respType = @"blob"; respFile = YES; destPath = [RNFetchBlobFS getTempPath:taskId withExtension:nil]; break; } } - } - else - { + } else { respType = @"blob"; + // for XMLHttpRequest, switch response data handling strategy automatically - if([options valueForKey:@"auto"]) { + if ([options valueForKey:@"auto"]) { respFile = YES; destPath = [RNFetchBlobFS getTempPath:taskId withExtension:@""]; } @@ -242,11 +243,10 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat #pragma mark - handling cookies // # 153 get cookies - if(response.URL != nil) - { + if (response.URL) { NSHTTPCookieStorage * cookieStore = [NSHTTPCookieStorage sharedHTTPCookieStorage]; NSArray * cookies = [NSHTTPCookie cookiesWithResponseHeaderFields: headers forURL:response.URL]; - if(cookies != nil && [cookies count] > 0) { + if (cookies.count) { [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil]; } } @@ -263,19 +263,21 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat @"status": [NSNumber numberWithInteger:statusCode] } ]; - } - else + } else { NSLog(@"oops"); + } - if(respFile == YES) + if (respFile) { @try{ NSFileManager * fm = [NSFileManager defaultManager]; NSString * folder = [destPath stringByDeletingLastPathComponent]; - if(![fm fileExistsAtPath:folder]) - { + + if (![fm fileExistsAtPath:folder]) { [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil]; } + + // if not set overwrite in options, defaults to TRUE BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue]; BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"]; @@ -283,14 +285,14 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat // For solving #141 append response data if the file already exists // base on PR#139 @kejinliang - if(appendToExistingFile) - { + if (appendToExistingFile) { destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""]; } - if (![fm fileExistsAtPath:destPath]) - { + + if (![fm fileExistsAtPath:destPath]) { [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil]; } + writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile]; [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; [writeStream open]; @@ -309,9 +311,10 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // For #143 handling multipart/x-mixed-replace response - if(self.isServerPush) + if (self.isServerPush) { [partBuffer appendData:data]; + return ; } @@ -319,27 +322,23 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat receivedBytes += [received longValue]; NSString * chunkString = @""; - if(isIncrement == YES) - { + if (isIncrement) { chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } - if(respFile == NO) - { - [respData appendData:data]; - } - else - { + if (respFile) { [writeStream write:[data bytes] maxLength:[data length]]; + } else { + [respData appendData:data]; } - if(expectedBytes == 0) + if (expectedBytes == 0) { return; + } NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)]; - if([self.progressConfig shouldReport:now]) - { + if ([self.progressConfig shouldReport:now]) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_PROGRESS body:@{ @@ -354,8 +353,9 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error { - if([session isEqual:session]) + if ([session isEqual:session]) { session = nil; + } } @@ -369,44 +369,32 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - if(error != nil) - { + if (error) { errMsg = [error localizedDescription]; } - if(respFile == YES) - { + if (respFile) { [writeStream close]; rnfbRespType = RESP_TYPE_PATH; respStr = destPath; - } - // base64 response - else { + } else { // base64 response // #73 fix unicode data encoding issue : // when response type is BASE64, we should first try to encode the response data to UTF8 format // if it turns out not to be `nil` that means the response data contains valid UTF8 string, // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding. NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding]; - if(responseFormat == BASE64) - { + if (responseFormat == BASE64) { rnfbRespType = RESP_TYPE_BASE64; respStr = [respData base64EncodedStringWithOptions:0]; - } - else if (responseFormat == UTF8) - { + } else if (responseFormat == UTF8) { rnfbRespType = RESP_TYPE_UTF8; respStr = utf8; - } - else - { - if(utf8 != nil) - { + } else { + if (utf8) { rnfbRespType = RESP_TYPE_UTF8; respStr = utf8; - } - else - { + } else { rnfbRespType = RESP_TYPE_BASE64; respStr = [respData base64EncodedStringWithOptions:0]; } @@ -429,12 +417,13 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom // upload progress handler - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite { - if(totalBytesExpectedToWrite == 0) + if (totalBytesExpectedToWrite == 0) { return; + } NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; - if([self.uploadProgressConfig shouldReport:now]) { + if ([self.uploadProgressConfig shouldReport:now]) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD body:@{ @@ -449,14 +438,10 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler { - BOOL trusty = [[options valueForKey:CONFIG_TRUSTY] boolValue]; - if(!trusty) - { - completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - } - else - { + if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) { completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + } else { + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); } } @@ -469,14 +454,13 @@ - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)sessio - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler { - if(followRedirect) - { - if(request.URL != nil) + if (followRedirect) { + if (request.URL) { [redirects addObject:[request.URL absoluteString]]; + } + completionHandler(request); - } - else - { + } else { completionHandler(nil); } } From 89d9b7a5a7152b2ec19acb35d03461702fb2fc92 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 16 Jan 2018 13:24:14 +0100 Subject: [PATCH 023/182] Network activity calls on main thread --- ios/RNFetchBlobRequest.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 10b5e660f..4b2ca9a1f 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -162,7 +162,9 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options // network status indicator if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) { - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; + }); } } @@ -367,7 +369,9 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom NSString * respStr; NSString * rnfbRespType; - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + }); if (error) { errMsg = [error localizedDescription]; From a46bf8180d76131eafe84ab44e0436322073820c Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 16 Jan 2018 13:36:09 +0100 Subject: [PATCH 024/182] task cancelled error message --- ios/RNFetchBlobRequest.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 4b2ca9a1f..c77668ce8 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -374,7 +374,11 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom }); if (error) { - errMsg = [error localizedDescription]; + if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) { + errMsg = @"task cancelled"; + } else { + errMsg = [error localizedDescription]; + } } if (respFile) { From 684f6df2838b41536a0e535966ffa5586866e79b Mon Sep 17 00:00:00 2001 From: nd-02110114 Date: Tue, 23 Jan 2018 15:05:05 +0900 Subject: [PATCH 025/182] add close tag --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 883f0fd13..edb5e170e 100644 --- a/README.md +++ b/README.md @@ -644,7 +644,7 @@ RNFetchBlob.fs.readStream( console.log('oops', err) }) ifstream.onEnd(() => { - }) }) ``` From 58df91fe8dd446dc3c3cb06474bd76d63bef13ff Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Tue, 20 Feb 2018 09:26:24 +0100 Subject: [PATCH 026/182] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 883f0fd13..e64e8f34c 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,14 @@ A project committed to making file access and data transfer easier and more efficient for React Native developers. > For Firebase Storage solution, please upgrade to the latest version for the best compatibility. +

## RNFB MAINTAINER GONE MISSING (Help Wanted) -wkh237's last Github activity was in September 2017. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here. +wkh237's last Github activity was in September 2017, and he has not reacted to emails either. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here. I don't have admin rights, I cannot accept PRs, I cannot given anyone else rights on this repo, somebody needs to fork it and become a full maintainer. +

## Features From e6480db3192b0c44721899bfc8d8966780e80026 Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Tue, 20 Feb 2018 09:26:57 +0100 Subject: [PATCH 027/182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e64e8f34c..10ca0df76 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A project committed to making file access and data transfer easier and more effi ## RNFB MAINTAINER GONE MISSING (Help Wanted) -wkh237's last Github activity was in September 2017, and he has not reacted to emails either. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here. I don't have admin rights, I cannot accept PRs, I cannot given anyone else rights on this repo, somebody needs to fork it and become a full maintainer. +wkh237's last Github activity was in September 2017, and he has not reacted to emails either. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here. I don't have admin rights, I cannot accept PRs, I cannot give anyone else rights on this repo, somebody needs to fork it and become a full maintainer.

From 62f12a128f67aa39bae8b76e9cf794c6f9ccdf56 Mon Sep 17 00:00:00 2001 From: Klaas Landsman Date: Wed, 7 Mar 2018 09:56:01 +0100 Subject: [PATCH 028/182] Implement `requiresMainQueueSetup`, fixes #553 --- ios/RNFetchBlob/RNFetchBlob.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index 47bda76c5..eb3c6d85a 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -70,6 +70,11 @@ - (NSDictionary *)constantsToExport }; } ++ (BOOL)requiresMainQueueSetup +{ + return YES; +} + // Fetch blob data request RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options taskId:(NSString *)taskId From 05768a26afb9f6c4a813c706324e7798dffe068b Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Tue, 20 Mar 2018 17:00:49 +0100 Subject: [PATCH 029/182] Update README.md --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 486897675..5a655c565 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,23 @@ -# react-native-fetch-blob -[![release](https://img.shields.io/github/release/wkh237/react-native-fetch-blob.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/react-native-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/react-native-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/react-native-fetch-blob.svg?maxAge=2592000&style=flat-square)]() - +## RNFB MAINTAINER GONE MISSING (Help Wanted) -A project committed to making file access and data transfer easier and more efficient for React Native developers. -> For Firebase Storage solution, please upgrade to the latest version for the best compatibility. +wkh237's last Github activity was in September 2017, and he has not reacted to emails either. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here. I don't have admin rights, I cannot accept PRs, I cannot give anyone else rights on this repo, somebody needs to fork it and become a full maintainer. -

-## RNFB MAINTAINER GONE MISSING (Help Wanted) +## About Pull Requests -wkh237's last Github activity was in September 2017, and he has not reacted to emails either. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here. I don't have admin rights, I cannot accept PRs, I cannot give anyone else rights on this repo, somebody needs to fork it and become a full maintainer. +I cannot (@lll000111) handle them, I'm not the owner. My own PRs are still in the queue waiting for review from the owner. I coulöd merge the PRs of others but not my own... but since I am in no position to do anything with this repo, I don't do mobile development, I don't even have a smart phone, I won't merge anything. **In any case though,** you should not send PRs for `master` but against the `0.10.9` branch. It already is quite different from `master`. So try that branch first if you want to patch, not `master`, even for your own fork.

+
+ +# react-native-fetch-blob +[![release](https://img.shields.io/github/release/wkh237/react-native-fetch-blob.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/react-native-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/react-native-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/react-native-fetch-blob.svg?maxAge=2592000&style=flat-square)]() + + +A project committed to making file access and data transfer easier and more efficient for React Native developers. +> For Firebase Storage solution, please upgrade to the latest version for the best compatibility. ## Features - Transfer data directly from/to storage without BASE64 bridging From c4c3d43636519106c94f9d1db6afca90f658243f Mon Sep 17 00:00:00 2001 From: KittenWithHerbs Date: Tue, 20 Mar 2018 17:03:43 +0100 Subject: [PATCH 030/182] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a655c565..177e968f9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ wkh237's last Github activity was in September 2017, and he has not reacted to e ## About Pull Requests -I cannot (@lll000111) handle them, I'm not the owner. My own PRs are still in the queue waiting for review from the owner. I coulöd merge the PRs of others but not my own... but since I am in no position to do anything with this repo, I don't do mobile development, I don't even have a smart phone, I won't merge anything. **In any case though,** you should not send PRs for `master` but against the `0.10.9` branch. It already is quite different from `master`. So try that branch first if you want to patch, not `master`, even for your own fork. +I (@lll000111) cannot handle them, I'm not the owner. My own PRs are still in the queue waiting for review from the owner. I could merge the PRs of others but not my own(!)... but since I am in no position to manage this repo — I don't do mobile development, I don't even have a smart phone — I won't merge anything. **In any case though,** you should not send PRs for `master` but against the `0.10.9` branch. It already is quite different from `master`. So try that branch first if you want to patch, not `master`, even for your own fork and your private patches.

From 0a638e35cad33ee33aef3df91fdd782493841991 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Thu, 22 Mar 2018 17:21:07 -0600 Subject: [PATCH 031/182] update readme with new maintainers message --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 177e968f9..80f1ef2d8 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,13 @@ -## RNFB MAINTAINER GONE MISSING (Help Wanted) +## New Maintainers -wkh237's last Github activity was in September 2017, and he has not reacted to emails either. Since there is a lot of work on issues and PRs that needs to be done, is there anybody who could provide a maintained fork of this package in the meantime? Create an issue and address (ping) me ([@lll000111](https://github.com/lll000111)), or send me an email, and I'll add a link to your maintained repo fork right here. I don't have admin rights, I cannot accept PRs, I cannot give anyone else rights on this repo, somebody needs to fork it and become a full maintainer. +We make quite a bit of use of react-native-fetch-blob at Jolt and would like to maintain the project. Feel free to open issues, PRs, etc. here as you would on the original repository. We will be investigating a new npm namespace under which to publish future versions of this library.
## About Pull Requests -I (@lll000111) cannot handle them, I'm not the owner. My own PRs are still in the queue waiting for review from the owner. I could merge the PRs of others but not my own(!)... but since I am in no position to manage this repo — I don't do mobile development, I don't even have a smart phone — I won't merge anything. **In any case though,** you should not send PRs for `master` but against the `0.10.9` branch. It already is quite different from `master`. So try that branch first if you want to patch, not `master`, even for your own fork and your private patches. +The `0.10.9` branch is the next branch intended to be released, so patches and pull requests should be applied to that branch if possible. -
-

# react-native-fetch-blob From fa38cd54d70641417d20b5d6430f845ef51e97ff Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sun, 25 Mar 2018 09:51:41 -0600 Subject: [PATCH 032/182] update README with correct directions for PRs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80f1ef2d8..6b4cfc75b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ We make quite a bit of use of react-native-fetch-blob at Jolt and would like to ## About Pull Requests -The `0.10.9` branch is the next branch intended to be released, so patches and pull requests should be applied to that branch if possible. +Bugfixes should be applied to the `0.10.9` branch and new features should be applied to the `0.11.0`. Documentation/README updates can be applied directly to `master`.
From fb63db99e0beccda99a2ec416a0f8b0ee809d750 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Tue, 27 Mar 2018 10:41:22 +0200 Subject: [PATCH 033/182] createFile methods with promises --- .../java/com/RNFetchBlob/RNFetchBlob.java | 8 ++++---- .../java/com/RNFetchBlob/RNFetchBlobFS.java | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index f5597d3ad..fae1f7d15 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -85,11 +85,11 @@ public Map getConstants() { } @ReactMethod - public void createFile(final String path, final String content, final String encode, final Callback callback) { + public void createFile(final String path, final String content, final String encode, final Promise promise) { threadPool.execute(new Runnable() { @Override public void run() { - RNFetchBlobFS.createFile(path, content, encode, callback); + RNFetchBlobFS.createFile(path, content, encode, promise); } }); } @@ -128,11 +128,11 @@ public void onHostDestroy() { } @ReactMethod - public void createFileASCII(final String path, final ReadableArray dataArray, final Callback callback) { + public void createFileASCII(final String path, final ReadableArray dataArray, final Promise promise) { threadPool.execute(new Runnable() { @Override public void run() { - RNFetchBlobFS.createFileASCII(path, dataArray, callback); + RNFetchBlobFS.createFileASCII(path, dataArray, promise); } }); } diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 0959c4f9f..614aced0f 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -727,7 +727,7 @@ public void onScanCompleted(String s, Uri uri) { * @param encoding Encoding of initial data. * @param callback RCT bridge callback. */ - static void createFile(String path, String data, String encoding, Callback callback) { + static void createFile(String path, String data, String encoding, Promise promise) { try { File dest = new File(path); boolean created = dest.createNewFile(); @@ -735,7 +735,7 @@ static void createFile(String path, String data, String encoding, Callback callb String orgPath = data.replace(RNFetchBlobConst.FILE_PREFIX, ""); File src = new File(orgPath); if(!src.exists()) { - callback.invoke("RNfetchBlob writeFileError", "source file : " + data + "not exists"); + promise.reject("RNfetchBlob writeFileError", "source file : " + data + "not exists"); return ; } FileInputStream fin = new FileInputStream(src); @@ -751,15 +751,15 @@ static void createFile(String path, String data, String encoding, Callback callb } else { if (!created) { - callback.invoke("create file error: failed to create file at path `" + path + "` for its parent path may not exists, or the file already exists. If you intended to overwrite the existing file use fs.writeFile instead."); + Promise.reject("create file error: failed to create file at path `" + path + "` for its parent path may not exists, or the file already exists. If you intended to overwrite the existing file use fs.writeFile instead."); return; } OutputStream ostream = new FileOutputStream(dest); ostream.write(RNFetchBlobFS.stringToBytes(data, encoding)); } - callback.invoke(null, path); + promise.resolve(path); } catch(Exception err) { - callback.invoke(err.getLocalizedMessage()); + promise.reject(err.getLocalizedMessage()); } } @@ -769,16 +769,16 @@ static void createFile(String path, String data, String encoding, Callback callb * @param data Content of new file * @param callback JS context callback */ - static void createFileASCII(String path, ReadableArray data, Callback callback) { + static void createFileASCII(String path, ReadableArray data, Promise promise) { try { File dest = new File(path); if(dest.exists()) { - callback.invoke("create file error: failed to create file at path `" + path + "`, file already exists."); + promise.reject("create file error: failed to create file at path `" + path + "`, file already exists."); return; } boolean created = dest.createNewFile(); if(!created) { - callback.invoke("create file error: failed to create file at path `" + path + "` for its parent path may not exists"); + promise.reject("create file error: failed to create file at path `" + path + "` for its parent path may not exists"); return; } OutputStream ostream = new FileOutputStream(dest); @@ -788,9 +788,9 @@ static void createFileASCII(String path, ReadableArray data, Callback callback) } ostream.write(chunk); chunk = null; - callback.invoke(null, path); + promise.resolve(path); } catch(Exception err) { - callback.invoke(err.getLocalizedMessage()); + promise.reject(err.getLocalizedMessage()); } } From b9172bb80b78995a3a749551f0a265c32ab88ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20St=C3=A5hl?= Date: Thu, 29 Mar 2018 09:47:01 +0200 Subject: [PATCH 034/182] Inform linter that we're handling android api versions correctly --- android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java b/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java index fef3ada97..de72ecaa1 100644 --- a/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java +++ b/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java @@ -1,5 +1,6 @@ package com.RNFetchBlob.Utils; +import android.annotation.TargetApi; import android.content.Context; import android.database.Cursor; import android.net.Uri; @@ -15,6 +16,7 @@ import java.io.FileOutputStream; public class PathResolver { + @TargetApi(19) public static String getRealPathFromURI(final Context context, final Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; From 2599ae4c00493d07027e593631fd12d1175dfaad Mon Sep 17 00:00:00 2001 From: Momen Zalabany Date: Wed, 11 Apr 2018 02:35:26 +0200 Subject: [PATCH 035/182] compatible with RN > 0.49 RN > 0.49 requires to implement requiresMainQueueSetup. this fix and suppress that yellow box warning ``` Module RNFetchBlob requires main queue setup since it overrides `init` but doesn't implement `requiresMainQueueSetup`. In a future release React Native will default to initializing all native modules on a background thread unless explicitly opted-out of. ``` --- ios/RNFetchBlob/RNFetchBlob.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index 246d6707c..794f6d39d 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -42,6 +42,10 @@ + (RCTBridge *)getRCTBridge return rootView.bridge; } ++ (BOOL)requiresMainQueueSetup { + return NO; +} + RCT_EXPORT_MODULE(); - (id) init { From 3b0c7ad393a31df1efbf2e189dd4cbaf03d49534 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 9 May 2018 21:50:11 -0500 Subject: [PATCH 036/182] response typo --- polyfill/Fetch.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polyfill/Fetch.js b/polyfill/Fetch.js index 7be52e084..3ecb5915c 100644 --- a/polyfill/Fetch.js +++ b/polyfill/Fetch.js @@ -73,7 +73,7 @@ class RNFetchBlobFetchPolyfill { // release blob cache created when sending request if(blobCache !== null && blobCache instanceof Blob) blobCache.close() - return Promise.resolve(new RNFetchBlobFetchRepsonse(resp)) + return Promise.resolve(new RNFetchBlobFetchResponse(resp)) }) }) @@ -97,7 +97,7 @@ class RNFetchBlobFetchPolyfill { } -class RNFetchBlobFetchRepsonse { +class RNFetchBlobFetchResponse { constructor(resp:FetchBlobResponse) { let info = resp.info() From 5750b0f93be5d4d7977be9057c7338ce7496bfbb Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 9 May 2018 21:58:29 -0500 Subject: [PATCH 037/182] revert readme --- README.md | 72 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 6b4cfc75b..5f73c6d81 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,3 @@ -## New Maintainers - -We make quite a bit of use of react-native-fetch-blob at Jolt and would like to maintain the project. Feel free to open issues, PRs, etc. here as you would on the original repository. We will be investigating a new npm namespace under which to publish future versions of this library. - -
- -## About Pull Requests - -Bugfixes should be applied to the `0.10.9` branch and new features should be applied to the `0.11.0`. Documentation/README updates can be applied directly to `master`. - -
- # react-native-fetch-blob [![release](https://img.shields.io/github/release/wkh237/react-native-fetch-blob.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/react-native-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/react-native-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/react-native-fetch-blob.svg?maxAge=2592000&style=flat-square)]() @@ -30,9 +18,9 @@ A project committed to making file access and data transfer easier and more effi * [Installation](#user-content-installation) * [HTTP Data Transfer](#user-content-http-data-transfer) * [Regular Request](#user-content-regular-request) - * [Download file](#download-example-fetch-files-that-need-authorization-token) + * [Download file](#user-content-download-example--fetch-files-that-needs-authorization-token) * [Upload file](#user-content-upload-example--dropbox-files-upload-api) - * [Multipart/form upload](#multipartform-data-example-post-form-data-with-file-and-data) + * [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data) * [Upload/Download progress](#user-content-uploaddownload-progress) * [Cancel HTTP request](#user-content-cancel-request) * [Android Media Scanner, and Download Manager Support](#user-content-android-media-scanner-and-download-manager-support) @@ -602,10 +590,12 @@ File Access APIs - [dirs](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#dirs) - [createFile](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#createfilepath-data-encodingpromise) - [writeFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writefilepathstring-contentstring--array-encodingstring-appendbooleanpromise) -- [appendFile (0.6.0) ](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#appendfilepathstring-contentstring--array-encodingstringpromise) +- [appendFile (0.6.0) ](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#appendfilepathstring-contentstring--arraynumber-encodingstring-promisenumber) - [readFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readfilepath-encodingpromise) -- [readStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersizepromise) -- [writeStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writestreampathstring-encodingstring-appendbooleanpromise) +- [readStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersize-interval-promisernfbreadstream) +- [hash (0.10.9)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#hashpath-algorithm-promise) +- [writeStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writestreampathstring-encodingstringpromise) +- [hash](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#hashpath-algorithmpromise) - [unlink](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#unlinkpathstringpromise) - [mkdir](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#mkdirpathstringpromise) - [ls](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#lspathstringpromise) @@ -648,13 +638,52 @@ RNFetchBlob.fs.readStream( console.log('oops', err) }) ifstream.onEnd(() => { - + ofstream.write('foo')) +.then(ofstream => ofstream.write('bar')) +.then(ofstream => ofstream.write('foobar')) +.then(ofstream => ofstream.close()) +.catch(console.error) +``` + +or + +```js +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: + ```js RNFetchBlob.fs.writeStream( PATH_TO_FILE, @@ -663,13 +692,18 @@ RNFetchBlob.fs.writeStream( // 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 From ff6a2a62901ddc657d1137f630ce29c1283d51b4 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 9 May 2018 22:00:12 -0500 Subject: [PATCH 038/182] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f73c6d81..1baebfd9d 100644 --- a/README.md +++ b/README.md @@ -833,4 +833,4 @@ See [release notes](https://github.com/wkh237/react-native-fetch-blob/releases) ### Development If you're interested in hacking this module, check our [development guide](https://github.com/wkh237/react-native-fetch-blob/wiki/Home), there might be some helpful information. -Please feel free to make a PR or file an issue. +Please feel free to make a PR or file an issue. \ No newline at end of file From c5de6f806b754cd40fdd326e6c77705353fccdf1 Mon Sep 17 00:00:00 2001 From: Gennady Basov Date: Thu, 10 May 2018 09:48:56 +0300 Subject: [PATCH 039/182] Reject promise by iOS openDocument when a file is not opened --- ios/RNFetchBlob/RNFetchBlob.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index a7572d43b..a3c63aaf8 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -588,9 +588,12 @@ + (BOOL)requiresMainQueueSetup if(scheme == nil || [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:scheme]]) { dispatch_sync(dispatch_get_main_queue(), ^{ - [documentController presentPreviewAnimated:YES]; + if([documentController presentPreviewAnimated:YES]) { + resolve(@[[NSNull null]]); + } else { + reject(@"EINVAL", @"document is not supported", nil); + } }); - resolve(@[[NSNull null]]); } else { reject(@"EINVAL", @"scheme is not supported", nil); } From dcd3aaa5eb94c612ed206a159cb3a38fe0ff72b4 Mon Sep 17 00:00:00 2001 From: Antoine Taillefer Date: Tue, 15 May 2018 08:50:14 +0200 Subject: [PATCH 040/182] Fix RNFetchBlobBody#getRequestStream method name --- android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java index 15045cffa..5b9ba46e0 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java @@ -68,7 +68,7 @@ RNFetchBlobBody setBody(String body) { try { switch (requestType) { case SingleFile: - requestStream = getReuqestStream(); + requestStream = getRequestStream(); contentLength = requestStream.available(); break; case AsIs: @@ -135,7 +135,7 @@ boolean clearRequestBody() { return true; } - private InputStream getReuqestStream() throws Exception { + private InputStream getRequestStream() throws Exception { // upload from storage if (rawBody.startsWith(RNFetchBlobConst.FILE_PREFIX)) { From cd1eb1e37ffb5347468668483b0acd227879f49f Mon Sep 17 00:00:00 2001 From: Antoine Taillefer Date: Tue, 15 May 2018 08:54:07 +0200 Subject: [PATCH 041/182] Handle Android content URIs for upload --- .../java/com/RNFetchBlob/RNFetchBlobBody.java | 39 ++++++++++++++++++- .../com/RNFetchBlob/RNFetchBlobConst.java | 1 + .../java/com/RNFetchBlob/RNFetchBlobReq.java | 3 +- index.js | 3 +- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java index 5b9ba46e0..df4e9088e 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.util.ArrayList; +import android.net.Uri; import okhttp3.MediaType; import okhttp3.RequestBody; import okio.BufferedSink; @@ -159,6 +160,13 @@ private InputStream getRequestStream() throws Exception { throw new Exception("error when getting request stream: " +e.getLocalizedMessage()); } } + } else if (rawBody.startsWith(RNFetchBlobConst.CONTENT_PREFIX)) { + String contentURI = rawBody.substring(RNFetchBlobConst.CONTENT_PREFIX.length()); + try { + return RNFetchBlob.RCTContext.getContentResolver().openInputStream(Uri.parse(contentURI)); + } catch (Exception e) { + throw new Exception("error when getting request stream for content URI: " + contentURI, e); + } } // base 64 encoded else { @@ -224,6 +232,20 @@ private File createMultipartBodyCache() throws IOException { RNFetchBlobUtils.emitWarningEvent("Failed to create form data from path :" + orgPath + ", file not exists."); } } + } else if (data.startsWith(RNFetchBlobConst.CONTENT_PREFIX)) { + String contentURI = data.substring(RNFetchBlobConst.CONTENT_PREFIX.length()); + InputStream is = null; + try { + is = ctx.getContentResolver().openInputStream(Uri.parse(contentURI)); + pipeStreamToFileStream(is, os); + } catch(Exception e) { + RNFetchBlobUtils.emitWarningEvent( + "Failed to create form data from content URI:" + contentURI + ", " + e.getLocalizedMessage()); + } finally { + if (is != null) { + is.close(); + } + } } // base64 embedded file content else { @@ -289,7 +311,7 @@ private void pipeStreamToFileStream(InputStream is, FileOutputStream os) throws * Compute approximate content length for form data * @return ArrayList */ - private ArrayList countFormDataLength() { + private ArrayList countFormDataLength() throws IOException { long total = 0; ArrayList list = new ArrayList<>(); ReactApplicationContext ctx = RNFetchBlob.RCTContext; @@ -320,6 +342,21 @@ else if (field.filename != null) { File file = new File(RNFetchBlobFS.normalizePath(orgPath)); total += file.length(); } + } else if (data.startsWith(RNFetchBlobConst.CONTENT_PREFIX)) { + String contentURI = data.substring(RNFetchBlobConst.CONTENT_PREFIX.length()); + InputStream is = null; + try { + is = ctx.getContentResolver().openInputStream(Uri.parse(contentURI)); + long length = is.available(); + total += length; + } catch(Exception e) { + RNFetchBlobUtils.emitWarningEvent( + "Failed to estimate form data length from content URI:" + contentURI + ", " + e.getLocalizedMessage()); + } finally { + if (is != null) { + is.close(); + } + } } // base64 embedded file content else { diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobConst.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobConst.java index 015cc8954..b86902a31 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobConst.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobConst.java @@ -7,6 +7,7 @@ public class RNFetchBlobConst { public static final String EVENT_HTTP_STATE = "RNFetchBlobState"; public static final String EVENT_MESSAGE = "RNFetchBlobMessage"; public static final String FILE_PREFIX = "RNFetchBlob-file://"; + public static final String CONTENT_PREFIX = "RNFetchBlob-content://"; public static final String FILE_PREFIX_BUNDLE_ASSET = "bundle-assets://"; public static final String FILE_PREFIX_CONTENT = "content://"; public static final String DATA_ENCODE_URI = "uri"; diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index aaa837cee..5be1088af 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -266,7 +266,8 @@ else if(cType.isEmpty()) { requestType = RequestType.SingleFile; } if(rawRequestBody != null) { - if(rawRequestBody.startsWith(RNFetchBlobConst.FILE_PREFIX)) { + if (rawRequestBody.startsWith(RNFetchBlobConst.FILE_PREFIX) + || rawRequestBody.startsWith(RNFetchBlobConst.CONTENT_PREFIX)) { requestType = RequestType.SingleFile; } else if (cType.toLowerCase().contains(";base64") || cType.toLowerCase().startsWith("application/octet")) { diff --git a/index.js b/index.js index bd67986fa..6d9ea348f 100644 --- a/index.js +++ b/index.js @@ -79,7 +79,8 @@ if(!RNFetchBlob || !RNFetchBlob.fetchBlobForm || !RNFetchBlob.fetchBlob) { } function wrap(path:string):string { - return 'RNFetchBlob-file://' + path + const prefix = path.startsWith('content://') ? 'RNFetchBlob-content://' : 'RNFetchBlob-file://' + return prefix + path } /** From 853fed3679769f3616298a2db7054c0919c7eeae Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Wed, 30 May 2018 16:44:00 +0200 Subject: [PATCH 042/182] Fix typo: "Status" instead of "Statu" --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index aaa837cee..65214c9b8 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -668,7 +668,7 @@ public void onReceive(Context context, Intent intent) { // #297 handle failed request int statusCode = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); if(statusCode == DownloadManager.STATUS_FAILED) { - this.callback.invoke("Download manager failed to download from " + this.url + ". Statu Code = " + statusCode, null, null); + this.callback.invoke("Download manager failed to download from " + this.url + ". Status Code = " + statusCode, null, null); return; } String contentUri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); From 393c668c38a152c891cd09fd121edc4c258f6335 Mon Sep 17 00:00:00 2001 From: Gui Meira Date: Wed, 30 May 2018 14:11:59 -0300 Subject: [PATCH 043/182] Update README with proper status code handling --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6b4cfc75b..44ba5ab7c 100644 --- a/README.md +++ b/README.md @@ -192,16 +192,20 @@ RNFetchBlob.fetch('GET', 'http://www.example.com/images/img1.png', { Authorization : 'Bearer access-token...', // more headers .. }) - // when response status code is 200 .then((res) => { - // 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() - + 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 + } }) - // Status code is not 200 + // Something went wrong: .catch((errorMessage, statusCode) => { // error handling }) From a88b59f0e9f62330a5f2a5a7921b6869ba7228b3 Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 1 Jun 2018 10:46:41 -0300 Subject: [PATCH 044/182] Solve Android security exposed app error --- .../gradle/wrapper/gradle-wrapper.properties | 4 +-- android/src/main/AndroidManifest.xml | 34 +++++++++++++++++-- .../java/com/RNFetchBlob/RNFetchBlob.java | 33 +++++++++++++++--- android/src/main/res/xml/provider_paths.xml | 9 +++++ 4 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 android/src/main/res/xml/provider_paths.xml diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index c60fdf0b6..317d481f3 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Aug 12 07:48:35 CEST 2017 +#Fri Jun 01 10:33:07 BRT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 807904417..afa9020b2 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,9 +1,37 @@ - + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 64b0b4833..0434bd829 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -3,7 +3,10 @@ import android.app.Activity; import android.app.DownloadManager; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; +import android.support.v4.content.FileProvider; import android.util.SparseArray; import com.facebook.react.bridge.ActivityEventListener; @@ -21,9 +24,12 @@ import com.facebook.react.modules.network.ForwardingCookieHandler; import com.facebook.react.modules.network.CookieJarContainer; import com.facebook.react.modules.network.OkHttpClientProvider; +import com.squareup.okhttp.OkHttpClient; + import okhttp3.OkHttpClient; import okhttp3.JavaNetCookieJar; +import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; @@ -105,10 +111,29 @@ public void run() { @ReactMethod public void actionViewIntent(String path, String mime, final Promise promise) { try { - Intent intent= new Intent(Intent.ACTION_VIEW) - .setDataAndType(Uri.parse("file://" + path), mime); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - this.getReactApplicationContext().startActivity(intent); + Uri uriForFile = FileProvider.getUriForFile(getCurrentActivity(), + this.getReactApplicationContext().getPackageName() + ".provider", new File(path)); + + if (Build.VERSION.SDK_INT >= 24) { + // Create the intent with data and type + Intent intent = new Intent(Intent.ACTION_VIEW) + .setDataAndType(uriForFile, mime); + + // Set flag to give temporary permission to external app to use FileProvider + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // Validate that the device can open the file + PackageManager pm = getCurrentActivity().getPackageManager(); + if (intent.resolveActivity(pm) != null) { + this.getReactApplicationContext().startActivity(intent); + } + + } else { + Intent intent = new Intent(Intent.ACTION_VIEW) + .setDataAndType(Uri.parse("file://" + path), mime).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + this.getReactApplicationContext().startActivity(intent); + } ActionViewVisible = true; final LifecycleEventListener listener = new LifecycleEventListener() { diff --git a/android/src/main/res/xml/provider_paths.xml b/android/src/main/res/xml/provider_paths.xml new file mode 100644 index 000000000..1434ff0ad --- /dev/null +++ b/android/src/main/res/xml/provider_paths.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file From 298a4de4f72305b7b3c33699209acb263bcace6a Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 1 Jun 2018 10:59:33 -0300 Subject: [PATCH 045/182] fix class imports --- .../java/com/RNFetchBlob/RNFetchBlob.java | 84 ++++++++----------- 1 file changed, 35 insertions(+), 49 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 0434bd829..f0f73a594 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -7,7 +7,6 @@ import android.net.Uri; import android.os.Build; import android.support.v4.content.FileProvider; -import android.util.SparseArray; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.Callback; @@ -24,8 +23,6 @@ import com.facebook.react.modules.network.ForwardingCookieHandler; import com.facebook.react.modules.network.CookieJarContainer; import com.facebook.react.modules.network.OkHttpClientProvider; -import com.squareup.okhttp.OkHttpClient; - import okhttp3.OkHttpClient; import okhttp3.JavaNetCookieJar; @@ -41,23 +38,26 @@ public class RNFetchBlob extends ReactContextBaseJavaModule { + // Cookies + private final ForwardingCookieHandler mCookieHandler; + private final CookieJarContainer mCookieJarContainer; private final OkHttpClient mClient; static ReactApplicationContext RCTContext; - private static LinkedBlockingQueue taskQueue = new LinkedBlockingQueue<>(); - private static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); + static LinkedBlockingQueue taskQueue = new LinkedBlockingQueue<>(); + static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); static LinkedBlockingQueue fsTaskQueue = new LinkedBlockingQueue<>(); - private static ThreadPoolExecutor fsThreadPool = new ThreadPoolExecutor(2, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); - private static boolean ActionViewVisible = false; - private static SparseArray promiseTable = new SparseArray<>(); + static ThreadPoolExecutor fsThreadPool = new ThreadPoolExecutor(2, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); + static public boolean ActionViewVisible = false; + static HashMap promiseTable = new HashMap<>(); public RNFetchBlob(ReactApplicationContext reactContext) { super(reactContext); mClient = OkHttpClientProvider.getOkHttpClient(); - ForwardingCookieHandler mCookieHandler = new ForwardingCookieHandler(reactContext); - CookieJarContainer mCookieJarContainer = (CookieJarContainer) mClient.cookieJar(); + mCookieHandler = new ForwardingCookieHandler(reactContext); + mCookieJarContainer = (CookieJarContainer) mClient.cookieJar(); mCookieJarContainer.setCookieJar(new JavaNetCookieJar(mCookieHandler)); RCTContext = reactContext; @@ -89,23 +89,14 @@ public Map getConstants() { } @ReactMethod - public void createFile(final String path, final String content, final String encode, final Promise promise) { + public void createFile(final String path, final String content, final String encode, final Callback callback) { threadPool.execute(new Runnable() { @Override public void run() { - RNFetchBlobFS.createFile(path, content, encode, promise); + RNFetchBlobFS.createFile(path, content, encode, callback); } }); - } - @ReactMethod - public void createFileASCII(final String path, final ReadableArray dataArray, final Promise promise) { - threadPool.execute(new Runnable() { - @Override - public void run() { - RNFetchBlobFS.createFileASCII(path, dataArray, promise); - } - }); } @ReactMethod @@ -156,10 +147,21 @@ public void onHostDestroy() { }; RCTContext.addLifecycleEventListener(listener); } catch(Exception ex) { - promise.reject("EUNSPECIFIED", ex.getLocalizedMessage()); + promise.reject(ex.getLocalizedMessage()); } } + @ReactMethod + public void createFileASCII(final String path, final ReadableArray dataArray, final Callback callback) { + threadPool.execute(new Runnable() { + @Override + public void run() { + RNFetchBlobFS.createFileASCII(path, dataArray, callback); + } + }); + + } + @ReactMethod public void writeArrayChunk(final String streamId, final ReadableArray dataArray, final Callback callback) { RNFetchBlobFS.writeArrayChunk(streamId, dataArray, callback); @@ -171,8 +173,8 @@ public void unlink(String path, Callback callback) { } @ReactMethod - public void mkdir(String path, Promise promise) { - RNFetchBlobFS.mkdir(path, promise); + public void mkdir(String path, Callback callback) { + RNFetchBlobFS.mkdir(path, callback); } @ReactMethod @@ -188,6 +190,7 @@ public void run() { RNFetchBlobFS.cp(path, dest, callback); } }); + } @ReactMethod @@ -196,8 +199,8 @@ public void mv(String path, String dest, Callback callback) { } @ReactMethod - public void ls(String path, Promise promise) { - RNFetchBlobFS.ls(path, promise); + public void ls(String path, Callback callback) { + RNFetchBlobFS.ls(path, callback); } @ReactMethod @@ -248,6 +251,7 @@ public void run() { RNFetchBlobFS.writeFile(path, encoding, data, append, promise); } }); + } @ReactMethod @@ -282,24 +286,15 @@ public void run() { new RNFetchBlobFS(ctx).scanFile(p, m, callback); } }); - } - @ReactMethod - public void hash(final String path, final String algorithm, final Promise promise) { - threadPool.execute(new Runnable() { - @Override - public void run() { - RNFetchBlobFS.hash(path, algorithm, promise); - } - }); } + @ReactMethod /** * @param path Stream file path * @param encoding Stream encoding, should be one of `base64`, `ascii`, and `utf8` * @param bufferSize Stream buffer size, default to 4096 or 4095(base64). */ - @ReactMethod public void readStream(final String path, final String encoding, final int bufferSize, final int tick, final String streamId) { final ReactApplicationContext ctx = this.getReactApplicationContext(); fsThreadPool.execute(new Runnable() { @@ -373,10 +368,10 @@ public void getContentIntent(String mime, Promise promise) { @ReactMethod public void addCompleteDownload (ReadableMap config, Promise promise) { - DownloadManager dm = (DownloadManager) RCTContext.getSystemService(RCTContext.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) RNFetchBlob.RCTContext.getSystemService(RNFetchBlob.RCTContext.DOWNLOAD_SERVICE); String path = RNFetchBlobFS.normalizePath(config.getString("path")); if(path == null) { - promise.reject("EINVAL", "RNFetchblob.addCompleteDownload can not resolve URI:" + config.getString("path")); + promise.reject("RNFetchblob.addCompleteDownload can not resolve URI:" + config.getString("path"), "RNFetchblob.addCompleteDownload can not resolve URI:" + path); return; } try { @@ -393,18 +388,9 @@ public void addCompleteDownload (ReadableMap config, Promise promise) { promise.resolve(null); } catch(Exception ex) { - promise.reject("EUNSPECIFIED", ex.getLocalizedMessage()); + promise.reject("RNFetchblob.addCompleteDownload failed", ex.getStackTrace().toString()); } } - @ReactMethod - public void getSDCardDir(Promise promise) { - RNFetchBlobFS.getSDCardDir(promise); - } - - @ReactMethod - public void getSDCardApplicationDir(Promise promise) { - RNFetchBlobFS.getSDCardApplicationDir(this.getReactApplicationContext(), promise); - } -} +} \ No newline at end of file From c66788ff233e2b8b7273295121d24b223b425e1a Mon Sep 17 00:00:00 2001 From: Augusto Date: Fri, 1 Jun 2018 11:09:40 -0300 Subject: [PATCH 046/182] fix class import --- .../java/com/RNFetchBlob/RNFetchBlob.java | 80 +++++++++++-------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index f0f73a594..b6cf7013e 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -7,6 +7,7 @@ import android.net.Uri; import android.os.Build; import android.support.v4.content.FileProvider; +import android.util.SparseArray; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.Callback; @@ -38,26 +39,23 @@ public class RNFetchBlob extends ReactContextBaseJavaModule { - // Cookies - private final ForwardingCookieHandler mCookieHandler; - private final CookieJarContainer mCookieJarContainer; private final OkHttpClient mClient; static ReactApplicationContext RCTContext; - static LinkedBlockingQueue taskQueue = new LinkedBlockingQueue<>(); - static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); + private static LinkedBlockingQueue taskQueue = new LinkedBlockingQueue<>(); + private static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); static LinkedBlockingQueue fsTaskQueue = new LinkedBlockingQueue<>(); - static ThreadPoolExecutor fsThreadPool = new ThreadPoolExecutor(2, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); - static public boolean ActionViewVisible = false; - static HashMap promiseTable = new HashMap<>(); + private static ThreadPoolExecutor fsThreadPool = new ThreadPoolExecutor(2, 10, 5000, TimeUnit.MILLISECONDS, taskQueue); + private static boolean ActionViewVisible = false; + private static SparseArray promiseTable = new SparseArray<>(); public RNFetchBlob(ReactApplicationContext reactContext) { super(reactContext); mClient = OkHttpClientProvider.getOkHttpClient(); - mCookieHandler = new ForwardingCookieHandler(reactContext); - mCookieJarContainer = (CookieJarContainer) mClient.cookieJar(); + ForwardingCookieHandler mCookieHandler = new ForwardingCookieHandler(reactContext); + CookieJarContainer mCookieJarContainer = (CookieJarContainer) mClient.cookieJar(); mCookieJarContainer.setCookieJar(new JavaNetCookieJar(mCookieHandler)); RCTContext = reactContext; @@ -89,14 +87,23 @@ public Map getConstants() { } @ReactMethod - public void createFile(final String path, final String content, final String encode, final Callback callback) { + public void createFile(final String path, final String content, final String encode, final Promise promise) { threadPool.execute(new Runnable() { @Override public void run() { - RNFetchBlobFS.createFile(path, content, encode, callback); + RNFetchBlobFS.createFile(path, content, encode, promise); } }); + } + @ReactMethod + public void createFileASCII(final String path, final ReadableArray dataArray, final Promise promise) { + threadPool.execute(new Runnable() { + @Override + public void run() { + RNFetchBlobFS.createFileASCII(path, dataArray, promise); + } + }); } @ReactMethod @@ -147,21 +154,10 @@ public void onHostDestroy() { }; RCTContext.addLifecycleEventListener(listener); } catch(Exception ex) { - promise.reject(ex.getLocalizedMessage()); + promise.reject("EUNSPECIFIED", ex.getLocalizedMessage()); } } - @ReactMethod - public void createFileASCII(final String path, final ReadableArray dataArray, final Callback callback) { - threadPool.execute(new Runnable() { - @Override - public void run() { - RNFetchBlobFS.createFileASCII(path, dataArray, callback); - } - }); - - } - @ReactMethod public void writeArrayChunk(final String streamId, final ReadableArray dataArray, final Callback callback) { RNFetchBlobFS.writeArrayChunk(streamId, dataArray, callback); @@ -173,8 +169,8 @@ public void unlink(String path, Callback callback) { } @ReactMethod - public void mkdir(String path, Callback callback) { - RNFetchBlobFS.mkdir(path, callback); + public void mkdir(String path, Promise promise) { + RNFetchBlobFS.mkdir(path, promise); } @ReactMethod @@ -190,7 +186,6 @@ public void run() { RNFetchBlobFS.cp(path, dest, callback); } }); - } @ReactMethod @@ -199,8 +194,8 @@ public void mv(String path, String dest, Callback callback) { } @ReactMethod - public void ls(String path, Callback callback) { - RNFetchBlobFS.ls(path, callback); + public void ls(String path, Promise promise) { + RNFetchBlobFS.ls(path, promise); } @ReactMethod @@ -251,7 +246,6 @@ public void run() { RNFetchBlobFS.writeFile(path, encoding, data, append, promise); } }); - } @ReactMethod @@ -286,15 +280,24 @@ public void run() { new RNFetchBlobFS(ctx).scanFile(p, m, callback); } }); - } @ReactMethod + public void hash(final String path, final String algorithm, final Promise promise) { + threadPool.execute(new Runnable() { + @Override + public void run() { + RNFetchBlobFS.hash(path, algorithm, promise); + } + }); + } + /** * @param path Stream file path * @param encoding Stream encoding, should be one of `base64`, `ascii`, and `utf8` * @param bufferSize Stream buffer size, default to 4096 or 4095(base64). */ + @ReactMethod public void readStream(final String path, final String encoding, final int bufferSize, final int tick, final String streamId) { final ReactApplicationContext ctx = this.getReactApplicationContext(); fsThreadPool.execute(new Runnable() { @@ -368,10 +371,10 @@ public void getContentIntent(String mime, Promise promise) { @ReactMethod public void addCompleteDownload (ReadableMap config, Promise promise) { - DownloadManager dm = (DownloadManager) RNFetchBlob.RCTContext.getSystemService(RNFetchBlob.RCTContext.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) RCTContext.getSystemService(RCTContext.DOWNLOAD_SERVICE); String path = RNFetchBlobFS.normalizePath(config.getString("path")); if(path == null) { - promise.reject("RNFetchblob.addCompleteDownload can not resolve URI:" + config.getString("path"), "RNFetchblob.addCompleteDownload can not resolve URI:" + path); + promise.reject("EINVAL", "RNFetchblob.addCompleteDownload can not resolve URI:" + config.getString("path")); return; } try { @@ -388,9 +391,18 @@ public void addCompleteDownload (ReadableMap config, Promise promise) { promise.resolve(null); } catch(Exception ex) { - promise.reject("RNFetchblob.addCompleteDownload failed", ex.getStackTrace().toString()); + promise.reject("EUNSPECIFIED", ex.getLocalizedMessage()); } } + @ReactMethod + public void getSDCardDir(Promise promise) { + RNFetchBlobFS.getSDCardDir(promise); + } + + @ReactMethod + public void getSDCardApplicationDir(Promise promise) { + RNFetchBlobFS.getSDCardApplicationDir(this.getReactApplicationContext(), promise); + } } \ No newline at end of file From 4c4c5eab7dfec84d748e814e19fe69e2f468efa3 Mon Sep 17 00:00:00 2001 From: Nicolas Van Eenaeme Date: Mon, 4 Jun 2018 13:44:24 +0200 Subject: [PATCH 047/182] sometimes getExternalFilesDir returns null, and the app crashes in this case --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 7a7910546..7e29fcce2 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -213,7 +213,11 @@ static public Map getSystemfolders(ReactApplicationContext ctx) state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { res.put("SDCardDir", Environment.getExternalStorageDirectory().getAbsolutePath()); - res.put("SDCardApplicationDir", ctx.getExternalFilesDir(null).getParentFile().getAbsolutePath()); + + File externalDirectory = ctx.getExternalFilesDir(null); + if (externalDirectory != null) { + res.put("SDCardApplicationDir", externalDirectory.getParentFile().getAbsolutePath()); + } } res.put("MainBundleDir", ctx.getApplicationInfo().dataDir); return res; From 3edacb8421f9668d2aa61b55feeb2d1d4454af69 Mon Sep 17 00:00:00 2001 From: Miles Matthias Date: Mon, 11 Jun 2018 14:39:39 -0600 Subject: [PATCH 048/182] Add manual linking instructions There are a million issues around people having issues with automatically linking and having a link to manual instructions would address a lot of these up front. This also follows the instructions pattern of most react native modules. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 44ba5ab7c..70c6a4818 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,11 @@ After `0.10.3` you can install this package directly from Github # replace with any one of the branches npm install --save github:wkh237/react-native-fetch-blob-package# ``` + +**Manually Link Native Modules** + +If automatically linking doesn't work for you, see instructions on [manually linking](https://github.com/joltup/react-native-fetch-blob/wiki/Manually-Link-Package#index). + **Automatically Link Native Modules** For 0.29.2+ projects, simply link native packages via the following command (note: rnpm has been merged into react-native) From b2b5f5c09136c06ff09d7d83793b0e553aac394a Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Fri, 15 Jun 2018 08:19:21 +0200 Subject: [PATCH 049/182] No depracation warning on instantiating dirs --- fs.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/fs.js b/fs.js index 2b4b3ba78..54807adf4 100644 --- a/fs.js +++ b/fs.js @@ -20,17 +20,8 @@ const dirs = { MovieDir : RNFetchBlob.MovieDir, DownloadDir : RNFetchBlob.DownloadDir, DCIMDir : RNFetchBlob.DCIMDir, - get SDCardDir() { - console.warn('SDCardDir as a constant is deprecated and will be removed in feature release. ' + - 'Use RNFetchBlob.android.getSDCardDir():Promise instead.'); - return RNFetchBlob.SDCardDir; - }, - get SDCardApplicationDir() { - console.warn('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.'); - return RNFetchBlob.SDCardApplicationDir; - }, + SDCardDir: RNFetchBlob.SDCardDir, + SDCardApplicationDir: RNFetchBlob.SDCardApplicationDir, MainBundleDir : RNFetchBlob.MainBundleDir, LibraryDir : RNFetchBlob.LibraryDir } From 63432aee1b8eeea00148959b272c61680fb3601f Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Fri, 15 Jun 2018 08:24:14 +0200 Subject: [PATCH 050/182] Depracation comment in code --- fs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs.js b/fs.js index 54807adf4..52e547c47 100644 --- a/fs.js +++ b/fs.js @@ -21,8 +21,8 @@ const dirs = { DownloadDir : RNFetchBlob.DownloadDir, DCIMDir : RNFetchBlob.DCIMDir, SDCardDir: RNFetchBlob.SDCardDir, - SDCardApplicationDir: RNFetchBlob.SDCardApplicationDir, - MainBundleDir : RNFetchBlob.MainBundleDir, + SDCardApplicationDir: RNFetchBlob.SDCardApplicationDir, // Deprecated + MainBundleDir : RNFetchBlob.MainBundleDir, // Depracated LibraryDir : RNFetchBlob.LibraryDir } From c7374e783c69fab65751c6186cdc4a76dba255c1 Mon Sep 17 00:00:00 2001 From: Artur Chrusciel Date: Fri, 15 Jun 2018 08:24:48 +0200 Subject: [PATCH 051/182] Depracated comment fix --- fs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs.js b/fs.js index 52e547c47..e61f44312 100644 --- a/fs.js +++ b/fs.js @@ -20,9 +20,9 @@ const dirs = { MovieDir : RNFetchBlob.MovieDir, DownloadDir : RNFetchBlob.DownloadDir, DCIMDir : RNFetchBlob.DCIMDir, - SDCardDir: RNFetchBlob.SDCardDir, + SDCardDir: RNFetchBlob.SDCardDir, // Depracated SDCardApplicationDir: RNFetchBlob.SDCardApplicationDir, // Deprecated - MainBundleDir : RNFetchBlob.MainBundleDir, // Depracated + MainBundleDir : RNFetchBlob.MainBundleDir, LibraryDir : RNFetchBlob.LibraryDir } From 69a662af517e34f456f159dcfa0eddd3fae6bbc3 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 10:40:04 -0600 Subject: [PATCH 052/182] remove duplicate requiresMainQueueSetup declaration fixes #64 --- ios/RNFetchBlob/RNFetchBlob.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index 4525caad2..5399ab7c7 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -74,11 +74,6 @@ - (NSDictionary *)constantsToExport }; } -+ (BOOL)requiresMainQueueSetup -{ - return YES; -} - // Fetch blob data request RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options taskId:(NSString *)taskId From 37b0ecf12e4b0ab4e3f65b9ac9b9a41a141dbb83 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 13:46:33 -0600 Subject: [PATCH 053/182] remove obsolete PR template, moving to master based dev --- .github/PULL_REQUEST_TEMPLATE | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE deleted file mode 100644 index b03e3e8e3..000000000 --- a/.github/PULL_REQUEST_TEMPLATE +++ /dev/null @@ -1,5 +0,0 @@ -Thank you for making a pull request ! Just a gentle reminder :) - -1. If the PR is offering a feature please make the request to our "Feature Branch" 0.11.0 -2. Bug fix request to "Bug Fix Branch" 0.10.9 -3. Correct README.md can directly to master From 39dd24bc2041827587b11d8147b8629265adcac0 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 13:57:22 -0600 Subject: [PATCH 054/182] update package.json metadata --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a93dba81d..9835f37b0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "react-native-fetch-blob", + "name": "rn-fetch-blob", "version": "0.10.8", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", @@ -27,12 +27,12 @@ } }, "repository": { - "url": "https://github.com/wkh237/react-native-fetch-blob.git" + "url": "https://github.com/joltup/react-native-fetch-blob.git" }, - "author": "wkh237 ", + "author": "Joltup", "license": "MIT", "contributors": [ "Ben ", - "" + "wkh237 " ] } From 581b3343c3f10584977db9d9431dd3cbbfecb463 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 13:57:45 -0600 Subject: [PATCH 055/182] 0.10.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9835f37b0..e083504f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.8", + "version": "0.10.9", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 34176c54ba29faca7929d7f8a204f17531ebd5e8 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 14:17:20 -0600 Subject: [PATCH 056/182] Update README to reflect new package name --- README.md | 108 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 3b38b7efe..35b798558 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ -# react-native-fetch-blob -[![release](https://img.shields.io/github/release/wkh237/react-native-fetch-blob.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/react-native-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/react-native-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/wkh237/react-native-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/react-native-fetch-blob.svg?maxAge=2592000&style=flat-square)]() +# New Releases +In order to publish new releases from this fork, we have renamed this project to +`rn-fetch-blob` and published to `https://www.npmjs.com/package/rn-fetch-blob`. + +# rn-fetch-blob +[![release](https://img.shields.io/github/release/joltup/rn-fetch-blob.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/rn-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/rn-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/rn-fetch-blob.svg?maxAge=2592000&style=flat-square)]() A project committed to making file access and data transfer easier and more efficient for React Native developers. @@ -13,7 +17,7 @@ A project committed to making file access and data transfer easier and more effi - Blob, File, XMLHttpRequest polyfills that make browser-based library available in RN (experimental) - JSON stream supported base on [Oboe.js](https://github.com/jimhigson/oboe.js/) @jimhigson -## TOC (visit [Wiki](https://github.com/wkh237/react-native-fetch-blob/wiki) to get the complete documentation) +## TOC (visit [Wiki](https://github.com/joltup/rn-fetch-blob/wiki) to get the complete documentation) * [About](#user-content-about) * [Installation](#user-content-installation) * [HTTP Data Transfer](#user-content-http-data-transfer) @@ -33,7 +37,7 @@ A project committed to making file access and data transfer easier and more effi * [Manage cached files](#user-content-cache-file-management) * [Web API Polyfills](#user-content-web-api-polyfills) * [Performance Tips](#user-content-performance-tips) -* [API References](https://github.com/wkh237/react-native-fetch-blob/wiki/Fetch-API) +* [API References](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API) * [Caveats](#user-content-caveats) * [Development](#user-content-development) @@ -43,7 +47,7 @@ This project was started in the cause of solving issue [facebook/react-native#85 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](https://github.com/wkh237/rn-firebase-storage-upload-sample) +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](https://github.com/joltup/rn-firebase-storage-upload-sample) ## Installation @@ -51,26 +55,26 @@ In `0.8.0` we introduced experimental Web API polyfills that make it possible to Install package from npm ```sh -npm install --save react-native-fetch-blob +npm install --save rn-fetch-blob ``` Or if using CocoaPods, add the pod to your `Podfile` ``` -pod 'react-native-fetch-blob', - :path => '../node_modules/react-native-fetch-blob' +pod 'rn-fetch-blob', + :path => '../node_modules/rn-fetch-blob' ``` -After `0.10.3` you can install this package directly from Github +After `0.10.3` you can install this package directly from Github ```sh # replace with any one of the branches -npm install --save github:wkh237/react-native-fetch-blob-package# +npm install --save github:joltup/rn-fetch-blob-package# ``` **Manually Link Native Modules** -If automatically linking doesn't work for you, see instructions on [manually linking](https://github.com/joltup/react-native-fetch-blob/wiki/Manually-Link-Package#index). +If automatically linking doesn't work for you, see instructions on [manually linking](https://github.com/joltup/rn-fetch-blob/wiki/Manually-Link-Package#index). **Automatically Link Native Modules** @@ -98,7 +102,7 @@ pre 0.29 projects RNFB_ANDROID_PERMISSIONS=true rnpm link ``` -The link script might not take effect if you have non-default project structure, please visit [the wiki](https://github.com/wkh237/react-native-fetch-blob/wiki/Manually-Link-Package) to link the package manually. +The link script might not take effect if you have non-default project structure, please visit [the wiki](https://github.com/joltup/rn-fetch-blob/wiki/Manually-Link-Package) to link the package manually. **Grant Permission to External storage for Android 5.0 or lower** @@ -142,15 +146,15 @@ ES6 The module uses ES6 style export statement, simply use `import` to load the module. ```js -import RNFetchBlob from 'react-native-fetch-blob' +import RNFetchBlob from 'rn-fetch-blob' ``` ES5 -If you're using ES5 require statement to load the module, please add `default`. See [here](https://github.com/wkh237/react-native-fetch-blob/wiki/Trouble-Shooting#rnfetchblobfetch-is-not-a-function) for more detail. +If you're using ES5 require statement to load the module, please add `default`. See [here](https://github.com/joltup/rn-fetch-blob/wiki/Trouble-Shooting#rnfetchblobfetch-is-not-a-function) for more detail. ``` -var RNFetchBlob = require('react-native-fetch-blob').default +var RNFetchBlob = require('rn-fetch-blob').default ``` ## HTTP Data Transfer @@ -158,7 +162,7 @@ var RNFetchBlob = require('react-native-fetch-blob').default ### Regular Request -After `0.8.0` react-native-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 +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 @@ -251,7 +255,7 @@ RNFetchBlob **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](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#dirs) in v0.5.0 which represents commonly used directories. +If you prefer a particular file path rather than randomly generated one, you can use `path` option. We've added [several constants](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#dirs) in v0.5.0 which represents commonly used directories. ```js let dirs = RNFetchBlob.fs.dirs @@ -273,7 +277,7 @@ RNFetchBlob #### Upload example : Dropbox [files-upload](https://www.dropbox.com/developers/documentation/http/documentation#files-upload) API -`react-native-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. +`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. ```js @@ -356,7 +360,7 @@ Elements have property `filename` will be transformed into binary format, otherw }) ``` -What if you want to append a file to form data? Just like [upload a file from storage](#user-content-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](https://github.com/wkh237/react-native-fetch-blob/issues/94)). +What if you want to append a file to form data? Just like [upload a file from storage](#user-content-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](https://github.com/joltup/rn-fetch-blob/issues/94)). ```js @@ -467,7 +471,7 @@ task.cancel((err) => { ... }) 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](https://github.com/github/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](https://github.com/wkh237/react-native-fetch-blob/wiki/Fetch-API#fetch-replacement) +[See document and examples](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API#fetch-replacement) ### Android Media Scanner, and Download Manager Support @@ -524,7 +528,7 @@ RNFetchBlob }) ``` -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](https://github.com/wkh237/react-native-fetch-blob/issues/236). +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](https://github.com/joltup/rn-fetch-blob/issues/236). **Download Notification and Visibility in Download App (Android Only)** @@ -592,31 +596,31 @@ Or show an image in image viewer 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](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#differences-between-file-source) first. +Before start using file APIs, we recommend read [Differences between File Source](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#differences-between-file-source) first. File Access APIs -- [asset (0.6.2)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#assetfilenamestringstring) -- [dirs](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#dirs) -- [createFile](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#createfilepath-data-encodingpromise) -- [writeFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writefilepathstring-contentstring--array-encodingstring-appendbooleanpromise) -- [appendFile (0.6.0) ](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#appendfilepathstring-contentstring--arraynumber-encodingstring-promisenumber) -- [readFile (0.6.0)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readfilepath-encodingpromise) -- [readStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersize-interval-promisernfbreadstream) -- [hash (0.10.9)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#hashpath-algorithm-promise) -- [writeStream](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#writestreampathstring-encodingstringpromise) -- [hash](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#hashpath-algorithmpromise) -- [unlink](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#unlinkpathstringpromise) -- [mkdir](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#mkdirpathstringpromise) -- [ls](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#lspathstringpromise) -- [mv](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#mvfromstring-tostringpromise) -- [cp](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#cpsrcstring-deststringpromise) -- [exists](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#existspathstringpromise) -- [isDir](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#isdirpathstringpromise) -- [stat](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#statpathstringpromise) -- [lstat](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#lstatpathstringpromise) -- [scanFile (Android only)](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API#scanfilepathstringpromise-androi-only) - -See [File API](https://github.com/wkh237/react-native-fetch-blob/wiki/File-System-Access-API) for more information +- [asset (0.6.2)](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#assetfilenamestringstring) +- [dirs](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#dirs) +- [createFile](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#createfilepath-data-encodingpromise) +- [writeFile (0.6.0)](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#writefilepathstring-contentstring--array-encodingstring-appendbooleanpromise) +- [appendFile (0.6.0) ](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#appendfilepathstring-contentstring--arraynumber-encodingstring-promisenumber) +- [readFile (0.6.0)](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#readfilepath-encodingpromise) +- [readStream](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#readstreampath-encoding-buffersize-interval-promisernfbreadstream) +- [hash (0.10.9)](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#hashpath-algorithm-promise) +- [writeStream](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#writestreampathstring-encodingstringpromise) +- [hash](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#hashpath-algorithmpromise) +- [unlink](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#unlinkpathstringpromise) +- [mkdir](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#mkdirpathstringpromise) +- [ls](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#lspathstringpromise) +- [mv](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#mvfromstring-tostringpromise) +- [cp](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#cpsrcstring-deststringpromise) +- [exists](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#existspathstringpromise) +- [isDir](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#isdirpathstringpromise) +- [stat](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#statpathstringpromise) +- [lstat](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#lstatpathstringpromise) +- [scanFile (Android only)](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#scanfilepathstringpromise-androi-only) + +See [File API](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API) for more information ### File Stream @@ -780,7 +784,7 @@ RNFetchBlob.fetch('POST', 'http://example.com/upload', { 'Transfer-Encoding' : ' ### Self-Signed SSL Server -By default, react-native-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` +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` ```js RNFetchBlob.config({ @@ -794,12 +798,12 @@ RNFetchBlob.config({ ## Web API Polyfills -After `0.8.0` we've made some [Web API polyfills](https://github.com/wkh237/react-native-fetch-blob/wiki/Web-API-Polyfills-(experimental)) that makes some browser-based library available in RN. +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. - Blob - XMLHttpRequest (Use our implementation if you're going to use it with Blob) -Here's a [sample app](https://github.com/wkh237/rn-firebase-storage-upload-sample) that uses polyfills to upload files to FireBase. +Here's a [sample app](https://github.com/joltup/rn-firebase-storage-upload-sample) that uses polyfills to upload files to FireBase. ## Performance Tips @@ -830,16 +834,16 @@ If you're going to concatenate files, you don't have to read the data to JS cont * This library does not urlencode unicode characters in URL automatically, see [#146](https://github.com/wkh237/react-native-fetch-blob/issues/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](https://github.com/wkh237/react-native-fetch-blob/wiki/Fetch-API#fetchprogressconfig-eventlistenerpromisernfetchblobresponse) to limit its frequency. +* When file stream and upload/download progress event slow down your app, consider an upgrade to `0.9.6+`, use [additional arguments](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API#fetchprogressconfig-eventlistenerpromisernfetchblobresponse) 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](https://github.com/wkh237/react-native-fetch-blob/wiki/Trouble-Shooting) or [issues labeled Trouble Shooting](https://github.com/wkh237/react-native-fetch-blob/issues?utf8=✓&q=label:%22trouble%20shooting%22%20), there'd be some helpful information. +when you got a problem, have a look at [Trouble Shooting](https://github.com/joltup/rn-fetch-blob/wiki/Trouble-Shooting) or [issues labeled Trouble Shooting](https://github.com/joltup/rn-fetch-blob/issues?utf8=✓&q=label:%22trouble%20shooting%22%20), there'd be some helpful information. ## Changes -See [release notes](https://github.com/wkh237/react-native-fetch-blob/releases) +See [release notes](https://github.com/joltup/rn-fetch-blob/releases) ### Development -If you're interested in hacking this module, check our [development guide](https://github.com/wkh237/react-native-fetch-blob/wiki/Home), there might be some helpful information. -Please feel free to make a PR or file an issue. \ No newline at end of file +If you're interested in hacking this module, check our [development guide](https://github.com/joltup/rn-fetch-blob/wiki/Home), there might be some helpful information. +Please feel free to make a PR or file an issue. From 5983f0cd69cefe3ba327b52ae7b8c6d113cea77e Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 14:18:11 -0600 Subject: [PATCH 057/182] update repo name in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e083504f8..2b60c8651 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ } }, "repository": { - "url": "https://github.com/joltup/react-native-fetch-blob.git" + "url": "https://github.com/joltup/rn-fetch-blob.git" }, "author": "Joltup", "license": "MIT", From 5721cb7396368cbe4e1dabc2ab9a5d842535ba21 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 17:40:15 -0600 Subject: [PATCH 058/182] rename missed occurrences of react-native-fetch-blob --- CONTRIBUTING.md | 8 +------- android/src/main/res/values/strings.xml | 2 +- index.js | 2 +- ios/RNFetchBlob.xcodeproj/project.pbxproj | 4 ++-- package.json | 2 +- ...-native-fetch-blob.podspec => rn-fetch-blob.podspec | 7 +++---- scripts/prelink.js | 10 +++++----- 7 files changed, 14 insertions(+), 21 deletions(-) rename react-native-fetch-blob.podspec => rn-fetch-blob.podspec (58%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb71468eb..ad245bfce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1 @@ -For developers who interested in making contribution to this project, please see [https://github.com/wkh237/react-native-fetch-blob-dev](https://github.com/wkh237/react-native-fetch-blob-dev) for more information. - -Please read the following rules before opening a PR : - -1. If the PR is offering a feature please make the PR to our "Feature Branch" 0.11.0 -2. Bug fix request to "Bug Fix Branch" 0.10.6 -3. Correct README.md can directly to master +For developers who interested in making contribution to this project, please see [https://github.com/joltup/rn-fetch-blob-dev](https://github.com/joltup/rn-fetch-blob-dev) for more information. diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index dc2d93a52..de5cc9fd5 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - react-native-fetch-blob + rn-fetch-blob diff --git a/index.js b/index.js index 6d9ea348f..0135fd8f7 100644 --- a/index.js +++ b/index.js @@ -72,7 +72,7 @@ emitter.addListener("RNFetchBlobMessage", (e) => { // Show warning if native module not detected if(!RNFetchBlob || !RNFetchBlob.fetchBlobForm || !RNFetchBlob.fetchBlob) { console.warn( - 'react-native-fetch-blob could not find valid native module.', + 'rn-fetch-blob could not find valid native module.', 'please make sure you have linked native modules using `rnpm link`,', 'and restart RN packager or manually compile IOS/Android project.' ) diff --git a/ios/RNFetchBlob.xcodeproj/project.pbxproj b/ios/RNFetchBlob.xcodeproj/project.pbxproj index 070fcabb1..4fbdc00ea 100644 --- a/ios/RNFetchBlob.xcodeproj/project.pbxproj +++ b/ios/RNFetchBlob.xcodeproj/project.pbxproj @@ -261,7 +261,7 @@ "$(SRCROOT)/../../React/**", "$(SRCROOT)/../../react-native/React/**", "$(SRCROOT)/../../node_modules/react-native/React/**", - "$(SRCROOT)/../../node_modules/react-native-fetch-blob/ios/RNFetchBlob", + "$(SRCROOT)/../../node_modules/rn-fetch-blob/ios/RNFetchBlob", "$(SRCROOT)/../../RNFetchBlobTest/node_modules/react-native/**", ); OTHER_LDFLAGS = "-ObjC"; @@ -282,7 +282,7 @@ "$(SRCROOT)/../../React/**", "$(SRCROOT)/../../react-native/React/**", "$(SRCROOT)/../../node_modules/react-native/React/**", - "$(SRCROOT)/../../node_modules/react-native-fetch-blob/ios/RNFetchBlob", + "$(SRCROOT)/../../node_modules/rn-fetch-blob/ios/RNFetchBlob", "$(SRCROOT)/../../RNFetchBlobTest/node_modules/react-native/**", ); OTHER_LDFLAGS = "-ObjC"; diff --git a/package.json b/package.json index 2b60c8651..4e8c6aadd 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ ], "rnpm": { "commands": { - "prelink": "node ./node_modules/react-native-fetch-blob/scripts/prelink.js" + "prelink": "node ./node_modules/rn-fetch-blob/scripts/prelink.js" } }, "repository": { diff --git a/react-native-fetch-blob.podspec b/rn-fetch-blob.podspec similarity index 58% rename from react-native-fetch-blob.podspec rename to rn-fetch-blob.podspec index f702d287b..6b84ea6de 100644 --- a/react-native-fetch-blob.podspec +++ b/rn-fetch-blob.podspec @@ -1,13 +1,12 @@ Pod::Spec.new do |s| - s.name = "react-native-fetch-blob" + s.name = "rn-fetch-blob" s.version = "0.10.6" s.summary = "A project committed to make file acess and data transfer easier, effiecient for React Native developers." s.requires_arc = true s.license = 'MIT' s.homepage = 'n/a' - s.authors = { "wkh237" => "xeiyan@gmail.com" } - s.source = { :git => "https://github.com/wkh237/react-native-fetch-blob", :tag => 'v0.10.6'} + s.source = { :git => "https://github.com/joltup/rn-fetch-blob", :tag => 'v0.10.6'} s.source_files = 'ios/**/*.{h,m}' - s.platform = :ios, "7.0" + s.platform = :ios, "8.0" s.dependency 'React/Core' end diff --git a/scripts/prelink.js b/scripts/prelink.js index 435cbc54d..e2c3ac483 100644 --- a/scripts/prelink.js +++ b/scripts/prelink.js @@ -6,13 +6,13 @@ try { var PACKAGE_JSON = process.cwd() + '/package.json'; var package = JSON.parse(fs.readFileSync(PACKAGE_JSON)); var APP_NAME = package.name; - var PACKAGE_GRADLE = process.cwd() + '/node_modules/react-native-fetch-blob/android/build.gradle' + var PACKAGE_GRADLE = process.cwd() + '/node_modules/rn-fetch-blob/android/build.gradle' var VERSION = checkVersion(); console.log('RNFetchBlob detected app version => ' + VERSION); if(VERSION < 0.28) { - console.log('You project version is '+ VERSION + ' which may not compatible to react-native-fetch-blob 7.0+, please consider upgrade your application template to react-native 0.27+.') + console.log('You project version is '+ VERSION + ' which may not compatible to rn-fetch-blob 7.0+, please consider upgrade your application template to react-native 0.27+.') // add OkHttp3 dependency fo pre 0.28 project var main = fs.readFileSync(PACKAGE_GRADLE); console.log('adding OkHttp3 dependency to pre 0.28 project .. ') @@ -52,7 +52,7 @@ try { } else { console.log( - '\033[95mreact-native-fetch-blob \033[97mwill not automatically add Android permissions after \033[92m0.9.4 '+ + '\033[95mrn-fetch-blob \033[97mwill not automatically add Android permissions after \033[92m0.9.4 '+ '\033[97mplease run the following command if you want to add default permissions :\n\n' + '\033[96m\tRNFB_ANDROID_PERMISSIONS=true react-native link \n') } @@ -64,8 +64,8 @@ try { } catch(err) { console.log( - '\033[95mreact-native-fetch-blob\033[97m link \033[91mFAILED \033[97m\nCould not automatically link package :'+ + '\033[95mrn-fetch-blob\033[97m link \033[91mFAILED \033[97m\nCould not automatically link package :'+ err.stack + 'please follow the instructions to manually link the library : ' + - '\033[4mhttps://github.com/wkh237/react-native-fetch-blob/wiki/Manually-Link-Package\n') + '\033[4mhttps://github.com/joltup/rn-fetch-blob/wiki/Manually-Link-Package\n') } From 00144aa9fdfc76602fd861c4cb7b1a4d313e113c Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 23 Jun 2018 17:41:30 -0600 Subject: [PATCH 059/182] 0.10.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e8c6aadd..52929d2f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.9", + "version": "0.10.10", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 521e0c4ceee3fff990e072b56768730b8417b1ac Mon Sep 17 00:00:00 2001 From: Vikas Kapadiya Date: Tue, 26 Jun 2018 20:28:37 +0530 Subject: [PATCH 060/182] Fix notification value for android download Manager --- README.md | 2 +- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 35b798558..f2e4688ee 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ If you're going to access external storage (say, SD card storage) for `Android 5 + + - ++ ... ``` diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 4bdb3dff3..ace53a5a6 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -161,7 +161,11 @@ public void run() { if (options.addAndroidDownloads.getBoolean("useDownloadManager")) { Uri uri = Uri.parse(url); DownloadManager.Request req = new DownloadManager.Request(uri); - req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + if(options.addAndroidDownloads.getBoolean("notification")) { + req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + } else { + req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); + } if(options.addAndroidDownloads.hasKey("title")) { req.setTitle(options.addAndroidDownloads.getString("title")); } From a309cc533032e82caeb43d7c139e4a87d72e13c3 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Tue, 26 Jun 2018 09:24:12 -0600 Subject: [PATCH 061/182] Update rn-fetch-blob.podspec --- rn-fetch-blob.podspec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rn-fetch-blob.podspec b/rn-fetch-blob.podspec index 6b84ea6de..cc7ce719c 100644 --- a/rn-fetch-blob.podspec +++ b/rn-fetch-blob.podspec @@ -5,7 +5,8 @@ Pod::Spec.new do |s| s.requires_arc = true s.license = 'MIT' s.homepage = 'n/a' - s.source = { :git => "https://github.com/joltup/rn-fetch-blob", :tag => 'v0.10.6'} + s.source = { :git => "https://github.com/joltup/rn-fetch-blob", :tag => 'v0.10.10'} + s.author = 'Joltup' s.source_files = 'ios/**/*.{h,m}' s.platform = :ios, "8.0" s.dependency 'React/Core' From 2a81f32def50e7ddf98176f19d62285b77853b54 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Tue, 26 Jun 2018 16:39:17 -0600 Subject: [PATCH 062/182] 0.10.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 52929d2f1..423f3080c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.10", + "version": "0.10.11", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 6984edccf0d36e606ac7b6a8adef1949d99c0b5c Mon Sep 17 00:00:00 2001 From: turtlegood Date: Thu, 12 Jul 2018 08:06:42 +0800 Subject: [PATCH 063/182] update README.md to inform the handle of cookies --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2e4688ee..e683b1f44 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ To sum up: ### 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. +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. ```js From e253ad28e60bbddf272a1f2e2d20c4d49f656e3e Mon Sep 17 00:00:00 2001 From: Miles Matthias Date: Thu, 12 Jul 2018 17:08:06 -0600 Subject: [PATCH 064/182] Fix installation via github instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2e4688ee..0e6d9e308 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ After `0.10.3` you can install this package directly from Github ```sh # replace with any one of the branches -npm install --save github:joltup/rn-fetch-blob-package# +npm install --save github:joltup/rn-fetch-blob# ``` **Manually Link Native Modules** From 5837361a5dd0b5997380bf7a3240e13b567dee69 Mon Sep 17 00:00:00 2001 From: adamburnett Date: Thu, 12 Jul 2018 18:05:03 -0600 Subject: [PATCH 065/182] Fixed file moving --- .../java/com/RNFetchBlob/RNFetchBlobFS.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 5d4d8edcd..6eba4f15a 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -599,16 +599,36 @@ static void mv(String path, String dest, Callback callback) { callback.invoke("Source file at path `" + path + "` does not exist"); return; } + + //Check if the output file directory exists. + File dir = new File(dest); + if (!dir.exists()) + { + dir.mkdirs(); + } + try { - boolean result = src.renameTo(new File(dest)); - if (!result) { - callback.invoke("mv failed for unknown reasons"); - return; + InputStream in = new FileInputStream(path); + OutputStream out = new FileOutputStream(dest); + + //read source path to byte buffer. Write from input to output stream + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) { //read is successful + out.write(buffer, 0, read); } + in.close(); + out.flush(); + + src.delete(); //remove original file + } catch (FileNotFoundException exception) { + callback.invoke(exception.toString()); + return; } catch (Exception e) { - callback.invoke(e.getLocalizedMessage()); + callback.invoke(e.toString()); return; } + callback.invoke(); } From 480093530c79cbd1aa80b01385b539f4e9489728 Mon Sep 17 00:00:00 2001 From: adamburnett Date: Mon, 16 Jul 2018 10:23:15 -0600 Subject: [PATCH 066/182] Added check for failing to create the output directory --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 6eba4f15a..7b4dfdb72 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -604,7 +604,11 @@ static void mv(String path, String dest, Callback callback) { File dir = new File(dest); if (!dir.exists()) { - dir.mkdirs(); + if (!dir.mkdirs()) + { + callback.invoke("Output directory creation failed."); + return; + } } try { @@ -622,7 +626,7 @@ static void mv(String path, String dest, Callback callback) { src.delete(); //remove original file } catch (FileNotFoundException exception) { - callback.invoke(exception.toString()); + callback.invoke("Source file not found."); return; } catch (Exception e) { callback.invoke(e.toString()); From 5094579a440478ab04cacd5653a495965433d0f0 Mon Sep 17 00:00:00 2001 From: adamburnett Date: Mon, 16 Jul 2018 11:16:06 -0600 Subject: [PATCH 067/182] Fixed truncating of progress report values. --- android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java | 4 ++-- ios/RNFetchBlobRequest.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java index df4e9088e..3150eb2e8 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java @@ -281,7 +281,7 @@ private File createMultipartBodyCache() throws IOException { */ private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws IOException { byte[] chunk = new byte[10240]; - int totalWritten = 0; + long totalWritten = 0; int read; while((read = stream.read(chunk, 0, 10240)) > 0) { sink.write(chunk, 0, read); @@ -403,7 +403,7 @@ private class FormField { * Emit progress event * @param written Integer */ - private void emitUploadProgress(int written) { + private void emitUploadProgress(long written) { RNFetchBlobProgressConfig config = RNFetchBlobReq.getReportUploadProgress(mTaskId); if(config != null && contentLength != 0 && config.shouldReport((float)written/contentLength)) { WritableMap args = Arguments.createMap(); diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index c77668ce8..a56cc92d0 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -345,8 +345,8 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat sendDeviceEventWithName:EVENT_PROGRESS body:@{ @"taskId": taskId, - @"written": [NSString stringWithFormat:@"%ld", (long) receivedBytes], - @"total": [NSString stringWithFormat:@"%ld", (long) expectedBytes], + @"written": [NSString stringWithFormat:@"%lld", (long long) receivedBytes], + @"total": [NSString stringWithFormat:@"%lld", (long long) expectedBytes], @"chunk": chunkString } ]; From 4f66c84d852d36e8af6d176076b15679d60ced0a Mon Sep 17 00:00:00 2001 From: adamburnett Date: Tue, 17 Jul 2018 09:53:37 -0600 Subject: [PATCH 068/182] Added null and path key check on addCompleteDownload method --- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index b6cf7013e..ac9ce5669 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -372,6 +372,11 @@ public void getContentIntent(String mime, Promise promise) { @ReactMethod public void addCompleteDownload (ReadableMap config, Promise promise) { DownloadManager dm = (DownloadManager) RCTContext.getSystemService(RCTContext.DOWNLOAD_SERVICE); + if (config == null || !config.hasKey("path")) + { + promise.reject("EINVAL", "RNFetchblob.addCompleteDownload config or path missing."); + return; + } String path = RNFetchBlobFS.normalizePath(config.getString("path")); if(path == null) { promise.reject("EINVAL", "RNFetchblob.addCompleteDownload can not resolve URI:" + config.getString("path")); From 1ebb03b831a1fd368509ede5553aaadbd6ea710b Mon Sep 17 00:00:00 2001 From: adamburnett Date: Tue, 17 Jul 2018 17:55:47 -0600 Subject: [PATCH 069/182] Removed output directory check / create. Fixes file moving. --- .../src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 7b4dfdb72..76eb4abe1 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -600,17 +600,6 @@ static void mv(String path, String dest, Callback callback) { return; } - //Check if the output file directory exists. - File dir = new File(dest); - if (!dir.exists()) - { - if (!dir.mkdirs()) - { - callback.invoke("Output directory creation failed."); - return; - } - } - try { InputStream in = new FileInputStream(path); OutputStream out = new FileOutputStream(dest); From 073cc3cfe4a5a6d26bdf3a45512b6d7f6c8131f5 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Tue, 17 Jul 2018 18:18:03 -0600 Subject: [PATCH 070/182] 0.10.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 423f3080c..de9f32762 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.11", + "version": "0.10.12", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From c31cb90f3d26fd1a35cd04d33b1c13a3c8825703 Mon Sep 17 00:00:00 2001 From: Lorien Date: Fri, 20 Jul 2018 11:59:38 -0700 Subject: [PATCH 071/182] change android request builder so it wont set Content-Type header to application/octet-stream if it was explicitly set to the empty string. This fixes amazon s3 uploads with a presigned url --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index ace53a5a6..369b9baaf 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -266,7 +266,9 @@ else if (value.equalsIgnoreCase("utf8")) requestType = RequestType.Form; } else if(cType.isEmpty()) { - builder.header("Content-Type", "application/octet-stream"); + if(!cType.equalsIgnoreCase("")) { + builder.header("Content-Type", "application/octet-stream"); + } requestType = RequestType.SingleFile; } if(rawRequestBody != null) { From 1a315a302ea4546887c49f3e88f94e0e0f840b20 Mon Sep 17 00:00:00 2001 From: Tales Lelo da Aparecida Date: Mon, 23 Jul 2018 19:30:23 -0300 Subject: [PATCH 072/182] Fixed trusty example calling `then` instead of `fetch` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad2fb0ce4..c719cfc81 100644 --- a/README.md +++ b/README.md @@ -790,7 +790,7 @@ By default, rn-fetch-blob does NOT allow connection to unknown certification pro RNFetchBlob.config({ trusty : true }) -.then('GET', 'https://mysite.com') +.fetch('GET', 'https://mysite.com') .then((resp) => { // ... }) From a4abef9c36ded6370324188cd10035b654b6db52 Mon Sep 17 00:00:00 2001 From: Danish Date: Tue, 24 Jul 2018 17:31:42 +0300 Subject: [PATCH 073/182] improvement way to get root SDK versions just added a function which acts like a ternary with fallback option. Hence, less cluttered "def" variables additionally, changed the SDK values from 23 to 26 as per new changes from react-native and Android Android Target API Level 26 will be required in August 2018. https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html And the React Native team is already working on this: facebook/react-native#18095 facebook/react-native#17741 PS: I am aware of this PR https://github.com/joltup/rn-fetch-blob/pull/128 but first its still targeting old SDK values i.e 23 as fallback and secondly I am not sure of the use of `project` to get the value instead of proper way i.e `rootProject.ext` to get the property value. --- android/build.gradle | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index d68693bf1..4664c1555 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,9 @@ apply plugin: 'com.android.library' +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + repositories { mavenCentral() } @@ -14,11 +18,11 @@ buildscript { } android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" + compileSdkVersion safeExtGet('compileSdkVersion', 26) + buildToolsVersion safeExtGet('buildToolsVersion', '26.0.3') defaultConfig { - minSdkVersion 16 - targetSdkVersion 23 + minSdkVersion safeExtGet('minSdkVersion', 16) + targetSdkVersion safeExtGet('targetSdkVersion', 26) versionCode 1 versionName "1.0" } @@ -33,7 +37,7 @@ android { } dependencies { - compile 'com.facebook.react:react-native:+' + compile 'com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}' //compile 'com.squareup.okhttp3:okhttp:+' //{RNFetchBlob_PRE_0.28_DEPDENDENCY} } From 27dc24314670631e326c3265350587267c316501 Mon Sep 17 00:00:00 2001 From: Aziz Khambati Date: Fri, 27 Jul 2018 22:28:03 +0530 Subject: [PATCH 074/182] (small fix) Fix link to issue which was giving 404 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c719cfc81..2a58062ed 100644 --- a/README.md +++ b/README.md @@ -528,7 +528,7 @@ RNFetchBlob }) ``` -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](https://github.com/joltup/rn-fetch-blob/issues/236). +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](https://github.com/wkh237/react-native-fetch-blob/issues/236). **Download Notification and Visibility in Download App (Android Only)** From d09c5d8095f4ff29194864eaa0623f66c79ffae5 Mon Sep 17 00:00:00 2001 From: Jeff Schoolcraft Date: Fri, 27 Jul 2018 15:01:25 -0400 Subject: [PATCH 075/182] Update README.md with tip on project references Wanted to include a note for folks upgrading from the old branch to the new branch about renaming all product references as this was a problem I came across in #122 (https://github.com/joltup/rn-fetch-blob/issues/122) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c719cfc81..4c90fa9a1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ In order to publish new releases from this fork, we have renamed this project to `rn-fetch-blob` and published to `https://www.npmjs.com/package/rn-fetch-blob`. +**Note**: If upgrading from the original fork change all references in your project from `react-native-fetch-blob` to `rn-fetch-blob`. This includes `*.xcodeproj/project.pbxproj` and `android/**/*.gradle` depending on the platform used, failing to do so may cause build errors. + # rn-fetch-blob [![release](https://img.shields.io/github/release/joltup/rn-fetch-blob.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/rn-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/rn-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/rn-fetch-blob.svg?maxAge=2592000&style=flat-square)]() From 840ddcefe7eddeadc9a1894181c17fc7aa354ea6 Mon Sep 17 00:00:00 2001 From: Danish Date: Sat, 4 Aug 2018 12:43:28 +0300 Subject: [PATCH 076/182] fix double quotes --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 4664c1555..184835289 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,7 +37,7 @@ android { } dependencies { - compile 'com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}' + compile "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" //compile 'com.squareup.okhttp3:okhttp:+' //{RNFetchBlob_PRE_0.28_DEPDENDENCY} } From e6e27ac0b9af015ebc67b9dc5605fc7bebe70942 Mon Sep 17 00:00:00 2001 From: Tom Spencer Date: Wed, 15 Aug 2018 20:59:03 +0100 Subject: [PATCH 077/182] Fix RuntimeException Fixes a case where `callback` was called twice when something went wrong in the `cp` operation, leading to a `java.lang.RuntimeException: Illegal callback invocation from native module. This callback type only permits a single invocation from native code.` This is the same fix [as seen in the original repo](https://github.com/wkh237/react-native-fetch-blob/pull/408). --- .../main/java/com/RNFetchBlob/RNFetchBlobFS.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 76eb4abe1..5574609db 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -548,6 +548,7 @@ static void cp(String path, String dest, Callback callback) { path = normalizePath(path); InputStream in = null; OutputStream out = null; + String message = ""; try { if(!isPathExists(path)) { @@ -571,7 +572,7 @@ static void cp(String path, String dest, Callback callback) { out.write(buf, 0, len); } } catch (Exception err) { - callback.invoke(err.getLocalizedMessage()); + message += err.getLocalizedMessage(); } finally { try { if (in != null) { @@ -580,11 +581,17 @@ static void cp(String path, String dest, Callback callback) { if (out != null) { out.close(); } - callback.invoke(); } catch (Exception e) { - callback.invoke(e.getLocalizedMessage()); + message += e.getLocalizedMessage(); } } + // Only call the callback once to prevent the app from crashing + // with an 'Illegal callback invocation from native module' exception. + if (message != "") { + callback.invoke(message); + } else { + callback.invoke(); + } } /** From 5551d01bf85e01a9422c92801c3b11ffc496cbe6 Mon Sep 17 00:00:00 2001 From: wenshe Date: Mon, 20 Aug 2018 18:16:34 +0800 Subject: [PATCH 078/182] fix progress and uploadprogress not callback in iOS --- ios/RNFetchBlobNetwork.h | 2 ++ ios/RNFetchBlobNetwork.m | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/ios/RNFetchBlobNetwork.h b/ios/RNFetchBlobNetwork.h index 1512712af..ff4cd9c6c 100644 --- a/ios/RNFetchBlobNetwork.h +++ b/ios/RNFetchBlobNetwork.h @@ -25,6 +25,8 @@ @property(nonnull, nonatomic) NSOperationQueue *taskQueue; @property(nonnull, nonatomic) NSMapTable * requestsTable; +@property(nonnull, nonatomic) NSMutableDictionary *rebindProgressDict; +@property(nonnull, nonatomic) NSMutableDictionary *rebindUploadProgressDict; + (RNFetchBlobNetwork* _Nullable)sharedInstance; + (NSMutableDictionary * _Nullable ) normalizeHeaders:(NSDictionary * _Nullable)headers; diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index 4531bf35e..f2e40b6b4 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -53,6 +53,8 @@ - (id)init { self.taskQueue = [[NSOperationQueue alloc] init]; self.taskQueue.qualityOfService = NSQualityOfServiceUtility; self.taskQueue.maxConcurrentOperationCount = 10; + self.rebindProgressDict = [NSMutableDictionary dictionary]; + self.rebindUploadProgressDict = [NSMutableDictionary dictionary]; } return self; @@ -87,14 +89,33 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options @synchronized([RNFetchBlobNetwork class]) { [self.requestsTable setObject:request forKey:taskId]; + [self checkProgressConfig]; } } +- (void) checkProgressConfig { + //reconfig progress + [self.rebindProgressDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, RNFetchBlobProgress * _Nonnull config, BOOL * _Nonnull stop) { + [self enableProgressReport:key config:config]; + }]; + [self.rebindProgressDict removeAllObjects]; + + //reconfig uploadProgress + [self.rebindUploadProgressDict enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, RNFetchBlobProgress * _Nonnull config, BOOL * _Nonnull stop) { + [self enableUploadProgress:key config:config]; + }]; + [self.rebindUploadProgressDict removeAllObjects]; +} + - (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config { if (config) { @synchronized ([RNFetchBlobNetwork class]) { - [self.requestsTable objectForKey:taskId].progressConfig = config; + if (![self.requestsTable objectForKey:taskId]) { + [self.rebindProgressDict setValue:config forKey:taskId]; + } else { + [self.requestsTable objectForKey:taskId].progressConfig = config; + } } } } @@ -103,7 +124,11 @@ - (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *) { if (config) { @synchronized ([RNFetchBlobNetwork class]) { - [self.requestsTable objectForKey:taskId].uploadProgressConfig = config; + if (![self.requestsTable objectForKey:taskId]) { + [self.rebindUploadProgressDict setValue:config forKey:taskId]; + } else { + [self.requestsTable objectForKey:taskId].uploadProgressConfig = config; + } } } } From 61a343e1f243cce35385e361a25e66558855411b Mon Sep 17 00:00:00 2001 From: adamburnett Date: Tue, 21 Aug 2018 10:31:17 -0600 Subject: [PATCH 079/182] path sent to unlink is now checked for file prefix. --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 5d4d8edcd..0e996c6cb 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -490,7 +490,8 @@ static void closeStream(String streamId, Callback callback) { */ static void unlink(String path, Callback callback) { try { - RNFetchBlobFS.deleteRecursive(new File(path)); + String normalizedPath = normalizePath(path); + RNFetchBlobFS.deleteRecursive(new File(normalizedPath)); callback.invoke(null, true); } catch(Exception err) { callback.invoke(err.getLocalizedMessage(), false); From fd81e468b1a9e5caffde44d807deec3c07130a69 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Fri, 24 Aug 2018 09:27:06 -0700 Subject: [PATCH 080/182] 0.10.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index de9f32762..66b0a5d28 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.12", + "version": "0.10.13", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From b4e15f3ab1ba9a068d4d43c7865894763166e3a5 Mon Sep 17 00:00:00 2001 From: reilem Date: Fri, 14 Sep 2018 12:25:46 +0200 Subject: [PATCH 081/182] Create index.d.ts --- index.d.ts | 621 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 621 insertions(+) create mode 100644 index.d.ts diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 000000000..910fa4dba --- /dev/null +++ b/index.d.ts @@ -0,0 +1,621 @@ +// Type definitions for react-native-fetch-blob 0.10 +// Project: https://github.com/wkh237/react-native-fetch-blob#readme +// Definitions by: MNB +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +export const RNFetchBlob: RNFetchBlobStatic; +export type RNFetchBlob = RNFetchBlobStatic; +export default RNFetchBlob; + +interface RNFetchBlobStatic { + fetch(method: Methods, url: string, headers?: { [key: string]: string }, body?: any + | null): StatefulPromise; + base64: { encode(input: string): string; decode(input: string): string }; + android: AndroidApi; + ios: IOSApi; + config(options: RNFetchBlobConfig): RNFetchBlobStatic; + session(name: string): RNFetchBlobSession; + fs: FS; + wrap(path: string): string; + net: Net; + polyfill: Polyfill; + // this require external module https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/oboe + JSONStream: any; +} + +export interface Polyfill { + Blob: PolyfillBlob; + File: PolyfillFile; + XMLHttpRequest: PolyfillXMLHttpRequest; + ProgressEvent: PolyfillProgressEvent; + Event: PolyfillEvent; + FileReader: PolyfillFileReader; + Fetch: PolyfillFetch; +} + +export declare class PolyfillFetch extends RNFetchBlobFetchPolyfill { + constructor(config: RNFetchBlobConfig); +} + +export declare class RNFetchBlobFetchPolyfill { + constructor(config: RNFetchBlobConfig); + + build(): (url: string, options: RNFetchBlobConfig) => StatefulPromise; +} + +export interface RNFetchBlobFetchRepsonse { + arrayBuffer(): Promise; + blob(): Promise; + json(): Promise; + rawResp(): Promise; + text(): Promise; + bodyUsed: boolean; + headers: any; + ok: boolean; + resp: FetchBlobResponse; + rnfbResp: FetchBlobResponse; + rnfbRespInfo: RNFetchBlobResponseInfo; + status: number; + type: string; +} + +/** + * RNFetchBlob response object class. + */ +export interface FetchBlobResponse { + taskId: string; + /** + * get path of response temp file + * @return File path of temp file. + */ + path(): string; + type: "base64" | "path" | "utf8"; + data: any; + /** + * Convert result to javascript RNFetchBlob object. + * @return Return a promise resolves Blob object. + */ + blob(contentType: string, sliceSize: number): Promise; + /** + * Convert result to text. + * @return Decoded base64 string. + */ + text(): string | Promise; + /** + * Convert result to JSON object. + * @return Parsed javascript object. + */ + json(): any; + /** + * Return BASE64 string directly. + * @return BASE64 string of response body. + */ + base64(): any; + /** + * Remove cahced file + */ + flush(): void; + respInfo: RNFetchBlobResponseInfo; + session(name: string): RNFetchBlobSession | null; + /** + * Read file content with given encoding, if the response does not contains + * a file path, show warning message + * @param encode Encode type, should be one of `base64`, `ascrii`, `utf8`. + */ + readFile(encode: Encoding): Promise | null; + /** + * Start read stream from cached file + * @param encode Encode type, should be one of `base64`, `ascrii`, `utf8`. + */ + readStream(encode: Encoding): RNFetchBlobStream | null; +} + +export interface PolyfillFileReader extends EventTarget { + isRNFBPolyFill: boolean; + onloadstart(e: Event): void; + onprogress(e: Event): void; + onload(e: Event): void; + onabort(e: Event): void; + onerror(e: Event): void; + onloadend(e: Event): void; + + abort(): void; + readAsArrayBuffer(b: PolyfillBlob): void; + readAsBinaryString(b: PolyfillBlob): void; + readAsText(b: PolyfillBlob, label?: string): void; + readAsDataURL(b: PolyfillBlob): void; + + readyState: number; + result: number; +} + +export declare namespace PolyfillFileReader { + const EMPTY: number; + const LOADING: number; + const DONE: number; +} + +export declare class PolyfillEvent { +} + +export interface PolyfillProgressEvent extends EventTarget { + lengthComputable: boolean; + loaded: number; + total: number; +} + +export declare class PolyfillBlob extends EventTarget { + /** + * RNFetchBlob Blob polyfill, create a Blob directly from file path, BASE64 + * encoded data, and string. The conversion is done implicitly according to + * given `mime`. However, the blob creation is asynchronously, to register + * event `onCreated` is need to ensure the Blob is creadted. + * + * @param data Content of Blob object + * @param cType Content type settings of Blob object, `text/plain` by default + * @param defer When this argument set to `true`, blob constructor will not invoke blob created event automatically. + */ + constructor(data: any, cType: any, defer: boolean); + + /** + * Since Blob content will asynchronously write to a file during creation, + * use this method to register an event handler for Blob initialized event. + * @param fn An event handler invoked when Blob created + * @return The Blob object instance itself + */ + onCreated(fn: () => void): PolyfillBlob; + + markAsDerived(): void; + + /** + * Get file reference of the Blob object. + * @return Blob file reference which can be consumed by RNFetchBlob fs + */ + getRNFetchBlobRef(): string; + + /** + * Create a Blob object which is sliced from current object + * @param start Start byte number + * @param end End byte number + * @param contentType Optional, content type of new Blob object + */ + slice(start?: number, end?: number, contentType?: string): PolyfillBlob; + + /** + * Read data of the Blob object, this is not standard method. + * @param encoding Read data with encoding + */ + readBlob(encoding: string): Promise; + + /** + * Release the resource of the Blob object. + * @nonstandard + */ + close(): Promise; +} + +export declare namespace PolyfillBlob { + function clearCache(): void; + + function build(data: any, cType: any): Promise; + + function setLog(level: number): void; +} + +export declare class PolyfillFile extends PolyfillBlob { +} + +export interface PolyfillXMLHttpRequest extends PolyfillXMLHttpRequestEventTarget { + upload: PolyfillXMLHttpRequestEventTarget; + readonly UNSENT: number; + readonly OPENED: number; + readonly HEADERS_RECEIVED: number; + readonly LOADING: number; + readonly DONE: number; + + /** + * XMLHttpRequest.open, always async, user and password not supported. When + * this method invoked, headers should becomes empty again. + * @param method Request method + * @param url Request URL + * @param async Always async + * @param user NOT SUPPORTED + * @param password NOT SUPPORTED + */ + open(method: string, url: string, async: true, user: any, password: any): void; + + /** + * Invoke this function to send HTTP request, and set body. + * @param body Body in RNfetchblob flavor + */ + send(body: any): void; + + overrideMimeType(mime: string): void; + + setRequestHeader(name: string, value: string): void; + + abort(): void; + + getResponseHeader(field: string): string | null; + + getAllResponseHeaders(): string | null; + + onreadystatechange(e: Event): void; + readyState: number; + status: number; + statusText: string; + response: any; + responseText: any; + responseURL: string; + responseHeaders: any; + timeout: number; + responseType: string; +} + +export declare namespace PolyfillXMLHttpRequest { + const binaryContentTypes: string[]; + const UNSENT: number; + const OPENED: number; + const HEADERS_RECEIVED: number; + const LOADING: number; + const DONE: number; + + function setLog(level: number): void; + + function addBinaryContentType(substr: string): void; + + function removeBinaryContentType(): void; +} + +export interface PolyfillXMLHttpRequestEventTarget extends EventTarget { + onabort(e: Event): void; + onerror(e: Event): void; + onload(e: Event): void; + onloadstart(e: Event): void; + onprogress(e: Event): void; + ontimeout(e: Event): void; + onloadend(e: Event): void; +} + +export interface Net { + /** + * Get cookie according to the given url. + * @param domain Domain of the cookies to be removed, remove all + * @return Cookies of a specific domain. + */ + getCookies(domain: string): Promise; + + /** + * Remove cookies for a specific domain + * @param domain Domain of the cookies to be removed, remove all + * cookies when this is null. + */ + removeCookies(domain?: string): Promise; +} + +export interface FS { + RNFetchBlobSession: RNFetchBlobSession; + + /** + * Remove file at path. + * @param path:string Path of target file. + */ + unlink(path: string): Promise; + + /** + * Create a directory. + * @param path Path of directory to be created + */ + mkdir(path: string): Promise; + + /** + * Get a file cache session + * @param name Stream ID + */ + session(name: string): RNFetchBlobSession; + + ls(path: string): Promise; + + /** + * Create file stream from file at `path`. + * @param path The file path. + * @param encoding Data encoding, should be one of `base64`, `utf8`, `ascii` + * @param bufferSize Size of stream buffer. + * @return RNFetchBlobStream stream instance. + */ + readStream(path: string, encoding: Encoding, bufferSize?: number, tick?: number): Promise; + + mv(path: string, dest: string): Promise; + + cp(path: string, dest: string): Promise; + + /** + * Create write stream to a file. + * @param path Target path of file stream. + * @param encoding Encoding of input data. + * @param append A flag represent if data append to existing ones. + * @return A promise resolves a `WriteStream` object. + */ + writeStream(path: string, encoding: Encoding, append?: boolean): Promise; + + /** + * Write data to file. + * @param path Path of the file. + * @param data Data to write to the file. + * @param encoding Encoding of data (Optional). + */ + writeFile(path: string, data: string | number[], encoding?: Encoding): Promise; + + appendFile(path: string, data: string | number[], encoding?: Encoding): Promise; + + /** + * Wrapper method of readStream. + * @param path Path of the file. + * @param encoding Encoding of read stream. + */ + readFile(path: string, encoding: Encoding, bufferSize?: number): Promise; + /** + * Check if file exists and if it is a folder. + * @param path Path to check + */ + exists(path: string): Promise; + + createFile(path: string, data: string, encoding: Encoding): Promise; + + isDir(path: string): Promise; + + /** + * Show statistic data of a path. + * @param path Target path + */ + stat(path: string): Promise; + + lstat(path: string): Promise; + + /** + * Android only method, request media scanner to scan the file. + * @param pairs Array contains Key value pairs with key `path` and `mime`. + */ + scanFile(pairs: Array<{ [key: string]: string }>): Promise; + + dirs: Dirs; + + slice(src: string, dest: string, start: number, end: number): Promise; + asset(path: string): string; + df(): Promise<{ free: number, total: number }>; +} + +export interface Dirs { + DocumentDir: string; + CacheDir: string; + PictureDir: string; + MusicDir: string; + MovieDir: string; + DownloadDir: string; + DCIMDir: string; + SDCardDir: string; + MainBundleDir: string; +} + +export interface RNFetchBlobWriteStream { + id: string; + encoding: string; + append: boolean; + + write(data: string): Promise; + close(): void; +} + +export interface RNFetchBlobReadStream { + path: string; + encoding: Encoding; + bufferSize?: number; + closed: boolean; + tick: number; + + open(): void; + + onData(fn: (chunk: string | number[]) => void): void; + + onError(fn: (err: any) => void): void; + + onEnd(fn: () => void): void; +} + +type Encoding = "utf8" | "ascii" | "base64"; + +/* tslint:disable-next-line interface-name*/ +export interface IOSApi { + /** + * Open a file in {@link https://developer.apple.com/reference/uikit/uidocumentinteractioncontroller UIDocumentInteractionController}, + * this is the default document viewer of iOS, supports several kinds of files. On Android, there's an similar method {@link android.actionViewIntent}. + * @param path This is a required field, the path to the document. The path should NOT contains any scheme prefix. + */ + previewDocument(path: string): void; + + /** + * Show options menu for interact with the file. + * @param path This is a required field, the path to the document. The path should NOT contains any scheme prefix. + */ + openDocument(path: string): void; +} + +export interface AndroidApi { + /** + * When sending an ACTION_VIEW intent with given file path and MIME type, system will try to open an + * App to handle the file. For example, open Gallery app to view an image, or install APK. + * @param path Path of the file to be opened. + * @param mime Basically system will open an app according to this MIME type. + */ + actionViewIntent(path: string, mime: string): Promise; +} + +type Methods = "POST" | "GET" | "DELETE" | "PUT" | "post" | "get" | "delete" | "put"; + +/** + * A declare class inherits Promise, it has extra method like progress, uploadProgress, + * and cancel which can help managing an asynchronous task's state. + */ +export interface StatefulPromise extends Promise { + /** + * Cancel the request when invoke this method. + */ + cancel(cb?: (reason: any) => void): StatefulPromise; + + /** + * Add an event listener which triggers when data receiving from server. + */ + progress(callback: (received: number, total: number) => void): StatefulPromise; + + /** + * Add an event listener with custom configuration + */ + progress(config: { count?: number, interval?: number }, callback: (received: number, total: number) => void): StatefulPromise; + + /** + * Add an event listener with custom configuration. + */ + uploadProgress(callback: (sent: number, total: number) => void): StatefulPromise; + + /** + * Add an event listener with custom configuration + */ + uploadProgress(config: { count?: number, interval?: number }, callback: (sent: number, total: number) => void): StatefulPromise; + + /** + * An IOS only API, when IOS app turns into background network tasks will be terminated after ~180 seconds, + * in order to handle these expired tasks, you can register an event handler, which will be called after the + * app become active. + */ + expire(callback: () => void): StatefulPromise; +} + +export declare class RNFetchBlobSession { + constructor(name: string, list: string[]); + + add(path: string): RNFetchBlobSession; + + remove(path: string): RNFetchBlobSession; + + dispose(): Promise; + + list(): string[]; + + name: string; + + static getSession(name: string): any; + + static setSession(name: string): void; + + static removeSession(name: string): void; +} + +/** + * A set of configurations that will be injected into a fetch method, with the following properties. + */ +export interface RNFetchBlobConfig { + /** + * When this property is true, the downloaded data will overwrite the existing file. (true by default) + */ + overwrite?: boolean; + + /** + * Set timeout of the request (in milliseconds). + */ + timeout?: number; + + /** + * Set this property to true to display a network indicator on status bar, this feature is only supported on IOS. + */ + indicator?: boolean; + + /** + * Set this property to true will allow the request create connection with server have self-signed SSL + * certification. This is not recommended to use in production. + */ + trusty?: 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}. + */ + fileCache?: boolean; + + /** + * Set this property to change temp file extension that created by fetch response data. + */ + appendExt?: string; + + /** + * When this property has value, fetch API will try to store response data in the path ignoring fileCache and + * appendExt property. + */ + path?: string; + + session?: string; + + addAndroidDownloads?: AddAndroidDownloads; + + /** + * Fix IOS request timeout issue #368 by change default request setting to defaultSessionConfiguration, and make backgroundSessionConfigurationWithIdentifier optional + */ + IOSBackgroundTask?: boolean; +} + +export interface AddAndroidDownloads { + /** + * download file using Android download manager or not. + */ + useDownloadManager?: boolean; + /** + * title of the file + */ + title?: string; + /** + * File description of the file. + */ + description?: string; + /** + * The destination which the file will be downloaded, it SHOULD be a location on external storage (DCIMDir). + */ + path?: string; + /** + * MIME type of the file. By default is text/plain + */ + mime?: string; + /** + * A boolean value, see Officail Document + * (https://developer.android.com/reference/android/app/DownloadManager.html#addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean)) + */ + mediaScannable?: boolean; + /** + * A boolean value decide whether show a notification when download complete. + */ + notification?: boolean; +} + +export interface RNFetchBlobResponseInfo { + taskId: string; + state: number; + headers: any; + status: number; + respType: "text" | "blob" | "" | "json"; + rnfbEncode: "path" | "base64" | "ascii" | "utf8"; +} + +export interface RNFetchBlobStream { + onData(): void; + onError(): void; + onEnd(): void; +} + +export declare class RNFetchBlobFile { +} + +export declare class RNFetchBlobStat { + lastModified: string; + size: string; + type: "directory" | "file"; + path: string; + filename: string; +} From 3aec4191f9661b78f5baf85da3f99ca1bd467a10 Mon Sep 17 00:00:00 2001 From: Guy Blank Date: Thu, 20 Sep 2018 09:27:38 +0300 Subject: [PATCH 082/182] support upload task + recieve finish event from background --- ios/RNFetchBlobNetwork.m | 10 +--- ios/RNFetchBlobRequest.h | 5 +- ios/RNFetchBlobRequest.m | 118 ++++++++++++++++++++++----------------- 3 files changed, 74 insertions(+), 59 deletions(-) diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index f2e40b6b4..fbb421f38 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -63,7 +63,7 @@ - (id)init { + (RNFetchBlobNetwork* _Nullable)sharedInstance { static id _sharedInstance = nil; static dispatch_once_t onceToken; - + dispatch_once(&onceToken, ^{ _sharedInstance = [[self alloc] init]; }); @@ -135,14 +135,8 @@ - (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *) - (void) cancelRequest:(NSString *)taskId { - NSURLSessionDataTask * task; - @synchronized ([RNFetchBlobNetwork class]) { - task = [self.requestsTable objectForKey:taskId].task; - } - - if (task && task.state == NSURLSessionTaskStateRunning) { - [task cancel]; + [[self.requestsTable objectForKey:taskId] cancelRequest:taskId]; } } diff --git a/ios/RNFetchBlobRequest.h b/ios/RNFetchBlobRequest.h index b550ac22e..7e5776ed3 100644 --- a/ios/RNFetchBlobRequest.h +++ b/ios/RNFetchBlobRequest.h @@ -32,7 +32,8 @@ @property (nullable, nonatomic) NSError * error; @property (nullable, nonatomic) RNFetchBlobProgress *progressConfig; @property (nullable, nonatomic) RNFetchBlobProgress *uploadProgressConfig; -@property (nullable, nonatomic, weak) NSURLSessionDataTask *task; +//@property (nullable, nonatomic, weak) NSURLSessionDataTask *task; +@property (nonatomic, strong) __block NSURLSession * session; - (void) sendRequest:(NSDictionary * _Nullable )options contentLength:(long)contentLength @@ -42,6 +43,8 @@ taskOperationQueue:(NSOperationQueue * _Nonnull)operationQueue callback:(_Nullable RCTResponseSenderBlock) callback; +- (void) cancelRequest:(NSString *)taskId; + @end #endif /* RNFetchBlobRequest_h */ diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index a56cc92d0..47c378570 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -11,10 +11,24 @@ #import "RNFetchBlobFS.h" #import "RNFetchBlobConst.h" #import "RNFetchBlobReqBuilder.h" +#if __has_include() +#import +#else +#import "RCTLog.h" +#endif #import "IOS7Polyfill.h" #import +NSMapTable * taskTable; + +__attribute__((constructor)) +static void initialize_tables() { + if(taskTable == nil) + { + taskTable = [[NSMapTable alloc] init]; + } +} typedef NS_ENUM(NSUInteger, ResponseFormat) { UTF8, @@ -36,6 +50,7 @@ @interface RNFetchBlobRequest () ResponseFormat responseFormat; BOOL followRedirect; BOOL backgroundTask; + BOOL uploadTask; } @end @@ -82,6 +97,10 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options self.options = options; backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue]; + uploadTask = [options valueForKey:@"IOSUploadTask"] == nil ? NO : [[options valueForKey:@"IOSUploadTask"] boolValue]; + + NSString * filepath = [options valueForKey:@"uploadFilePath"]; + // when followRedirect not set in options, defaults to TRUE followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue]; isIncrement = [[options valueForKey:@"increment"] boolValue]; @@ -104,7 +123,6 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options NSString * path = [self.options valueForKey:CONFIG_FILE_PATH]; NSString * key = [self.options valueForKey:CONFIG_KEY]; - NSURLSession * session; bodyLength = contentLength; @@ -117,6 +135,7 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId]; } + // request timeout, -1 if not set in options float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue]; @@ -125,7 +144,7 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options } defaultConfigObject.HTTPMaximumConnectionsPerHost = 10; - session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; + _session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; if (path || [self.options valueForKey:CONFIG_USE_TEMP]) { respFile = YES; @@ -157,8 +176,19 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options respFile = NO; } - self.task = [session dataTaskWithRequest:req]; - [self.task resume]; + __block NSURLSessionTask * task; + + if(uploadTask) + { + task = [_session uploadTaskWithRequest:req fromFile:[NSURL URLWithString:filepath]]; + } + else + { + task = [_session dataTaskWithRequest:req]; + } + + [taskTable setObject:task forKey:taskId]; + [task resume]; // network status indicator if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) { @@ -182,6 +212,7 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options // set expected content length on response received - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { + NSLog(@"sess didReceiveResponse"); expectedBytes = [response expectedContentLength]; NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; @@ -207,7 +238,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat partBuffer = [[NSMutableData alloc] init]; completionHandler(NSURLSessionResponseAllow); - + return; } else { self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; @@ -269,42 +300,6 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat NSLog(@"oops"); } - if (respFile) - { - @try{ - NSFileManager * fm = [NSFileManager defaultManager]; - NSString * folder = [destPath stringByDeletingLastPathComponent]; - - if (![fm fileExistsAtPath:folder]) { - [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil]; - } - - // if not set overwrite in options, defaults to TRUE - BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue]; - BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"]; - - appendToExistingFile = !overwrite; - - // For solving #141 append response data if the file already exists - // base on PR#139 @kejinliang - if (appendToExistingFile) { - destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""]; - } - - if (![fm fileExistsAtPath:destPath]) { - [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil]; - } - - writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile]; - [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; - [writeStream open]; - } - @catch(NSException * ex) - { - NSLog(@"write file error"); - } - } - completionHandler(NSURLSessionResponseAllow); } @@ -328,11 +323,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } - if (respFile) { - [writeStream write:[data bytes] maxLength:[data length]]; - } else { - [respData appendData:data]; - } + [respData appendData:data]; if (expectedBytes == 0) { return; @@ -353,8 +344,16 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } } +- (void) cancelRequest:(NSString *)taskId +{ + NSURLSessionDataTask * task = [taskTable objectForKey:taskId]; + if(task != nil && task.state == NSURLSessionTaskStateRunning) + [task cancel]; +} + - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error { + RCTLog(@"[RNFetchBlobRequest] session didBecomeInvalidWithError %@", [error description]); if ([session isEqual:session]) { session = nil; } @@ -363,7 +362,7 @@ - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - + RCTLog(@"[RNFetchBlobRequest] session didCompleteWithError %@", [error description]); self.error = error; NSString * errMsg; NSString * respStr; @@ -416,10 +415,17 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom respStr ?: [NSNull null] ]); + @synchronized(taskTable) + { + if([taskTable objectForKey:taskId] == nil) + NSLog(@"object released by ARC."); + else + [taskTable removeObjectForKey:taskId]; + } + respData = nil; receivedBytes = 0; [session finishTasksAndInvalidate]; - } // upload progress handler @@ -430,7 +436,7 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen } NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; - + if ([self.uploadProgressConfig shouldReport:now]) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD @@ -456,7 +462,19 @@ - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthentica - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { - NSLog(@"sess done in background"); + RCTLog(@"[RNFetchBlobRequest] session done in background"); + dispatch_async(dispatch_get_main_queue(), ^{ + id appDelegate = [UIApplication sharedApplication].delegate; + SEL selector = NSSelectorFromString(@"backgroundTransferCompletionHandler"); + if ([appDelegate respondsToSelector:selector]) { + void(^completionHandler)() = [appDelegate performSelector:selector]; + if (completionHandler != nil) { + completionHandler(); + completionHandler = nil; + } + } + + }); } - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler From 9c76911e9886f4a5512b0cda8a35e5767d2e08d1 Mon Sep 17 00:00:00 2001 From: Guy Blank Date: Tue, 2 Oct 2018 10:15:36 +0300 Subject: [PATCH 083/182] upload task - check if upload file exists --- ios/RNFetchBlobRequest.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 47c378570..0aea16e31 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -100,6 +100,12 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options uploadTask = [options valueForKey:@"IOSUploadTask"] == nil ? NO : [[options valueForKey:@"IOSUploadTask"] boolValue]; NSString * filepath = [options valueForKey:@"uploadFilePath"]; + + if (uploadTask && ![[NSFileManager defaultManager] fileExistsAtPath:filepath]) { + RCTLog(@"[RNFetchBlobRequest] sendRequest uploadTask file doesn't exist %@", filepath); + callback(@[@"uploadTask file doesn't exist", @"", [NSNull null]]); + return; + } // when followRedirect not set in options, defaults to TRUE followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue]; From 8d06e9c4975ccc245ae01946cd312e14821b1d41 Mon Sep 17 00:00:00 2001 From: Guy Blank Date: Tue, 2 Oct 2018 11:14:06 +0300 Subject: [PATCH 084/182] fix file exists check --- ios/RNFetchBlobRequest.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 0aea16e31..479d108b8 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -101,7 +101,7 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options NSString * filepath = [options valueForKey:@"uploadFilePath"]; - if (uploadTask && ![[NSFileManager defaultManager] fileExistsAtPath:filepath]) { + if (uploadTask && ![[NSFileManager defaultManager] fileExistsAtPath:[NSURL URLWithString:filepath].path]) { RCTLog(@"[RNFetchBlobRequest] sendRequest uploadTask file doesn't exist %@", filepath); callback(@[@"uploadTask file doesn't exist", @"", [NSNull null]]); return; From c01e1588fd6d11b3a50060fcce4b2181aff7a667 Mon Sep 17 00:00:00 2001 From: Guy Blank Date: Wed, 3 Oct 2018 17:09:11 +0300 Subject: [PATCH 085/182] Update README.md --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index a8414f045..6644f08f7 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ A project committed to making file access and data transfer easier and more effi * [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data) * [Upload/Download progress](#user-content-uploaddownload-progress) * [Cancel HTTP request](#user-content-cancel-request) + * [iOS Background Uploading](#user-content-ios-background-uploading) * [Android Media Scanner, and Download Manager Support](#user-content-android-media-scanner-and-download-manager-support) * [Self-Signed SSL Server](#user-content-self-signed-ssl-server) * [Transfer Encoding](#user-content-transfer-encoding) @@ -475,6 +476,34 @@ If you have existing code that uses `whatwg-fetch`(the official **fetch**), it's [See document and examples](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API#fetch-replacement) +### iOS Background Uploading + Normally, iOS interrupts network connections when an app is moved to the background, and will throw an error 'Lost connection to background transfer service' when the app resumes. To continue the upload of large files even when the app is in the background, you will need to enable IOSUploadTask options. + +First add the following property to your AppDelegate.h: +``` +@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)(); +``` +Then add the following to your AppDelegate.m: +``` +- (void)application:(UIApplication *)application +handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(void (^)(void))completionHandler { + self.backgroundTransferCompletionHandler = completionHandler; +} +``` +The following example shows how to upload a file in the background: + ```js + RNFetchBlob + .config({ + IOSBackgroundTask: true, // required for both upload + IOSUploadTask: true, // Use instead of IOSDownloadTask if uploading + uploadFilePath : 'file://' + filePath + }) + .fetch('PUT', url, { + 'Content-Type': mediaType + }, RNFetchBlob.wrap(filePath)); +``` + ### 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`. From 8bc5cebddaddc2e6d6d27dcb248d2e9bb24aecaf Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 15 Oct 2018 12:34:42 -0700 Subject: [PATCH 086/182] index.d.ts: Fix extends -> implements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: ``` node_modules/rn-fetch-blob/index.d.ts:147:43 - error TS2689: Cannot extend an interface 'EventTarget'. Did you mean 'implements'? 147 export declare class PolyfillBlob extends EventTarget { ~~~~~~~~~~~ error Command failed with exit code 1. ``` After: ``` ✨ Done in 3.06s. ``` --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 910fa4dba..881a5adfd 100644 --- a/index.d.ts +++ b/index.d.ts @@ -144,7 +144,7 @@ export interface PolyfillProgressEvent extends EventTarget { total: number; } -export declare class PolyfillBlob extends EventTarget { +export declare class PolyfillBlob implements EventTarget { /** * RNFetchBlob Blob polyfill, create a Blob directly from file path, BASE64 * encoded data, and string. The conversion is done implicitly according to From d6d5372893178c0be4e5512a6aa1a3ee16342ea6 Mon Sep 17 00:00:00 2001 From: Jacob Lauritzen Date: Tue, 20 Nov 2018 08:12:00 -0500 Subject: [PATCH 087/182] Update provider_paths.xml to allow access to cache --- android/src/main/res/xml/provider_paths.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/android/src/main/res/xml/provider_paths.xml b/android/src/main/res/xml/provider_paths.xml index 1434ff0ad..c38617d34 100644 --- a/android/src/main/res/xml/provider_paths.xml +++ b/android/src/main/res/xml/provider_paths.xml @@ -6,4 +6,7 @@ - \ No newline at end of file + + From 39c0c0fbcabea16c9c3bec15228319299826e310 Mon Sep 17 00:00:00 2001 From: Alpha Date: Thu, 6 Dec 2018 17:36:47 -0500 Subject: [PATCH 088/182] Add flow type definitions --- index.js.flow | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 index.js.flow diff --git a/index.js.flow b/index.js.flow new file mode 100644 index 000000000..ecfd50a2d --- /dev/null +++ b/index.js.flow @@ -0,0 +1,187 @@ +// @flow strict + +declare class AndroidApi { + actionViewIntent(path: string, mime?: string): Promise; + addCompleteDownload(options: AndroidDownloadOption): Promise; + getContentIntent(mime: string): Promise; + getSDCardApplicationDir(): Promise; + getSDCardDir(): Promise; +} + +declare class FetchBlobResponse { + data: string; + respInfo: RNFetchBlobResponseInfo; + taskId: string; + type: "utf8" | "base64" | "path"; + array(): Promise; + base64(): string | Promise; + blob(): Promise; + flush(): Promise; + info(): RNFetchBlobResponseInfo; + // $FlowExpectedError Not possible to specify in strict mode. + json(): any; + path(): string; + readFile(encoding: Encoding): ?Promise; + readStream(encoding: Encoding): ?Promise; + session(name: string): ?RNFetchBlobSession; + text(): string | Promise; +} + +declare class FsApi { + RNFetchBlobSession: RNFetchBlobSession; + dirs: Dirs; + appendFile(path: string, data: string | number[], encoding?: Encoding | "uri"): Promise; + asset(path: string): string; + cp(path: string, dest: string): Promise; + createFile(path: string, data: string, encoding: Encoding | "uri"): Promise; + df(): Promise; + exists(path: string): Promise; + hash(path: string, algorithm: HashAlgorithm): Promise; + isDir(path: string): Promise; + ls(path: string): Promise; + lstat(path: string): Promise; + mkdir(path: string): Promise; + mv(path: string, dest: string): Promise; + pathForAppGroup(groupName: string): Promise; + readFile(path: string, encoding: Encoding, bufferSize?: number): Promise; + readStream(path: string, encoding: Encoding, bufferSize?: number, tick?: number): Promise; + scanFile(pairs: {mime: string, path: string}[]): Promise; + session(name: string): RNFetchBlobSession; + slice(src: string, dest: string, start: number, end: number): Promise; + stat(path: string): Promise; + unlink(path: string): Promise; + writeFile(path: string, data: string | number[], encoding?: Encoding | "uri"): Promise; + writeStream(path: string, encoding: Encoding, append?: boolean): Promise; +} + +declare class IosApi { + excludeFromBackupKey(path: string): Promise; + openDocument(path: string, scheme?: string): Promise; + previewDocument(path: string, scheme?: string): Promise; +} + +declare class RNFetchBlobReadStream { + bufferSize?: number; + closed: boolean; + encoding: Encoding; + path: string; + tick: number; + onData(fn: (chunk: string) => void): void; + onEnd(fn: () => void): void; + onError(fn: (err: Error) => void): void; + open(): void; +} + +declare class RNFetchBlobSession { + static getSession(name: string): RNFetchBlobSession; + static removeSession(name: string): void; + static setSession(name: string, val: RNFetchBlobSession): void; + + name: string; + add(path: string): RNFetchBlobSession; + constructor(name: string, list: string[]): RNFetchBlobSession; + dispose(): Promise; + list(): string[]; + remove(path: string): RNFetchBlobSession; +} + +declare class RNFetchBlobWriteStream { + append: boolean; + encoding: string; + id: string; + close(): void; + write(data: string): Promise; +} + +declare class RNFetchBlob { + android: AndroidApi; + base64: {+decode: (input: string) => string, +encode: (input: string) => string}; + fs: FsApi; + ios: IosApi; + config(options: RNFetchBlobConfig): {fetch: (method: Methods, url: string, headers?: {[key: string]: string}, body?: string | FormField[]) => StatefulPromise}; + fetch(method: Methods, url: string, headers?: {[key: string]: string}, body?: string | FormField[]): StatefulPromise; + session(name: string): RNFetchBlobSession; + wrap(path: string): string; +} + +declare class StatefulPromise extends Promise { + cancel(callback?: (error: ?string, taskId: ?string) => void): void; + expire(callback: () => void): StatefulPromise; + progress(config: {count?: number, interval?: number} | ProgressCallback, callback?: ProgressCallback): StatefulPromise; + stateChange(callback: (state: RNFetchBlobResponseInfo) => void): StatefulPromise; + uploadProgress(config: {count?: number, interval?: number} | UploadProgressCallback, callback?: UploadProgressCallback): StatefulPromise; +} + +export type AddAndroidDownloads = { + description?: string, + mediaScannable?: boolean, + mime?: string, + notification?: boolean, + path?: string, + title?: string, + useDownloadManager?: boolean +}; +export type AndroidDownloadOption = { + description?: string, + mime?: string, + path: string, + showNotification?: boolean, + title?: string +}; +export type AndroidFsStat = { + external_free: number, + external_total: number, + internal_free: number, + internal_total: number +}; +export type Dirs = { + CacheDir: string, + DCIMDir: string, + DocumentDir: string, + DownloadDir: string, + LibraryDir: string, + MainBundleDir: string, + MovieDir: string, + MusicDir: string, + PictureDir: string, + SDCardApplicationDir: string, + SDCardDir: string +}; +export type Encoding = "utf8" | "ascii" | "base64"; +export type FormField = {data: string, filename?: string, name: string, type?: string}; +export type HashAlgorithm = "md5" | "sha1" | "sha224" | "sha256" | "sha384" | "sha512"; +export type IosFsStat = {free: number, total: number}; +export type Methods = "POST" | "GET" | "DELETE" | "PUT" | "post" | "get" | "delete" | "put"; +export type ProgressCallback = (received: number, total: number) => void; +export type RNFetchBlobConfig = { + IOSBackgroundTask?: boolean, + addAndroidDownloads?: AddAndroidDownloads, + appendExt?: string, + fileCache?: boolean, + indicator?: boolean, + overwrite?: boolean, + path?: string, + session?: string, + timeout?: number, + trusty?: boolean +}; +export type RNFetchBlobResponseInfo = { + headers: {[fieldName: string]: string}, + redirects: string[], + respType: "text" | "blob" | "" | "json", + rnfbEncode: "path" | Encoding, + state: string, + status: number, + taskId: string, + timeout: boolean +}; +export type RNFetchBlobStat = { + filename: string, + lastModified: number, + path: string, + size: number, + type: "directory" | "file" | "asset" +}; +export type UploadProgressCallback = (sent: number, total: number) => void; + +declare export default RNFetchBlob; From f4acab9e5f348d4ba4b756d3ca2744c5e69a0d6d Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Tue, 11 Dec 2018 19:54:19 -0700 Subject: [PATCH 089/182] update android build config for newer react-native versions --- android/build.gradle | 5 +++-- android/gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 184835289..062f54172 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -11,9 +11,10 @@ repositories { buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.1.4' } } @@ -37,7 +38,7 @@ android { } dependencies { - compile "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" + implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" //compile 'com.squareup.okhttp3:okhttp:+' //{RNFetchBlob_PRE_0.28_DEPDENDENCY} } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 317d481f3..c75df059d 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip From 9ed5dcb25647a42ba7019b77db5f90b9adc596e6 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Tue, 11 Dec 2018 20:03:58 -0700 Subject: [PATCH 090/182] 0.10.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66b0a5d28..fead022bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.13", + "version": "0.10.14", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From ca4bf4e3e4fd4113e580595dda5ec5a25f35b102 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 22 Dec 2018 08:21:45 -0700 Subject: [PATCH 091/182] Revert "Merge pull request #198 from capriza/master" This reverts commit d69c72bb3f7ab0e25092be31e49fd0be605e480b, reversing changes made to c95ef1c199c32d55e29e192517e1fa0be7dd960c. --- README.md | 29 --------- ios/RNFetchBlobNetwork.m | 10 +++- ios/RNFetchBlobRequest.h | 5 +- ios/RNFetchBlobRequest.m | 124 ++++++++++++++++----------------------- 4 files changed, 59 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 6644f08f7..a8414f045 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ A project committed to making file access and data transfer easier and more effi * [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data) * [Upload/Download progress](#user-content-uploaddownload-progress) * [Cancel HTTP request](#user-content-cancel-request) - * [iOS Background Uploading](#user-content-ios-background-uploading) * [Android Media Scanner, and Download Manager Support](#user-content-android-media-scanner-and-download-manager-support) * [Self-Signed SSL Server](#user-content-self-signed-ssl-server) * [Transfer Encoding](#user-content-transfer-encoding) @@ -476,34 +475,6 @@ If you have existing code that uses `whatwg-fetch`(the official **fetch**), it's [See document and examples](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API#fetch-replacement) -### iOS Background Uploading - Normally, iOS interrupts network connections when an app is moved to the background, and will throw an error 'Lost connection to background transfer service' when the app resumes. To continue the upload of large files even when the app is in the background, you will need to enable IOSUploadTask options. - -First add the following property to your AppDelegate.h: -``` -@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)(); -``` -Then add the following to your AppDelegate.m: -``` -- (void)application:(UIApplication *)application -handleEventsForBackgroundURLSession:(NSString *)identifier - completionHandler:(void (^)(void))completionHandler { - self.backgroundTransferCompletionHandler = completionHandler; -} -``` -The following example shows how to upload a file in the background: - ```js - RNFetchBlob - .config({ - IOSBackgroundTask: true, // required for both upload - IOSUploadTask: true, // Use instead of IOSDownloadTask if uploading - uploadFilePath : 'file://' + filePath - }) - .fetch('PUT', url, { - 'Content-Type': mediaType - }, RNFetchBlob.wrap(filePath)); -``` - ### 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`. diff --git a/ios/RNFetchBlobNetwork.m b/ios/RNFetchBlobNetwork.m index fbb421f38..f2e40b6b4 100644 --- a/ios/RNFetchBlobNetwork.m +++ b/ios/RNFetchBlobNetwork.m @@ -63,7 +63,7 @@ - (id)init { + (RNFetchBlobNetwork* _Nullable)sharedInstance { static id _sharedInstance = nil; static dispatch_once_t onceToken; - + dispatch_once(&onceToken, ^{ _sharedInstance = [[self alloc] init]; }); @@ -135,8 +135,14 @@ - (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *) - (void) cancelRequest:(NSString *)taskId { + NSURLSessionDataTask * task; + @synchronized ([RNFetchBlobNetwork class]) { - [[self.requestsTable objectForKey:taskId] cancelRequest:taskId]; + task = [self.requestsTable objectForKey:taskId].task; + } + + if (task && task.state == NSURLSessionTaskStateRunning) { + [task cancel]; } } diff --git a/ios/RNFetchBlobRequest.h b/ios/RNFetchBlobRequest.h index 7e5776ed3..b550ac22e 100644 --- a/ios/RNFetchBlobRequest.h +++ b/ios/RNFetchBlobRequest.h @@ -32,8 +32,7 @@ @property (nullable, nonatomic) NSError * error; @property (nullable, nonatomic) RNFetchBlobProgress *progressConfig; @property (nullable, nonatomic) RNFetchBlobProgress *uploadProgressConfig; -//@property (nullable, nonatomic, weak) NSURLSessionDataTask *task; -@property (nonatomic, strong) __block NSURLSession * session; +@property (nullable, nonatomic, weak) NSURLSessionDataTask *task; - (void) sendRequest:(NSDictionary * _Nullable )options contentLength:(long)contentLength @@ -43,8 +42,6 @@ taskOperationQueue:(NSOperationQueue * _Nonnull)operationQueue callback:(_Nullable RCTResponseSenderBlock) callback; -- (void) cancelRequest:(NSString *)taskId; - @end #endif /* RNFetchBlobRequest_h */ diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 479d108b8..a56cc92d0 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -11,24 +11,10 @@ #import "RNFetchBlobFS.h" #import "RNFetchBlobConst.h" #import "RNFetchBlobReqBuilder.h" -#if __has_include() -#import -#else -#import "RCTLog.h" -#endif #import "IOS7Polyfill.h" #import -NSMapTable * taskTable; - -__attribute__((constructor)) -static void initialize_tables() { - if(taskTable == nil) - { - taskTable = [[NSMapTable alloc] init]; - } -} typedef NS_ENUM(NSUInteger, ResponseFormat) { UTF8, @@ -50,7 +36,6 @@ @interface RNFetchBlobRequest () ResponseFormat responseFormat; BOOL followRedirect; BOOL backgroundTask; - BOOL uploadTask; } @end @@ -97,16 +82,6 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options self.options = options; backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue]; - uploadTask = [options valueForKey:@"IOSUploadTask"] == nil ? NO : [[options valueForKey:@"IOSUploadTask"] boolValue]; - - NSString * filepath = [options valueForKey:@"uploadFilePath"]; - - if (uploadTask && ![[NSFileManager defaultManager] fileExistsAtPath:[NSURL URLWithString:filepath].path]) { - RCTLog(@"[RNFetchBlobRequest] sendRequest uploadTask file doesn't exist %@", filepath); - callback(@[@"uploadTask file doesn't exist", @"", [NSNull null]]); - return; - } - // when followRedirect not set in options, defaults to TRUE followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue]; isIncrement = [[options valueForKey:@"increment"] boolValue]; @@ -129,6 +104,7 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options NSString * path = [self.options valueForKey:CONFIG_FILE_PATH]; NSString * key = [self.options valueForKey:CONFIG_KEY]; + NSURLSession * session; bodyLength = contentLength; @@ -141,7 +117,6 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId]; } - // request timeout, -1 if not set in options float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue]; @@ -150,7 +125,7 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options } defaultConfigObject.HTTPMaximumConnectionsPerHost = 10; - _session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; + session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; if (path || [self.options valueForKey:CONFIG_USE_TEMP]) { respFile = YES; @@ -182,19 +157,8 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options respFile = NO; } - __block NSURLSessionTask * task; - - if(uploadTask) - { - task = [_session uploadTaskWithRequest:req fromFile:[NSURL URLWithString:filepath]]; - } - else - { - task = [_session dataTaskWithRequest:req]; - } - - [taskTable setObject:task forKey:taskId]; - [task resume]; + self.task = [session dataTaskWithRequest:req]; + [self.task resume]; // network status indicator if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) { @@ -218,7 +182,6 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options // set expected content length on response received - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { - NSLog(@"sess didReceiveResponse"); expectedBytes = [response expectedContentLength]; NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; @@ -244,7 +207,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat partBuffer = [[NSMutableData alloc] init]; completionHandler(NSURLSessionResponseAllow); - + return; } else { self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; @@ -306,6 +269,42 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat NSLog(@"oops"); } + if (respFile) + { + @try{ + NSFileManager * fm = [NSFileManager defaultManager]; + NSString * folder = [destPath stringByDeletingLastPathComponent]; + + if (![fm fileExistsAtPath:folder]) { + [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil]; + } + + // if not set overwrite in options, defaults to TRUE + BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue]; + BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"]; + + appendToExistingFile = !overwrite; + + // For solving #141 append response data if the file already exists + // base on PR#139 @kejinliang + if (appendToExistingFile) { + destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""]; + } + + if (![fm fileExistsAtPath:destPath]) { + [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil]; + } + + writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile]; + [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + [writeStream open]; + } + @catch(NSException * ex) + { + NSLog(@"write file error"); + } + } + completionHandler(NSURLSessionResponseAllow); } @@ -329,7 +328,11 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } - [respData appendData:data]; + if (respFile) { + [writeStream write:[data bytes] maxLength:[data length]]; + } else { + [respData appendData:data]; + } if (expectedBytes == 0) { return; @@ -350,16 +353,8 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } } -- (void) cancelRequest:(NSString *)taskId -{ - NSURLSessionDataTask * task = [taskTable objectForKey:taskId]; - if(task != nil && task.state == NSURLSessionTaskStateRunning) - [task cancel]; -} - - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error { - RCTLog(@"[RNFetchBlobRequest] session didBecomeInvalidWithError %@", [error description]); if ([session isEqual:session]) { session = nil; } @@ -368,7 +363,7 @@ - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - RCTLog(@"[RNFetchBlobRequest] session didCompleteWithError %@", [error description]); + self.error = error; NSString * errMsg; NSString * respStr; @@ -421,17 +416,10 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom respStr ?: [NSNull null] ]); - @synchronized(taskTable) - { - if([taskTable objectForKey:taskId] == nil) - NSLog(@"object released by ARC."); - else - [taskTable removeObjectForKey:taskId]; - } - respData = nil; receivedBytes = 0; [session finishTasksAndInvalidate]; + } // upload progress handler @@ -442,7 +430,7 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen } NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; - + if ([self.uploadProgressConfig shouldReport:now]) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD @@ -468,19 +456,7 @@ - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthentica - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { - RCTLog(@"[RNFetchBlobRequest] session done in background"); - dispatch_async(dispatch_get_main_queue(), ^{ - id appDelegate = [UIApplication sharedApplication].delegate; - SEL selector = NSSelectorFromString(@"backgroundTransferCompletionHandler"); - if ([appDelegate respondsToSelector:selector]) { - void(^completionHandler)() = [appDelegate performSelector:selector]; - if (completionHandler != nil) { - completionHandler(); - completionHandler = nil; - } - } - - }); + NSLog(@"sess done in background"); } - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler From d8c79f6b261e7bd76b477f2b304379b1dbeb8836 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sat, 22 Dec 2018 08:25:30 -0700 Subject: [PATCH 092/182] 0.10.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fead022bf..4cf032974 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.14", + "version": "0.10.15", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 574febb4a88bfe3bc45cb03c5730c43e86276ccb Mon Sep 17 00:00:00 2001 From: vun Date: Sat, 5 Jan 2019 06:23:53 +0800 Subject: [PATCH 093/182] Add RNFetchblob.fs.hash function to type definition --- index.d.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/index.d.ts b/index.d.ts index 881a5adfd..7ecda3143 100644 --- a/index.d.ts +++ b/index.d.ts @@ -293,6 +293,7 @@ export interface Net { removeCookies(domain?: string): Promise; } +type HashAlgorithm = "md5" | "sha1" | "sha224" | "sha256" | "sha384" | "sha512"; export interface FS { RNFetchBlobSession: RNFetchBlobSession; @@ -316,6 +317,14 @@ export interface FS { ls(path: string): Promise; + /** + * Read the file from the given path and calculate a cryptographic hash sum over its contents. + * + * @param path Path to the file + * @param algorithm The hash algorithm to use + */ + hash(path: string, algorithm: HashAlgorithm); + /** * Create file stream from file at `path`. * @param path The file path. From b48f0e786231fdd34d5c7b7b272e60e5708ed82f Mon Sep 17 00:00:00 2001 From: vun Date: Sat, 5 Jan 2019 06:42:15 +0800 Subject: [PATCH 094/182] Added return type for RNFetchblob.fs.hash typedef --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 7ecda3143..f80157723 100644 --- a/index.d.ts +++ b/index.d.ts @@ -323,7 +323,7 @@ export interface FS { * @param path Path to the file * @param algorithm The hash algorithm to use */ - hash(path: string, algorithm: HashAlgorithm); + hash(path: string, algorithm: HashAlgorithm): Promise; /** * Create file stream from file at `path`. From e816b028b126b85c6aa807ec0eff9ddc79077243 Mon Sep 17 00:00:00 2001 From: Greg Alexander Date: Wed, 23 Jan 2019 23:13:25 -0600 Subject: [PATCH 095/182] upgrading to sdk 28 and androidx --- android/gradle.properties | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 android/gradle.properties diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 000000000..e69de29bb From e83f84f1329218c3cf52b99d7a0dbb3a1a8c47d8 Mon Sep 17 00:00:00 2001 From: Greg Alexander Date: Wed, 23 Jan 2019 23:13:52 -0600 Subject: [PATCH 096/182] upgrading to sdk 28 and androidx --- android/build.gradle | 8 ++++---- android/gradle.properties | 2 ++ android/src/main/AndroidManifest.xml | 2 +- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 3 +-- .../src/main/java/com/RNFetchBlob/RNFetchBlobBody.java | 2 +- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 3 +-- .../com/RNFetchBlob/Response/RNFetchBlobFileResp.java | 3 +-- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 062f54172..afe1c95ed 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -14,16 +14,16 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.android.tools.build:gradle:3.2.1' } } android { - compileSdkVersion safeExtGet('compileSdkVersion', 26) - buildToolsVersion safeExtGet('buildToolsVersion', '26.0.3') + compileSdkVersion safeExtGet('compileSdkVersion', 28) + buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3') defaultConfig { minSdkVersion safeExtGet('minSdkVersion', 16) - targetSdkVersion safeExtGet('targetSdkVersion', 26) + targetSdkVersion safeExtGet('targetSdkVersion', 28) versionCode 1 versionName "1.0" } diff --git a/android/gradle.properties b/android/gradle.properties index e69de29bb..5465fec0e 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -0,0 +1,2 @@ +android.enableJetifier=true +android.useAndroidX=true \ No newline at end of file diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index afa9020b2..b9c03c786 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -24,7 +24,7 @@ diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index ac9ce5669..f47aef963 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -6,7 +6,7 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; -import android.support.v4.content.FileProvider; +import androidx.core.content.FileProvider; import android.util.SparseArray; import com.facebook.react.bridge.ActivityEventListener; @@ -28,7 +28,6 @@ import okhttp3.JavaNetCookieJar; import java.io.File; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java index 3150eb2e8..adbe48b72 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java @@ -1,6 +1,6 @@ package com.RNFetchBlob; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.Base64; import com.facebook.react.bridge.Arguments; diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 369b9baaf..060538b48 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -8,7 +8,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.Build; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.Base64; import com.RNFetchBlob.Response.RNFetchBlobDefaultResp; @@ -16,7 +16,6 @@ import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMapKeySetIterator; diff --git a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java index e4f725777..7a6acf8e5 100644 --- a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java +++ b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java @@ -1,7 +1,6 @@ package com.RNFetchBlob.Response; -import android.support.annotation.NonNull; -import android.util.Log; +import androidx.annotation.NonNull; import com.RNFetchBlob.RNFetchBlobConst; import com.RNFetchBlob.RNFetchBlobProgressConfig; From 1a9d1bce5dcb5255899e5372d0e51a297dbf6dc1 Mon Sep 17 00:00:00 2001 From: Samuel Suther Date: Thu, 24 Jan 2019 22:32:40 +0100 Subject: [PATCH 097/182] require cycle This fixed the warning for "require cycle" on newer React-Versions --- polyfill/FileReader.js | 1 - 1 file changed, 1 deletion(-) diff --git a/polyfill/FileReader.js b/polyfill/FileReader.js index b72df17f7..ef0ebfc0b 100644 --- a/polyfill/FileReader.js +++ b/polyfill/FileReader.js @@ -2,7 +2,6 @@ // Use of this source code is governed by a MIT-style license that can be // found in the LICENSE file. -import RNFetchBlob from '../index.js' import ProgressEvent from './ProgressEvent.js' import EventTarget from './EventTarget' import Blob from './Blob' From 27768f470401deb08f281cb9552cf76cc65b495d Mon Sep 17 00:00:00 2001 From: Greg Alexander Date: Thu, 24 Jan 2019 16:38:19 -0600 Subject: [PATCH 098/182] build fix --- android/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/build.gradle b/android/build.gradle index afe1c95ed..a4ca7a421 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,6 +6,8 @@ def safeExtGet(prop, fallback) { repositories { mavenCentral() + jcenter() + google() } buildscript { From 24683eb4168badee5467a208f1062a435260eced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=9D=A4?= <1498710037@qq.com> Date: Thu, 7 Feb 2019 16:44:51 +0800 Subject: [PATCH 099/182] Solve the conflict between FileProvider and other libraries --- android/src/main/AndroidManifest.xml | 4 ++-- android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index afa9020b2..1c92420b8 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -24,7 +24,7 @@ @@ -34,4 +34,4 @@ - \ No newline at end of file + diff --git a/android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java b/android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java new file mode 100644 index 000000000..0d1fced4a --- /dev/null +++ b/android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java @@ -0,0 +1,4 @@ +package com.RNFetchBlob.Utils; + +public class FileProvider extends android.support.v4.content.FileProvider { +} From 9ae02891dba13ce378ca985f779f49dbe193bb8b Mon Sep 17 00:00:00 2001 From: Reed Jones Date: Fri, 8 Feb 2019 09:50:46 -0700 Subject: [PATCH 100/182] specify react-native link module in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8414f045..52b124c2a 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ If automatically linking doesn't work for you, see instructions on [manually lin For 0.29.2+ projects, simply link native packages via the following command (note: rnpm has been merged into react-native) ``` -react-native link +react-native link rn-fetch-blob ``` As for projects < 0.29 you need `rnpm` to link native packages @@ -95,7 +95,7 @@ rnpm link Optionally, use the following command to add Android permissions to `AndroidManifest.xml` automatically ```sh -RNFB_ANDROID_PERMISSIONS=true react-native link +RNFB_ANDROID_PERMISSIONS=true react-native link rn-fetch-blob ``` pre 0.29 projects From 24abf39a4727cdda52c2ee8bd257bb0777832830 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Thu, 21 Feb 2019 17:34:28 +0530 Subject: [PATCH 101/182] Updated for iOS Not working in iPhone due to presence of charset utf-8 --- ios/RNFetchBlobReqBuilder.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNFetchBlobReqBuilder.m b/ios/RNFetchBlobReqBuilder.m index 16154436e..16963bb5f 100644 --- a/ios/RNFetchBlobReqBuilder.m +++ b/ios/RNFetchBlobReqBuilder.m @@ -69,7 +69,7 @@ +(void) buildMultipartRequest:(NSDictionary *)options [mheaders setValue:[NSString stringWithFormat:@"%lu",[postData length]] forKey:@"Content-Length"]; [mheaders setValue:@"100-continue" forKey:@"Expect"]; // appaned boundary to content-type - [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forKey:@"content-type"]; + [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] forKey:@"content-type"]; [request setHTTPMethod: method]; [request setAllHTTPHeaderFields:mheaders]; onComplete(request, [formData length]); From c5f9a668af14dc586c4b88e61a91a65aba10a6ff Mon Sep 17 00:00:00 2001 From: Jediah Dizon Date: Fri, 22 Feb 2019 18:43:52 -0700 Subject: [PATCH 102/182] Fix error message on `mkdir` function --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 101e8033a..225667a2c 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -523,7 +523,7 @@ private static void deleteRecursive(File fileOrDirectory) throws IOException { static void mkdir(String path, Promise promise) { File dest = new File(path); if(dest.exists()) { - promise.reject("EEXIST", dest.isDirectory() ? "Folder" : "File" + " '" + path + "' already exists"); + promise.reject("EEXIST", (dest.isDirectory() ? "Folder" : "File") + " '" + path + "' already exists"); return; } try { From ede920cd133ed74096f31216b249bb6e6eac679a Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Sat, 2 Mar 2019 20:14:43 +0100 Subject: [PATCH 103/182] Fixing #236 which did not expect null from DownloadManager.query() --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 369b9baaf..ef3b54f51 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -667,29 +667,39 @@ public void onReceive(Context context, Intent intent) { DownloadManager dm = (DownloadManager) appCtx.getSystemService(Context.DOWNLOAD_SERVICE); dm.query(query); Cursor c = dm.query(query); - + // #236 unhandled null check for DownloadManager.query() return value + if (c == null) { + this.callback.invoke("Download manager failed to download from " + this.url + ". Query was unsuccessful ", null, null); + return; + } String filePath = null; - // the file exists in media content database - if (c.moveToFirst()) { - // #297 handle failed request - int statusCode = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); - if(statusCode == DownloadManager.STATUS_FAILED) { - this.callback.invoke("Download manager failed to download from " + this.url + ". Status Code = " + statusCode, null, null); - return; - } - String contentUri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); - if ( contentUri != null && - options.addAndroidDownloads.hasKey("mime") && - options.addAndroidDownloads.getString("mime").contains("image")) { - Uri uri = Uri.parse(contentUri); - Cursor cursor = appCtx.getContentResolver().query(uri, new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null); - // use default destination of DownloadManager - if (cursor != null) { - cursor.moveToFirst(); - filePath = cursor.getString(0); - cursor.close(); + try { + // the file exists in media content database + if (c.moveToFirst()) { + // #297 handle failed request + int statusCode = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); + if(statusCode == DownloadManager.STATUS_FAILED) { + this.callback.invoke("Download manager failed to download from " + this.url + ". Status Code = " + statusCode, null, null); + return; } + String contentUri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); + if ( contentUri != null && + options.addAndroidDownloads.hasKey("mime") && + options.addAndroidDownloads.getString("mime").contains("image")) { + Uri uri = Uri.parse(contentUri); + Cursor cursor = appCtx.getContentResolver().query(uri, new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null); + // use default destination of DownloadManager + if (cursor != null) { + cursor.moveToFirst(); + filePath = cursor.getString(0); + cursor.close(); + } + } + } + } finally { + if (c != null) { + c.close(); } } From 0b47f3d34a95504eab6ead1784c1646fc7c2e9b3 Mon Sep 17 00:00:00 2001 From: Michael Gall Date: Thu, 7 Mar 2019 17:44:46 +1100 Subject: [PATCH 104/182] Add the FLAG_ACTIVITY_NEW_TASK flag. This is caused by an error on Android 9: 'Error: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?' --- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index ac9ce5669..be310c87f 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -120,6 +120,8 @@ public void actionViewIntent(String path, String mime, final Promise promise) { // Set flag to give temporary permission to external app to use FileProvider intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + // All the activity to be opened outside of an activity + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Validate that the device can open the file PackageManager pm = getCurrentActivity().getPackageManager(); if (intent.resolveActivity(pm) != null) { @@ -410,4 +412,4 @@ public void getSDCardDir(Promise promise) { public void getSDCardApplicationDir(Promise promise) { RNFetchBlobFS.getSDCardApplicationDir(this.getReactApplicationContext(), promise); } -} \ No newline at end of file +} From 56fedad8941c530bf5e86c0ed75febc4b2bf122a Mon Sep 17 00:00:00 2001 From: Micah Ng Date: Fri, 8 Mar 2019 16:39:15 -0500 Subject: [PATCH 105/182] Fix fs.dirs api on iOS These constants were never actually implemented. --- ios/RNFetchBlob/RNFetchBlob.m | 9 +++++++-- ios/RNFetchBlobFS.h | 9 +++++++-- ios/RNFetchBlobFS.m | 8 ++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index b4642d459..99e0897e6 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -68,9 +68,14 @@ - (id) init { - (NSDictionary *)constantsToExport { return @{ - @"MainBundleDir" : [RNFetchBlobFS getMainBundleDir], + @"CacheDir" : [RNFetchBlobFS getCacheDir], @"DocumentDir": [RNFetchBlobFS getDocumentDir], - @"CacheDir" : [RNFetchBlobFS getCacheDir] + @"DownloadDir" : [RNFetchBlobFS getDownloadDir], + @"LibraryDir" : [RNFetchBlobFS getLibraryDir], + @"MainBundleDir" : [RNFetchBlobFS getMainBundleDir], + @"MovieDir" : [RNFetchBlobFS getMovieDir], + @"MusicDir" : [RNFetchBlobFS getMusicDir], + @"PictureDir" : [RNFetchBlobFS getPictureDir], }; } diff --git a/ios/RNFetchBlobFS.h b/ios/RNFetchBlobFS.h index 222b2f8e6..514120138 100644 --- a/ios/RNFetchBlobFS.h +++ b/ios/RNFetchBlobFS.h @@ -46,10 +46,15 @@ @property (nonatomic) BOOL appendData; // get dirs -+ (NSString *) getMainBundleDir; -+ (NSString *) getTempPath; + (NSString *) getCacheDir; + (NSString *) getDocumentDir; ++ (NSString *) getDownloadDir; ++ (NSString *) getLibraryDir; ++ (NSString *) getMainBundleDir; ++ (NSString *) getMovieDir; ++ (NSString *) getMusicDir; ++ (NSString *) getPictureDir; ++ (NSString *) getTempPath; + (NSString *) getTempPath:(NSString*)taskId withExtension:(NSString *)ext; + (NSString *) getPathOfAsset:(NSString *)assetURI; + (NSString *) getPathForAppGroup:(NSString *)groupName; diff --git a/ios/RNFetchBlobFS.m b/ios/RNFetchBlobFS.m index 1d16ffa40..e597ee5d5 100644 --- a/ios/RNFetchBlobFS.m +++ b/ios/RNFetchBlobFS.m @@ -104,6 +104,14 @@ + (NSString *) getDocumentDir { return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; } ++ (NSString *) getDownloadDir { + return [NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSUserDomainMask, YES) firstObject]; +} + ++ (NSString *) getLibraryDir { + return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject]; +} + + (NSString *) getMusicDir { return [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) firstObject]; } From 831092a628a15f2e7e9a0f41fce94ba6206451dc Mon Sep 17 00:00:00 2001 From: Michael Mason Date: Tue, 30 Apr 2019 16:19:29 +0100 Subject: [PATCH 106/182] Fix crash when streaming file with Arabic chars See: https://developer.android.com/reference/java/nio/charset/Charset.html#defaultCharset() > Android note: The Android platform default is always UTF-8. --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 101e8033a..d610ba707 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -21,9 +21,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule; import java.io.*; -import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; import java.security.MessageDigest; import java.util.ArrayList; import java.util.HashMap; @@ -325,9 +323,7 @@ else if(resolved == null) { boolean error = false; if (encoding.equalsIgnoreCase("utf8")) { - CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); while ((cursor = fs.read(buffer)) != -1) { - encoder.encode(ByteBuffer.wrap(buffer).asCharBuffer()); String chunk = new String(buffer, 0, cursor); emitStreamEvent(streamId, "data", chunk); if(tick > 0) From 51b50f27878f737f36f17737e1c0c869ac49ba40 Mon Sep 17 00:00:00 2001 From: Michael Mason Date: Tue, 30 Apr 2019 16:25:59 +0100 Subject: [PATCH 107/182] Fix crash on HTTP response containing Arabic chars See: https://developer.android.com/reference/java/nio/charset/Charset.html#defaultCharset() > Android note: The Android platform default is always UTF-8. --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 369b9baaf..9bc24f84f 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -503,28 +503,12 @@ private void done(Response resp) { // encoding will somehow break the UTF8 string format, to encode UTF8 // string correctly, we should do URL encoding before BASE64. byte[] b = resp.body().bytes(); - CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); if(responseFormat == ResponseFormat.BASE64) { callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP)); return; } - try { - encoder.encode(ByteBuffer.wrap(b).asCharBuffer()); - // if the data contains invalid characters the following lines will be - // skipped. - String utf8 = new String(b); - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, utf8); - } - // This usually mean the data is contains invalid unicode characters, it's - // binary data - catch(CharacterCodingException ignored) { - if(responseFormat == ResponseFormat.UTF8) { - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, ""); - } - else { - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP)); - } - } + String utf8 = new String(b); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, utf8); } } catch (IOException e) { callback.invoke("RNFetchBlob failed to encode response data to BASE64 string.", null); From bfc51af4308b8ef674e9145f499adad016d66075 Mon Sep 17 00:00:00 2001 From: Michael Mason Date: Tue, 30 Apr 2019 16:39:30 +0100 Subject: [PATCH 108/182] Remove unused imports --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 9bc24f84f..c68f4f5d7 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -37,10 +37,6 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; -import java.nio.ByteBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; import java.security.KeyStore; import java.util.ArrayList; import java.util.Arrays; From b7c5e94f26278eb7235b074fd8a2e9e2363af5ac Mon Sep 17 00:00:00 2001 From: Juliette Rapala Date: Thu, 2 May 2019 14:03:52 -0500 Subject: [PATCH 109/182] Remove unused and deprecated AsyncStorage import --- index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/index.js b/index.js index 0135fd8f7..21d1413c1 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,6 @@ import { DeviceEventEmitter, NativeAppEventEmitter, Platform, - AsyncStorage, AppState, } from 'react-native' import type { From be168c3b75d68db4f8b24cd66c12d2d62b6e6b92 Mon Sep 17 00:00:00 2001 From: Sergey Sychev Date: Mon, 6 May 2019 12:53:30 +0300 Subject: [PATCH 110/182] info() method definition for FetchBlobResponse --- index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/index.d.ts b/index.d.ts index 881a5adfd..1affdfbaf 100644 --- a/index.d.ts +++ b/index.d.ts @@ -96,6 +96,7 @@ export interface FetchBlobResponse { */ flush(): void; respInfo: RNFetchBlobResponseInfo; + info(): RNFetchBlobResponseInfo; session(name: string): RNFetchBlobSession | null; /** * Read file content with given encoding, if the response does not contains From dbed840c7d14561fc38591e73a4e69752ee75cc0 Mon Sep 17 00:00:00 2001 From: nadav Date: Mon, 3 Jun 2019 14:56:08 +0300 Subject: [PATCH 111/182] Update Fetch.js https://github.com/joltup/rn-fetch-blob/issues/369 Resolution to the above issue, the RN code passes two instances of Content-Type, one containing capital letters and the other in lower case. The Android native code saves those options after applying .toLowerCase() on them. The data in the lower case content-type overwrote the data in the Content-Type, and since the data on both the keys wasn't updated together at the fixed part of the code, it overwrote it with invalid data and caused the request to fail. --- polyfill/Fetch.js | 1 + 1 file changed, 1 insertion(+) diff --git a/polyfill/Fetch.js b/polyfill/Fetch.js index 3ecb5915c..35a18b316 100644 --- a/polyfill/Fetch.js +++ b/polyfill/Fetch.js @@ -40,6 +40,7 @@ class RNFetchBlobFetchPolyfill { promise = Blob.build(body).then((b) => { blobCache = b options.headers['Content-Type'] = 'multipart/form-data;boundary=' + b.multipartBoundary + options.headers['content-type'] = 'multipart/form-data;boundary=' + b.multipartBoundary return Promise.resolve(RNFetchBlob.wrap(b._ref)) }) } From da40583878dec8d96220278bf9916c4634f61160 Mon Sep 17 00:00:00 2001 From: Emmett Harper Date: Fri, 14 Jun 2019 15:49:40 -0700 Subject: [PATCH 112/182] Cancel download throw error bugfix (Android) --- index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/index.js b/index.js index 0135fd8f7..2bdb93255 100644 --- a/index.js +++ b/index.js @@ -229,8 +229,14 @@ function fetch(...args:any):Promise { return fetchFile(options, method, url, headers, body) } + let promiseResolve; + let promiseReject; + // from remote HTTP(S) let promise = new Promise((resolve, reject) => { + promiseResolve = resolve; + promiseReject = reject; + let nativeMethodName = Array.isArray(body) ? 'fetchBlobForm' : 'fetchBlob' // on progress event listener @@ -371,6 +377,7 @@ function fetch(...args:any):Promise { subscriptionUpload.remove() stateEvent.remove() RNFetchBlob.cancelRequest(taskId, fn) + promiseReject(new Error("canceled")) } promise.taskId = taskId From 7420183e30b1d9bbf3de32d1eb1889e74a3f5e9d Mon Sep 17 00:00:00 2001 From: Alex Aphonin Date: Thu, 27 Jun 2019 21:13:54 +0300 Subject: [PATCH 113/182] Intent.FLAG_ACTIVITY_NEW_TASK added --- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index ac9ce5669..b3803d66a 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -119,7 +119,8 @@ public void actionViewIntent(String path, String mime, final Promise promise) { // Set flag to give temporary permission to external app to use FileProvider intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - + // All the activity to be opened outside of an activity + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Validate that the device can open the file PackageManager pm = getCurrentActivity().getPackageManager(); if (intent.resolveActivity(pm) != null) { From f836385b10f4d74691a5c4ff1fb4e8b51d9bd196 Mon Sep 17 00:00:00 2001 From: Sushant Gupta Date: Sun, 7 Jul 2019 15:44:59 +0530 Subject: [PATCH 114/182] Bug fix for download interruption promise rejection --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 16 +++++++++++++--- .../Response/RNFetchBlobFileResp.java | 4 ++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 369b9baaf..473455e94 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -531,16 +531,26 @@ private void done(Response resp) { } break; case FileStorage: + ResponseBody responseBody = resp.body(); + try { // In order to write response data to `destPath` we have to invoke this method. // It uses customized response body which is able to report download progress // and write response data to destination path. - resp.body().bytes(); + responseBody.bytes(); } catch (Exception ignored) { // ignored.printStackTrace(); } - this.destPath = this.destPath.replace("?append=true", ""); - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); + + RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; + + if(rnFetchBlobFileResp != null && rnFetchBlobFileResp.isDownloadComplete() == false){ + callback.invoke("RNFetchBlob failed. Download interrupted.", null); + } + else { + this.destPath = this.destPath.replace("?append=true", ""); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); + } break; default: try { diff --git a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java index e4f725777..18ba47981 100644 --- a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java +++ b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java @@ -69,6 +69,10 @@ public long contentLength() { return originalBody.contentLength(); } + public boolean isDownloadComplete() { + return bytesDownloaded == contentLength(); + } + @Override public BufferedSource source() { ProgressReportingSource countable = new ProgressReportingSource(); From 01f10cb100c47979a016db5ec632fffc823d0757 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Date: Mon, 8 Jul 2019 15:39:36 +0700 Subject: [PATCH 115/182] fix cocoa pod 0.60.0 --- rn-fetch-blob.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rn-fetch-blob.podspec b/rn-fetch-blob.podspec index cc7ce719c..af9644501 100644 --- a/rn-fetch-blob.podspec +++ b/rn-fetch-blob.podspec @@ -9,5 +9,5 @@ Pod::Spec.new do |s| s.author = 'Joltup' s.source_files = 'ios/**/*.{h,m}' s.platform = :ios, "8.0" - s.dependency 'React/Core' + s.dependency 'React' end From 0f6c3e3cc1c9c3c4b1640c8da42adffc3d620e90 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Date: Wed, 10 Jul 2019 18:04:31 +0700 Subject: [PATCH 116/182] - use dependency React-Core instead React - though It worked --- rn-fetch-blob.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rn-fetch-blob.podspec b/rn-fetch-blob.podspec index af9644501..2f3d95412 100644 --- a/rn-fetch-blob.podspec +++ b/rn-fetch-blob.podspec @@ -9,5 +9,5 @@ Pod::Spec.new do |s| s.author = 'Joltup' s.source_files = 'ios/**/*.{h,m}' s.platform = :ios, "8.0" - s.dependency 'React' + s.dependency 'React-Core' end From 6153af89bb0e608b5ab4c55b2a2800a7f5565a90 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sun, 14 Jul 2019 16:59:31 -0600 Subject: [PATCH 117/182] use android x file provider --- android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java b/android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java index 0d1fced4a..d48f75fb1 100644 --- a/android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java +++ b/android/src/main/java/com/RNFetchBlob/Utils/FileProvider.java @@ -1,4 +1,4 @@ package com.RNFetchBlob.Utils; -public class FileProvider extends android.support.v4.content.FileProvider { +public class FileProvider extends androidx.core.content.FileProvider { } From 4339ac35516adc91e9b6b6453846f5afafbf8fe2 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Sun, 14 Jul 2019 17:48:54 -0600 Subject: [PATCH 118/182] 0.10.16 --- package.json | 2 +- rn-fetch-blob.podspec | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 4cf032974..6162696c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.15", + "version": "0.10.16", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { diff --git a/rn-fetch-blob.podspec b/rn-fetch-blob.podspec index 2f3d95412..6956abea5 100644 --- a/rn-fetch-blob.podspec +++ b/rn-fetch-blob.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = "rn-fetch-blob" - s.version = "0.10.6" + s.version = "0.10.16" s.summary = "A project committed to make file acess and data transfer easier, effiecient for React Native developers." s.requires_arc = true s.license = 'MIT' s.homepage = 'n/a' - s.source = { :git => "https://github.com/joltup/rn-fetch-blob", :tag => 'v0.10.10'} + s.source = { :git => "https://github.com/joltup/rn-fetch-blob", :tag => 'v0.10.16'} s.author = 'Joltup' s.source_files = 'ios/**/*.{h,m}' s.platform = :ios, "8.0" From baf0398cf2636067b414a641c67183e67f95c9c8 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Tue, 16 Jul 2019 07:55:53 -0600 Subject: [PATCH 119/182] add version compatibility warning to README --- README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a8414f045..1d7ca3118 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,11 @@ -# New Releases -In order to publish new releases from this fork, we have renamed this project to -`rn-fetch-blob` and published to `https://www.npmjs.com/package/rn-fetch-blob`. - -**Note**: If upgrading from the original fork change all references in your project from `react-native-fetch-blob` to `rn-fetch-blob`. This includes `*.xcodeproj/project.pbxproj` and `android/**/*.gradle` depending on the platform used, failing to do so may cause build errors. - # rn-fetch-blob [![release](https://img.shields.io/github/release/joltup/rn-fetch-blob.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/rn-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/rn-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/rn-fetch-blob.svg?maxAge=2592000&style=flat-square)]() - A project committed to making file access and data transfer easier and more efficient for React Native developers. -> For Firebase Storage solution, please upgrade to the latest version for the best compatibility. + +# 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 From f13692ae23e33aff8218c5899319b20e620245fb Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Thu, 18 Jul 2019 19:31:43 -0600 Subject: [PATCH 120/182] convert to new react native config format --- package.json | 5 ----- react-native.config.js | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 react-native.config.js diff --git a/package.json b/package.json index 6162696c5..f9aa002be 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,6 @@ "filestream", "image header" ], - "rnpm": { - "commands": { - "prelink": "node ./node_modules/rn-fetch-blob/scripts/prelink.js" - } - }, "repository": { "url": "https://github.com/joltup/rn-fetch-blob.git" }, diff --git a/react-native.config.js b/react-native.config.js new file mode 100644 index 000000000..03c61b6ec --- /dev/null +++ b/react-native.config.js @@ -0,0 +1,7 @@ +module.exports = { + dependency: { + hooks: { + prelink: 'node ./node_modules/rn-fetch-blob/scripts/prelink.js', + }, + }, +}; From 880bdc0e9bf42929be1af949b13576ffed58902b Mon Sep 17 00:00:00 2001 From: Krzysztof Sakowski Date: Thu, 25 Jul 2019 16:34:53 +0200 Subject: [PATCH 121/182] Fix REAME.me anchor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d7ca3118..500a8d8f8 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ rn-fetch-blob version 0.10.16 is only compatible with react native 0.60 and up. * [Installation](#user-content-installation) * [HTTP Data Transfer](#user-content-http-data-transfer) * [Regular Request](#user-content-regular-request) - * [Download file](#user-content-download-example--fetch-files-that-needs-authorization-token) + * [Download file](#download-example-fetch-files-that-need-authorization-token) * [Upload file](#user-content-upload-example--dropbox-files-upload-api) * [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data) * [Upload/Download progress](#user-content-uploaddownload-progress) From e51bdd1530e97e04875fb2f678a17a646709639d Mon Sep 17 00:00:00 2001 From: Danh Nguyen Date: Tue, 30 Jul 2019 10:50:32 +0700 Subject: [PATCH 122/182] add FLAG_ACTIVITY_NEW_TASK --- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index ac9ce5669..d7befcf9e 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -119,6 +119,8 @@ public void actionViewIntent(String path, String mime, final Promise promise) { // Set flag to give temporary permission to external app to use FileProvider intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + // All the activity to be opened outside of an activity + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Validate that the device can open the file PackageManager pm = getCurrentActivity().getPackageManager(); From 95207a99bcb86d07f634450a1cb5a000345c8f13 Mon Sep 17 00:00:00 2001 From: Danh Nguyen Date: Tue, 30 Jul 2019 11:44:11 +0700 Subject: [PATCH 123/182] fix cannot import file from download folder in android --- .../com/RNFetchBlob/Utils/PathResolver.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java b/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java index de72ecaa1..c83fdbaf6 100644 --- a/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java +++ b/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java @@ -37,12 +37,25 @@ public static String getRealPathFromURI(final Context context, final Uri uri) { } // DownloadsProvider else if (isDownloadsDocument(uri)) { + try { + final String id = DocumentsContract.getDocumentId(uri); + //Starting with Android O, this "id" is not necessarily a long (row number), + //but might also be a "raw:/some/file/path" URL + if (id != null && id.startsWith("raw:/")) { + Uri rawuri = Uri.parse(id); + String path = rawuri.getPath(); + return path; + } + final Uri contentUri = ContentUris.withAppendedId( + Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - final String id = DocumentsContract.getDocumentId(uri); - final Uri contentUri = ContentUris.withAppendedId( - Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - - return getDataColumn(context, contentUri, null, null); + return getDataColumn(context, contentUri, null, null); + } + catch (Exception ex) { + //something went wrong, but android should still be able to handle the original uri by returning null here (see readFile(...)) + return null; + } + } // MediaProvider else if (isMediaDocument(uri)) { From aca905853f4bf121d751cfe8df068478497ec181 Mon Sep 17 00:00:00 2001 From: Ankit Makwana Date: Fri, 16 Aug 2019 16:51:05 +0530 Subject: [PATCH 124/182] Fix #170 - RNFetchBlob fs hash with md5 param fails if the file size is 0(blank) --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 101e8033a..34e4304fc 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -878,9 +878,11 @@ static void hash(String path, String algorithm, Promise promise) { FileInputStream inputStream = new FileInputStream(path); byte[] buffer = new byte[(int)file.length()]; - int read; - while ((read = inputStream.read(buffer)) != -1) { - md.update(buffer, 0, read); + if(file.length() != 0) { + int read; + while ((read = inputStream.read(buffer)) != -1) { + md.update(buffer, 0, read); + } } StringBuilder hexString = new StringBuilder(); From deb3588a36620e5efa9b1c2bc99ad4874c2e6ff8 Mon Sep 17 00:00:00 2001 From: nadav Date: Wed, 28 Aug 2019 11:32:58 +0300 Subject: [PATCH 125/182] Update RNFetchBlob.m Solved an issue where the rootNavigationController is not necessarily the currently displayed controller, which caused an error of: Warning: Attempt to present on whose view is not in the window hierarchy! --- ios/RNFetchBlob/RNFetchBlob.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index b4642d459..66069e1b6 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -622,7 +622,12 @@ - (NSDictionary *)constantsToExport - (UIViewController *) documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *) controller { UIWindow *window = [UIApplication sharedApplication].keyWindow; - return window.rootViewController; + UIViewController *currentlyPresentedView = [window.rootViewController presentedViewController]; + if (currentlyPresentedView == nil) + { + return window.rootViewController; + } + return currentlyPresentedView; } # pragma mark - check expired network events From cd4e023656c327815f9059490d3db9c345f85eee Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Tue, 3 Sep 2019 18:44:06 +0200 Subject: [PATCH 126/182] RNFetchBlobFS.writeFile(): ensure that files are closed properly in all cases and that stringToBytes() (which could potentially OOM) is called *before* the output file is opened --- .../java/com/RNFetchBlob/RNFetchBlobFS.java | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 101e8033a..aa145ff36 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -69,32 +69,45 @@ static void writeFile(String path, String encoding, String data, final boolean a } } - FileOutputStream fout = new FileOutputStream(f, append); // write data from a file if(encoding.equalsIgnoreCase(RNFetchBlobConst.DATA_ENCODE_URI)) { String normalizedData = normalizePath(data); File src = new File(normalizedData); if (!src.exists()) { promise.reject("ENOENT", "No such file '" + path + "' " + "('" + normalizedData + "')"); - fout.close(); return; } - FileInputStream fin = new FileInputStream(src); byte[] buffer = new byte [10240]; int read; written = 0; - while((read = fin.read(buffer)) > 0) { - fout.write(buffer, 0, read); - written += read; + FileInputStream fin = null; + FileOutputStream fout = null; + try { + fin = new FileInputStream(src); + fout = new FileOutputStream(f, append); + while ((read = fin.read(buffer)) > 0) { + fout.write(buffer, 0, read); + written += read; + } + } finally { + if (fin != null) { + fin.close(); + } + if (fout != null) { + fout.close(); + } } - fin.close(); } else { byte[] bytes = stringToBytes(data, encoding); - fout.write(bytes); - written = bytes.length; + FileOutputStream fout = new FileOutputStream(f, append); + try { + fout.write(bytes); + written = bytes.length; + } finally { + fout.close(); + } } - fout.close(); promise.resolve(written); } catch (FileNotFoundException e) { // 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 } FileOutputStream os = new FileOutputStream(f, append); - byte[] bytes = new byte[data.size()]; - for(int i=0;i Date: Wed, 11 Sep 2019 12:17:58 -0300 Subject: [PATCH 127/182] Create sync method to App Group dir --- fs.js | 14 ++++++++++++++ ios/RNFetchBlob/RNFetchBlob.m | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/fs.js b/fs.js index e61f44312..77bbe7a9d 100644 --- a/fs.js +++ b/fs.js @@ -135,6 +135,19 @@ function pathForAppGroup(groupName: string): Promise { return RNFetchBlob.pathForAppGroup(groupName) } +/** + * Returns the path for the app group synchronous. + * @param {string} groupName Name of app group + * @return {string} Path of App Group dir + */ +function syncPathAppGroup(groupName: string): string { + if (Platform.OS === 'ios') { + return RNFetchBlob.syncPathAppGroup(groupName); + } else { + return ''; + } +} + /** * Wrapper method of readStream. * @param {string} path Path of the file. @@ -402,6 +415,7 @@ export default { writeFile, appendFile, pathForAppGroup, + syncPathAppGroup, readFile, hash, exists, diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index b4642d459..034605dc1 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -228,6 +228,18 @@ - (NSDictionary *)constantsToExport } } +#pragma mark - fs.syncPathAppGroup +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(syncPathAppGroup:(NSString *)groupName) { + NSURL *pathUrl = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:groupName]; + NSString *path = [pathUrl path]; + + if(path) { + return path; + } else { + return @""; + } +} + #pragma mark - fs.exists RCT_EXPORT_METHOD(exists:(NSString *)path callback:(RCTResponseSenderBlock)callback) { [RNFetchBlobFS exists:path callback:callback]; From ee6b4cb449f785211797dc487614be5c01cde8f6 Mon Sep 17 00:00:00 2001 From: Matt Way Date: Fri, 13 Sep 2019 11:35:11 +1000 Subject: [PATCH 128/182] changed to chunk size instead of reading entire file --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 101e8033a..eefd57f68 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -876,11 +876,12 @@ static void hash(String path, String algorithm, Promise promise) { MessageDigest md = MessageDigest.getInstance(algorithms.get(algorithm)); FileInputStream inputStream = new FileInputStream(path); - byte[] buffer = new byte[(int)file.length()]; + int chunkSize = 4096 * 256; // 1Mb + byte[] buffer = new byte[chunkSize]; - int read; - while ((read = inputStream.read(buffer)) != -1) { - md.update(buffer, 0, read); + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + md.update(buffer, 0, bytesRead); } StringBuilder hexString = new StringBuilder(); From 5d477d91185e912f87f8b0ac66ca0c697fb46287 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Wed, 25 Sep 2019 22:09:57 -0600 Subject: [PATCH 129/182] 0.11.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f9aa002be..23eeda0fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.10.16", + "version": "0.11.0", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 7b8be92b27acf4da77edaf4005f8499a1f08f88b Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Wed, 25 Sep 2019 22:20:36 -0600 Subject: [PATCH 130/182] use package.json for versioning --- rn-fetch-blob.podspec | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rn-fetch-blob.podspec b/rn-fetch-blob.podspec index 6956abea5..4edbd5cc9 100644 --- a/rn-fetch-blob.podspec +++ b/rn-fetch-blob.podspec @@ -1,11 +1,14 @@ +require "json" +package = JSON.parse(File.read('package.json')) + Pod::Spec.new do |s| - s.name = "rn-fetch-blob" - s.version = "0.10.16" - s.summary = "A project committed to make file acess and data transfer easier, effiecient for React Native developers." + s.name = package['name'] + s.version = package['version'] + s.summary = package['description'] s.requires_arc = true s.license = 'MIT' s.homepage = 'n/a' - s.source = { :git => "https://github.com/joltup/rn-fetch-blob", :tag => 'v0.10.16'} + s.source = { :git => "https://github.com/joltup/rn-fetch-blob" } s.author = 'Joltup' s.source_files = 'ios/**/*.{h,m}' s.platform = :ios, "8.0" From fb6095220386c40a11bc74382c011bfad2673a78 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Wed, 25 Sep 2019 22:20:58 -0600 Subject: [PATCH 131/182] 0.11.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23eeda0fc..aa24c2cb8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.11.0", + "version": "0.11.1", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 00c12e32e1e110fdc006e1a885f7bb185f19acf9 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Thu, 26 Sep 2019 21:26:53 -0600 Subject: [PATCH 132/182] Revert "Merge pull request #353 from thinkproductivity/mjmasn-patch-1" This reverts commit 6bbebd3429f733236eae9a273bae3bcff5c0e69b, reversing changes made to 90ce0c401ab6c3d9667f6311e04f57a499f3864d. --- .../java/com/RNFetchBlob/RNFetchBlobFS.java | 4 ++++ .../java/com/RNFetchBlob/RNFetchBlobReq.java | 24 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index abc17f7bc..aa8241dff 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -21,7 +21,9 @@ import com.facebook.react.modules.core.DeviceEventManagerModule; import java.io.*; +import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; import java.security.MessageDigest; import java.util.ArrayList; import java.util.HashMap; @@ -339,7 +341,9 @@ else if(resolved == null) { boolean error = false; if (encoding.equalsIgnoreCase("utf8")) { + CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); while ((cursor = fs.read(buffer)) != -1) { + encoder.encode(ByteBuffer.wrap(buffer).asCharBuffer()); String chunk = new String(buffer, 0, cursor); emitStreamEvent(streamId, "data", chunk); if(tick > 0) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index a894aec93..b73907950 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -36,6 +36,10 @@ import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; import java.security.KeyStore; import java.util.ArrayList; import java.util.Arrays; @@ -498,12 +502,28 @@ private void done(Response resp) { // encoding will somehow break the UTF8 string format, to encode UTF8 // string correctly, we should do URL encoding before BASE64. byte[] b = resp.body().bytes(); + CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); if(responseFormat == ResponseFormat.BASE64) { callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP)); return; } - String utf8 = new String(b); - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, utf8); + try { + encoder.encode(ByteBuffer.wrap(b).asCharBuffer()); + // if the data contains invalid characters the following lines will be + // skipped. + String utf8 = new String(b); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, utf8); + } + // This usually mean the data is contains invalid unicode characters, it's + // binary data + catch(CharacterCodingException ignored) { + if(responseFormat == ResponseFormat.UTF8) { + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, ""); + } + else { + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP)); + } + } } } catch (IOException e) { callback.invoke("RNFetchBlob failed to encode response data to BASE64 string.", null); From 0e2c40e69b47080324a69a28354679a8f2eec497 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Thu, 26 Sep 2019 21:28:12 -0600 Subject: [PATCH 133/182] Revert "Merge pull request #396 from sonudoo/download-interruption-android-bugfix" This reverts commit 4305ef817581314ad0ecf4b64981988c8171707d, reversing changes made to d35fb734243437c1ac33cefc7d755add64ed66fe. --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 16 +++------------- .../Response/RNFetchBlobFileResp.java | 4 ---- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index b73907950..505f6e0e0 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -530,26 +530,16 @@ private void done(Response resp) { } break; case FileStorage: - ResponseBody responseBody = resp.body(); - try { // In order to write response data to `destPath` we have to invoke this method. // It uses customized response body which is able to report download progress // and write response data to destination path. - responseBody.bytes(); + resp.body().bytes(); } catch (Exception ignored) { // ignored.printStackTrace(); } - - RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; - - if(rnFetchBlobFileResp != null && rnFetchBlobFileResp.isDownloadComplete() == false){ - callback.invoke("RNFetchBlob failed. Download interrupted.", null); - } - else { - this.destPath = this.destPath.replace("?append=true", ""); - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); - } + this.destPath = this.destPath.replace("?append=true", ""); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); break; default: try { diff --git a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java index 8a7447ee0..7a6acf8e5 100644 --- a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java +++ b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java @@ -68,10 +68,6 @@ public long contentLength() { return originalBody.contentLength(); } - public boolean isDownloadComplete() { - return bytesDownloaded == contentLength(); - } - @Override public BufferedSource source() { ProgressReportingSource countable = new ProgressReportingSource(); From 9931f1e08f40b58f9e5c87cfb2deb889dac64706 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Thu, 26 Sep 2019 21:29:45 -0600 Subject: [PATCH 134/182] 0.11.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aa24c2cb8..6ecb17afd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.11.1", + "version": "0.11.2", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From d03a502bad832bf1ffe6f33cafffe4987b86cda5 Mon Sep 17 00:00:00 2001 From: Sushant Gupta Date: Mon, 30 Sep 2019 17:36:44 +0530 Subject: [PATCH 135/182] Bug fix for download interruption promise rejection --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 16 +++++-- .../Response/RNFetchBlobFileResp.java | 48 ++++++++++++++++--- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 505f6e0e0..b73907950 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -530,16 +530,26 @@ private void done(Response resp) { } break; case FileStorage: + ResponseBody responseBody = resp.body(); + try { // In order to write response data to `destPath` we have to invoke this method. // It uses customized response body which is able to report download progress // and write response data to destination path. - resp.body().bytes(); + responseBody.bytes(); } catch (Exception ignored) { // ignored.printStackTrace(); } - this.destPath = this.destPath.replace("?append=true", ""); - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); + + RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; + + if(rnFetchBlobFileResp != null && rnFetchBlobFileResp.isDownloadComplete() == false){ + callback.invoke("RNFetchBlob failed. Download interrupted.", null); + } + else { + this.destPath = this.destPath.replace("?append=true", ""); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); + } break; default: try { diff --git a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java index 7a6acf8e5..2470eef61 100644 --- a/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java +++ b/android/src/main/java/com/RNFetchBlob/Response/RNFetchBlobFileResp.java @@ -33,6 +33,7 @@ public class RNFetchBlobFileResp extends ResponseBody { long bytesDownloaded = 0; ReactApplicationContext rctContext; FileOutputStream ofStream; + boolean isEndMarkerReceived; public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseBody body, String path, boolean overwrite) throws IOException { super(); @@ -41,6 +42,7 @@ public RNFetchBlobFileResp(ReactApplicationContext ctx, String taskId, ResponseB this.originalBody = body; assert path != null; this.mPath = path; + this.isEndMarkerReceived = false; if (path != null) { boolean appendToExistingFile = !overwrite; path = path.replace("?append=true", ""); @@ -68,6 +70,11 @@ public long contentLength() { return originalBody.contentLength(); } + public boolean isDownloadComplete() { + return (bytesDownloaded == contentLength()) // Case of non-chunked downloads + || (contentLength() == -1 && isEndMarkerReceived); // Case of chunked downloads + } + @Override public BufferedSource source() { ProgressReportingSource countable = new ProgressReportingSource(); @@ -83,22 +90,49 @@ public long read(@NonNull Buffer sink, long byteCount) throws IOException { bytesDownloaded += read > 0 ? read : 0; if (read > 0) { ofStream.write(bytes, 0, (int) read); + } else if (contentLength() == -1 && read == -1) { + // End marker has been received for chunked download + isEndMarkerReceived = true; } RNFetchBlobProgressConfig reportConfig = RNFetchBlobReq.getReportProgress(mTaskId); - if (reportConfig != null && contentLength() != 0 &&reportConfig.shouldReport(bytesDownloaded / contentLength())) { - WritableMap args = Arguments.createMap(); - args.putString("taskId", mTaskId); - args.putString("written", String.valueOf(bytesDownloaded)); - args.putString("total", String.valueOf(contentLength())); - rctContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(RNFetchBlobConst.EVENT_PROGRESS, args); + + if (contentLength() != 0) { + + // For non-chunked download, progress is received / total + // For chunked download, progress can be either 0 (started) or 1 (ended) + float progress = (contentLength() != -1) ? bytesDownloaded / contentLength() : ( ( isEndMarkerReceived ) ? 1 : 0 ); + + if (reportConfig != null && reportConfig.shouldReport(progress /* progress */)) { + if (contentLength() != -1) { + // For non-chunked downloads + reportProgress(mTaskId, bytesDownloaded, contentLength()); + } else { + // For chunked downloads + if (!isEndMarkerReceived) { + reportProgress(mTaskId, 0, contentLength()); + } else{ + reportProgress(mTaskId, bytesDownloaded, bytesDownloaded); + } + } + } + } + return read; } catch(Exception ex) { return -1; } } + private void reportProgress(String taskId, long bytesDownloaded, long contentLength) { + WritableMap args = Arguments.createMap(); + args.putString("taskId", taskId); + args.putString("written", String.valueOf(bytesDownloaded)); + args.putString("total", String.valueOf(contentLength)); + rctContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(RNFetchBlobConst.EVENT_PROGRESS, args); + } + @Override public Timeout timeout() { return null; From 7ee256f3955d803dec9b39ffc2f7353b298b77a9 Mon Sep 17 00:00:00 2001 From: Alpha Date: Wed, 2 Oct 2019 14:55:31 -0400 Subject: [PATCH 136/182] Fix errors in TypeScript typings --- index.d.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index b74710926..540a99c81 100644 --- a/index.d.ts +++ b/index.d.ts @@ -356,7 +356,7 @@ export interface FS { */ writeFile(path: string, data: string | number[], encoding?: Encoding): Promise; - appendFile(path: string, data: string | number[], encoding?: Encoding): Promise; + appendFile(path: string, data: string | number[], encoding?: Encoding | "uri"): Promise; /** * Wrapper method of readStream. @@ -399,6 +399,7 @@ export interface Dirs { DocumentDir: string; CacheDir: string; PictureDir: string; + LibraryDir: string; MusicDir: string; MovieDir: string; DownloadDir: string; @@ -432,7 +433,7 @@ export interface RNFetchBlobReadStream { onEnd(fn: () => void): void; } -type Encoding = "utf8" | "ascii" | "base64"; +export type Encoding = "utf8" | "ascii" | "base64"; /* tslint:disable-next-line interface-name*/ export interface IOSApi { @@ -606,11 +607,13 @@ export interface AddAndroidDownloads { export interface RNFetchBlobResponseInfo { taskId: string; - state: number; + state: string; headers: any; + redirects: string[]; status: number; respType: "text" | "blob" | "" | "json"; rnfbEncode: "path" | "base64" | "ascii" | "utf8"; + timeout: boolean; } export interface RNFetchBlobStream { @@ -623,8 +626,8 @@ export declare class RNFetchBlobFile { } export declare class RNFetchBlobStat { - lastModified: string; - size: string; + lastModified: number; + size: number; type: "directory" | "file"; path: string; filename: string; From 66692b6e9b65a23d15439365dd7e45f372086b65 Mon Sep 17 00:00:00 2001 From: Juliette Rapala Date: Thu, 10 Oct 2019 11:07:31 -0500 Subject: [PATCH 137/182] Fix #458 - Remove duped FLAG_ACTIVITY_NEW_TASK --- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 42e9f6e4a..602d51d33 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -121,8 +121,6 @@ public void actionViewIntent(String path, String mime, final Promise promise) { // All the activity to be opened outside of an activity intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - // All the activity to be opened outside of an activity - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Validate that the device can open the file PackageManager pm = getCurrentActivity().getPackageManager(); if (intent.resolveActivity(pm) != null) { From dd831a9c4eedefd8f2edd3d0b3d268390572adac Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Thu, 17 Oct 2019 07:28:53 -0300 Subject: [PATCH 138/182] add missing methods to android static export in index.d.ts --- index.d.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/index.d.ts b/index.d.ts index 540a99c81..81ef7e29d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -451,6 +451,33 @@ export interface IOSApi { openDocument(path: string): void; } +export interface AndroidDownloadOption { + /** + * Title string to be displayed when the file added to Downloads app. + */ + title: string + + /** + * File description to be displayed when the file added to Downloads app. + */ + description: string + + /** + * MIME string of the file. + */ + mime: string + + /** + * URI string of the file. + */ + path: string + + /** + * Boolean value that determines if notification will be displayed. + */ + showNotification: boolean +} + export interface AndroidApi { /** * When sending an ACTION_VIEW intent with given file path and MIME type, system will try to open an @@ -459,6 +486,25 @@ export interface AndroidApi { * @param mime Basically system will open an app according to this MIME type. */ actionViewIntent(path: string, mime: string): Promise; + + /** + * + * This method brings up OS default file picker and resolves a file URI when the user selected a file. + * However, it does not resolve or reject when user dismiss the file picker via pressing hardware back button, + * but you can still handle this behavior via AppState. + * @param mime MIME type filter, only the files matches the MIME will be shown. + */ + getContentIntent(mime: string): Promise; + + /** + * Using this function to add an existing file to Downloads app. + * @param options An object that for setting the title, description, mime, and notification of the item. + */ + addCompleteDownload(options: AndroidDownloadOption): Promise; + + getSDCardDir(): Promise; + + getSDCardApplicationDir(): Promise; } type Methods = "POST" | "GET" | "DELETE" | "PUT" | "post" | "get" | "delete" | "put"; From 61af1c7ac69fc514f364dd7ede24a65203c8a73a Mon Sep 17 00:00:00 2001 From: Etienne Moulin Date: Tue, 22 Oct 2019 16:31:58 -0400 Subject: [PATCH 139/182] Use non deprecated version of the method sslSocketFactory - It happens to fix a bug when using conscrypt --- .../com/RNFetchBlob/RNFetchBlobUtils.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobUtils.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobUtils.java index 6dbcbe7c7..ab35fdd31 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobUtils.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobUtils.java @@ -56,22 +56,21 @@ public static void emitWarningEvent(String data) { public static OkHttpClient.Builder getUnsafeOkHttpClient(OkHttpClient client) { try { // Create a trust manager that does not validate certificate chains - final TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - @Override - public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { - } - - @Override - public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { - } - - @Override - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return new java.security.cert.X509Certificate[]{}; - } - } + final X509TrustManager x509TrustManager = new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } }; + final TrustManager[] trustAllCerts = new TrustManager[]{ x509TrustManager }; // Install the all-trusting trust manager final SSLContext sslContext = SSLContext.getInstance("SSL"); @@ -80,7 +79,7 @@ public java.security.cert.X509Certificate[] getAcceptedIssuers() { final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); OkHttpClient.Builder builder = client.newBuilder(); - builder.sslSocketFactory(sslSocketFactory); + builder.sslSocketFactory(sslSocketFactory, x509TrustManager); builder.hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { From bfbfdfcb9664c88da3c65a7926af0e0c149eb37f Mon Sep 17 00:00:00 2001 From: sadafk831 Date: Wed, 30 Oct 2019 21:43:52 +0530 Subject: [PATCH 140/182] fixing the issue of translating the non english language data --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index b73907950..8c869e701 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -514,11 +514,13 @@ private void done(Response resp) { String utf8 = new String(b); callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, utf8); } - // This usually mean the data is contains invalid unicode characters, it's - // binary data + // This usually mean the data is contains invalid unicode characters but still valid data, + // it's binary data, so send it as a normal string catch(CharacterCodingException ignored) { + if(responseFormat == ResponseFormat.UTF8) { - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, ""); + String utf8 = new String(b); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_UTF8, utf8); } else { callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP)); From bffd9e400aca59f97a2661d480aacaf5fecfd292 Mon Sep 17 00:00:00 2001 From: Tsukasa Setoguchi Date: Thu, 31 Oct 2019 16:13:57 +0900 Subject: [PATCH 141/182] Fix comment: default timeout from 30000ms to 60000ms --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 1be30833f..9e46bc24e 100644 --- a/index.js +++ b/index.js @@ -104,7 +104,7 @@ function wrap(path:string):string { * activity takes place ) * If it doesn't exist, the file is downloaded as usual * @property {number} timeout - * Request timeout in millionseconds, by default it's 30000ms. + * Request timeout in millionseconds, by default it's 60000ms. * * @return {function} This method returns a `fetch` method instance. */ From 7f8ec949f2c39cbd3a7f6aa4a5b2dcb106cdcf83 Mon Sep 17 00:00:00 2001 From: nadav Date: Tue, 19 Nov 2019 13:17:35 +0200 Subject: [PATCH 142/182] Update RNFetchBlob.java Android to throw an exception when there's no suitable app that can open the file --- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 6b446baaa..e581b193d 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -120,11 +120,8 @@ public void actionViewIntent(String path, String mime, final Promise promise) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // All the activity to be opened outside of an activity intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - // Validate that the device can open the file - PackageManager pm = getCurrentActivity().getPackageManager(); - if (intent.resolveActivity(pm) != null) { - this.getReactApplicationContext().startActivity(intent); - } + // Don't validate that the intent can run, instead, let it throw an exception if it can't. + this.getReactApplicationContext().startActivity(intent); } else { Intent intent = new Intent(Intent.ACTION_VIEW) @@ -410,4 +407,4 @@ public void getSDCardDir(Promise promise) { public void getSDCardApplicationDir(Promise promise) { RNFetchBlobFS.getSDCardApplicationDir(this.getReactApplicationContext(), promise); } -} \ No newline at end of file +} From 3bbe72daac06b4af75230918bbc78e91a1354f8b Mon Sep 17 00:00:00 2001 From: Cristiano Coelho Date: Thu, 28 Nov 2019 17:59:17 -0300 Subject: [PATCH 143/182] wifi only option, and missing typings. --- README.md | 46 +++++++++++---- .../com/RNFetchBlob/RNFetchBlobConfig.java | 2 + .../java/com/RNFetchBlob/RNFetchBlobReq.java | 59 +++++++++++++++---- index.d.ts | 10 ++++ index.js | 6 ++ index.js.flow | 4 +- ios/RNFetchBlobConst.h | 1 + ios/RNFetchBlobConst.m | 1 + ios/RNFetchBlobRequest.m | 4 ++ types.js | 5 +- 10 files changed, 112 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f2d547667..b5ca84c45 100644 --- a/README.md +++ b/README.md @@ -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. @@ -116,8 +116,8 @@ If you're going to access external storage (say, SD card storage) for `Android 5 -+ -+ ++ ++ + ... @@ -129,10 +129,18 @@ Also, if you're going to use `Android Download Manager` you have to add this to -+ ++ ``` +If you are going to use the `wifiOnly` flag, you need to add this to `AndroidManifest.xml` + +```diff ++ + ... + +``` + **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). @@ -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`. @@ -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() @@ -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()) @@ -648,7 +656,7 @@ RNFetchBlob.fs.readStream( ifstream.onError((err) => { console.log('oops', err) }) - ifstream.onEnd(() => { + ifstream.onEnd(() => { { // set session of a response res.session('foo') - }) + }) RNFetchblob.config({ // 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 .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') @@ -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. diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java index a5c68b689..8ac9e7a85 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java @@ -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; @@ -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"); } diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index b73907950..197477a0f 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -9,6 +9,9 @@ import android.net.Uri; import android.os.Build; import androidx.annotation.NonNull; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.ConnectivityManager; import android.util.Base64; import com.RNFetchBlob.Response.RNFetchBlobDefaultResp; @@ -36,6 +39,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; @@ -231,6 +235,45 @@ 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){ + continue; + } + + // netinfo is deprecated + //if (netInfo.getType() == ConnectivityManager.TYPE_WIFI && netInfo.getState() == NetworkInfo.State.CONNECTED) { + 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)); @@ -530,26 +573,16 @@ private void done(Response resp) { } break; case FileStorage: - ResponseBody responseBody = resp.body(); - try { // In order to write response data to `destPath` we have to invoke this method. // It uses customized response body which is able to report download progress // and write response data to destination path. - responseBody.bytes(); + resp.body().bytes(); } catch (Exception ignored) { // ignored.printStackTrace(); } - - RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; - - if(rnFetchBlobFileResp != null && rnFetchBlobFileResp.isDownloadComplete() == false){ - callback.invoke("RNFetchBlob failed. Download interrupted.", null); - } - else { - this.destPath = this.destPath.replace("?append=true", ""); - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); - } + this.destPath = this.destPath.replace("?append=true", ""); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); break; default: try { diff --git a/index.d.ts b/index.d.ts index 540a99c81..972f8e609 100644 --- a/index.d.ts +++ b/index.d.ts @@ -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}. diff --git a/index.js b/index.js index 1be30833f..2a36ba75b 100644 --- a/index.js +++ b/index.js @@ -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 30000ms. + * @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. */ diff --git a/index.js.flow b/index.js.flow index ecfd50a2d..03666e569 100644 --- a/index.js.flow +++ b/index.js.flow @@ -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}, diff --git a/ios/RNFetchBlobConst.h b/ios/RNFetchBlobConst.h index 6347b7a45..7d09c3a74 100644 --- a/ios/RNFetchBlobConst.h +++ b/ios/RNFetchBlobConst.h @@ -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; diff --git a/ios/RNFetchBlobConst.m b/ios/RNFetchBlobConst.m index bc9b793a5..1376d692e 100644 --- a/ios/RNFetchBlobConst.m +++ b/ios/RNFetchBlobConst.m @@ -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"; diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index a56cc92d0..7bb0ddde5 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -124,6 +124,10 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options defaultConfigObject.timeoutIntervalForRequest = timeout/1000; } + if([options valueForKey:CONFIG_WIFI_ONLY] != nil && ![options[CONFIG_WIFI_ONLY] boolValue]){ + [defaultConfigObject setAllowsCellularAccess:NO]; + } + defaultConfigObject.HTTPMaximumConnectionsPerHost = 10; session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; diff --git a/types.js b/types.js index f2f03ccd1..da256af61 100644 --- a/types.js +++ b/types.js @@ -5,7 +5,10 @@ type RNFetchBlobConfig = { appendExt : string, session : string, addAndroidDownloads : any, - indicator : bool + indicator : bool, + followRedirect : bool, + trusty : bool, + wifiOnly : bool }; type RNFetchBlobNative = { From d7dd38f9a990c7ce61ad0352958bc3a7241aec08 Mon Sep 17 00:00:00 2001 From: Bhavik Patel Date: Tue, 10 Dec 2019 18:49:39 -0500 Subject: [PATCH 144/182] Check if addAndroidDownloads map has notification key before consuming --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 505f6e0e0..aeacb6b8b 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -160,7 +160,7 @@ public void run() { if (options.addAndroidDownloads.getBoolean("useDownloadManager")) { Uri uri = Uri.parse(url); DownloadManager.Request req = new DownloadManager.Request(uri); - if(options.addAndroidDownloads.getBoolean("notification")) { + if(options.addAndroidDownloads.hasKey("notification") && options.addAndroidDownloads.getBoolean("notification")) { req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); } else { req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); From 52aa5ecd7a4d9534faef75aaeff267584f56c5c3 Mon Sep 17 00:00:00 2001 From: Cristiano Coelho Date: Tue, 10 Dec 2019 23:20:47 -0300 Subject: [PATCH 145/182] do not use P2P Wifi connections. Fixes issue on samsung --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 197477a0f..6a9ebf599 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -252,8 +252,11 @@ else if(this.options.fileCache) continue; } - // netinfo is deprecated - //if (netInfo.getType() == ConnectivityManager.TYPE_WIFI && netInfo.getState() == NetworkInfo.State.CONNECTED) { + // Don't use P2P Wi-Fi on recent samsung devices + if(caps.hasTransport(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)){ + continue; + } + if(caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){ clientBuilder.proxy(Proxy.NO_PROXY); clientBuilder.socketFactory(network.getSocketFactory()); From 99a81e5ec35bc392879a5babaed26289f1a9065a Mon Sep 17 00:00:00 2001 From: Cristiano Coelho Date: Wed, 11 Dec 2019 01:38:43 -0300 Subject: [PATCH 146/182] take 2 at samsung issues: ensure network is connected --- .../src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 6a9ebf599..bad184c62 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -10,6 +10,7 @@ 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; @@ -246,14 +247,15 @@ else if(this.options.fileCache) Network[] networks = connectivityManager.getAllNetworks(); for (Network network : networks) { - //NetworkInfo netInfo = connectivityManager.getNetworkInfo(network); + + NetworkInfo netInfo = connectivityManager.getNetworkInfo(network); NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(network); - if(caps == null){ + + if(caps == null || netInfo == null){ continue; } - // Don't use P2P Wi-Fi on recent samsung devices - if(caps.hasTransport(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)){ + if(!netInfo.isConnected()){ continue; } From 3e3d36ea1ca3318938ccb30f5e5f308d5f409f6d Mon Sep 17 00:00:00 2001 From: Cristiano Coelho Date: Thu, 12 Dec 2019 10:56:37 -0300 Subject: [PATCH 147/182] comment warning, too noisy on timeouts. --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index bad184c62..d7de9627c 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -426,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) { } @@ -721,7 +721,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 From 8ee728e6c14dbc6a7b109e8afedc50711b497dd1 Mon Sep 17 00:00:00 2001 From: Cristiano Coelho Date: Thu, 12 Dec 2019 11:26:32 -0300 Subject: [PATCH 148/182] undo these changes that were carried over from outdated master --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index d7de9627c..e6611c3a4 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -578,16 +578,27 @@ private void done(Response resp) { } break; case FileStorage: + ResponseBody responseBody = resp.body(); + try { // In order to write response data to `destPath` we have to invoke this method. // It uses customized response body which is able to report download progress // and write response data to destination path. - resp.body().bytes(); + responseBody.bytes(); } catch (Exception ignored) { // ignored.printStackTrace(); } - this.destPath = this.destPath.replace("?append=true", ""); - callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); + + RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; + + if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){ + callback.invoke("RNFetchBlob failed. Download interrupted.", null); + } + else { + this.destPath = this.destPath.replace("?append=true", ""); + callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath); + } + break; default: try { From 92a46a2ec1fb4f1264bd029f72582f6a3a5f35e9 Mon Sep 17 00:00:00 2001 From: Cristiano Coelho Date: Thu, 12 Dec 2019 12:00:05 -0300 Subject: [PATCH 149/182] Use a friendlier error for download interrupts. Interrupts are normal, and this error ends up directly on the UI --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index e6611c3a4..1fe0145fd 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -592,7 +592,7 @@ private void done(Response resp) { RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){ - callback.invoke("RNFetchBlob failed. Download interrupted.", null); + callback.invoke("Download interrupted.", null); } else { this.destPath = this.destPath.replace("?append=true", ""); From f2ac3e0b3bef57f6163e3efbb91a25d7423864d0 Mon Sep 17 00:00:00 2001 From: Cristiano Coelho Date: Thu, 12 Dec 2019 14:59:52 -0300 Subject: [PATCH 150/182] make request timeout consistent with iOS, do not mess with ios indicator if not requested to --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 2 +- ios/RNFetchBlobRequest.m | 127 +++++++++--------- 2 files changed, 66 insertions(+), 63 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 1fe0145fd..a431c697c 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -462,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); diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index 7bb0ddde5..cdbe6b1e5 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -56,7 +56,7 @@ - (NSString *)md5:(NSString *)input { const char* str = [input UTF8String]; unsigned char result[CC_MD5_DIGEST_LENGTH]; CC_MD5(str, (CC_LONG)strlen(str), result); - + NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; for (int i = 0; i 0) { defaultConfigObject.timeoutIntervalForRequest = timeout/1000; } - + if([options valueForKey:CONFIG_WIFI_ONLY] != nil && ![options[CONFIG_WIFI_ONLY] boolValue]){ [defaultConfigObject setAllowsCellularAccess:NO]; } - + defaultConfigObject.HTTPMaximumConnectionsPerHost = 10; session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue]; - + if (path || [self.options valueForKey:CONFIG_USE_TEMP]) { respFile = YES; - + NSString* cacheKey = taskId; if (key) { cacheKey = [self md5:key]; - + if (!cacheKey) { cacheKey = taskId; } - + destPath = [RNFetchBlobFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]]; - + if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) { callback(@[[NSNull null], RESP_TYPE_PATH, destPath]); - + return; } } - + if (path) { destPath = path; } else { @@ -160,10 +160,10 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options respData = [[NSMutableData alloc] init]; respFile = NO; } - + self.task = [session dataTaskWithRequest:req]; [self.task resume]; - + // network status indicator if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) { dispatch_async(dispatch_get_main_queue(), ^{ @@ -187,17 +187,17 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { expectedBytes = [response expectedContentLength]; - + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; NSString * respType = @""; respStatus = statusCode; - + if ([response respondsToSelector:@selector(allHeaderFields)]) { NSDictionary *headers = [httpResponse allHeaderFields]; NSString * respCType = [[RNFetchBlobReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString]; - + if (self.isServerPush) { if (partBuffer) { [self.bridge.eventDispatcher @@ -208,7 +208,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } ]; } - + partBuffer = [[NSMutableData alloc] init]; completionHandler(NSURLSessionResponseAllow); @@ -216,11 +216,11 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } else { self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; } - + if(respCType) { NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE]; - + if ([respCType RNFBContainsString:@"text/"]) { respType = @"text"; } else if ([respCType RNFBContainsString:@"application/json"]) { @@ -236,7 +236,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } } else { respType = @"blob"; - + // for XMLHttpRequest, switch response data handling strategy automatically if ([options valueForKey:@"auto"]) { respFile = YES; @@ -246,7 +246,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } else { respType = @"text"; } - + #pragma mark - handling cookies // # 153 get cookies if (response.URL) { @@ -256,7 +256,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil]; } } - + [self.bridge.eventDispatcher sendDeviceEventWithName: EVENT_STATE_CHANGE body:@{ @@ -272,33 +272,33 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat } else { NSLog(@"oops"); } - + if (respFile) { @try{ NSFileManager * fm = [NSFileManager defaultManager]; NSString * folder = [destPath stringByDeletingLastPathComponent]; - + if (![fm fileExistsAtPath:folder]) { [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil]; } - + // if not set overwrite in options, defaults to TRUE BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue]; BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"]; - + appendToExistingFile = !overwrite; - + // For solving #141 append response data if the file already exists // base on PR#139 @kejinliang if (appendToExistingFile) { destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""]; } - + if (![fm fileExistsAtPath:destPath]) { [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil]; } - + writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile]; [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; [writeStream open]; @@ -308,7 +308,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat NSLog(@"write file error"); } } - + completionHandler(NSURLSessionResponseAllow); } @@ -320,30 +320,30 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat if (self.isServerPush) { [partBuffer appendData:data]; - + return ; } - + NSNumber * received = [NSNumber numberWithLong:[data length]]; receivedBytes += [received longValue]; NSString * chunkString = @""; - + if (isIncrement) { chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } - + if (respFile) { [writeStream write:[data bytes] maxLength:[data length]]; } else { [respData appendData:data]; } - + if (expectedBytes == 0) { return; } - + NSNumber * now =[NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)]; - + if ([self.progressConfig shouldReport:now]) { [self.bridge.eventDispatcher sendDeviceEventWithName:EVENT_PROGRESS @@ -367,16 +367,19 @@ - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - + self.error = error; NSString * errMsg; NSString * respStr; NSString * rnfbRespType; - - dispatch_async(dispatch_get_main_queue(), ^{ - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - }); - + + // only run this if we were requested to change it + if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + }); + } + if (error) { if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) { errMsg = @"task cancelled"; @@ -384,7 +387,7 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom errMsg = [error localizedDescription]; } } - + if (respFile) { [writeStream close]; rnfbRespType = RESP_TYPE_PATH; @@ -395,7 +398,7 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom // if it turns out not to be `nil` that means the response data contains valid UTF8 string, // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding. NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding]; - + if (responseFormat == BASE64) { rnfbRespType = RESP_TYPE_BASE64; respStr = [respData base64EncodedStringWithOptions:0]; @@ -412,18 +415,18 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCom } } } - - + + callback(@[ errMsg ?: [NSNull null], rnfbRespType ?: @"", respStr ?: [NSNull null] ]); - + respData = nil; receivedBytes = 0; [session finishTasksAndInvalidate]; - + } // upload progress handler @@ -432,7 +435,7 @@ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSen if (totalBytesExpectedToWrite == 0) { return; } - + NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)]; if ([self.uploadProgressConfig shouldReport:now]) { @@ -465,12 +468,12 @@ - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)sessio - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler { - + if (followRedirect) { if (request.URL) { [redirects addObject:[request.URL absoluteString]]; } - + completionHandler(request); } else { completionHandler(nil); From 6e50a4e1d7f8141138f34f097db05d2ecec03496 Mon Sep 17 00:00:00 2001 From: ihavenoface5 Date: Tue, 17 Dec 2019 11:26:12 -0700 Subject: [PATCH 151/182] added null check to path before creating a File --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index b0dd577d0..298b92b03 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -666,9 +666,12 @@ static void exists(String path, Callback callback) { } else { path = normalizePath(path); - boolean exist = new File(path).exists(); - boolean isDir = new File(path).isDirectory(); - callback.invoke(exist, isDir); + if (path != null) { + boolean exist = new File(path).exists(); + boolean isDir = new File(path).isDirectory(); + callback.invoke(exist, isDir); + } + callback.invoke(false, false); } } From b8e0dff388f1d8ce5a03db04740f9fb70b3598df Mon Sep 17 00:00:00 2001 From: ihavenoface5 Date: Tue, 17 Dec 2019 14:13:08 -0700 Subject: [PATCH 152/182] Update RNFetchBlobFS.java --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 298b92b03..34ce8296f 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -416,7 +416,7 @@ void writeStream(String path, String encoding, boolean append, Callback callback File dest = new File(path); File dir = dest.getParentFile(); - if(!dest.exists()) { + if(!dest.)()) { if(dir != null && !dir.exists()) { if (!dir.mkdirs()) { callback.invoke("ENOTDIR", "Failed to create parent directory of '" + path + "'"); @@ -671,7 +671,9 @@ static void exists(String path, Callback callback) { boolean isDir = new File(path).isDirectory(); callback.invoke(exist, isDir); } - callback.invoke(false, false); + else { + callback.invoke(false, false); + } } } From 2d66cbfc7feef2902da0b1d96baf57632b01f1c7 Mon Sep 17 00:00:00 2001 From: ihavenoface5 Date: Tue, 17 Dec 2019 14:22:51 -0700 Subject: [PATCH 153/182] Update RNFetchBlobFS.java --- android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index 34ce8296f..a4d70153f 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -416,7 +416,7 @@ void writeStream(String path, String encoding, boolean append, Callback callback File dest = new File(path); File dir = dest.getParentFile(); - if(!dest.)()) { + if(!dest.exists()) { if(dir != null && !dir.exists()) { if (!dir.mkdirs()) { callback.invoke("ENOTDIR", "Failed to create parent directory of '" + path + "'"); From 3ea8218fbfe9aa4986ced4c722e4b9265fa96657 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Thu, 19 Dec 2019 09:37:33 -0700 Subject: [PATCH 154/182] 0.12.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ecb17afd..a0fa1b5c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.11.2", + "version": "0.12.0", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From c6b372766febffacec4366a1fad214a442e5cf04 Mon Sep 17 00:00:00 2001 From: ihavenoface5 Date: Mon, 3 Feb 2020 09:20:17 -0700 Subject: [PATCH 155/182] Update RNFetchBlobReq.java added class cast exception for FileStorage response type. --- .../main/java/com/RNFetchBlob/RNFetchBlobReq.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index a8abd7183..63d22acdf 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -591,7 +591,17 @@ private void done(Response resp) { // ignored.printStackTrace(); } - RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; + try { + RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; + } catch (ClassCastException ex) { + // unexpected response type + if (responseBody != null) { + callback.invoke("Unexpected FileStorage response file: " + responseBody.string(), null); + } else { + callback.invoke("Unexpected FileStorage response with no file.", null); + } + return; + } if(rnFetchBlobFileResp != null && !rnFetchBlobFileResp.isDownloadComplete()){ callback.invoke("Download interrupted.", null); From 3f75d5e9c6d0da2682167f1a0c8f3fb5164d102e Mon Sep 17 00:00:00 2001 From: ihavenoface5 Date: Mon, 3 Feb 2020 10:23:06 -0700 Subject: [PATCH 156/182] Update RNFetchBlobReq.java fixed scoping problem --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 63d22acdf..e89eb458b 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -591,8 +591,10 @@ private void done(Response resp) { // ignored.printStackTrace(); } + RNFetchBlobFileResp rnFetchBlobFileResp; + try { - RNFetchBlobFileResp rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; + rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; } catch (ClassCastException ex) { // unexpected response type if (responseBody != null) { From af52cc73e8ec11ee6dcb33cb95139f4aa9435644 Mon Sep 17 00:00:00 2001 From: pex7 Date: Thu, 12 Mar 2020 11:20:37 -0600 Subject: [PATCH 157/182] Update RNFetchBlobReq.java --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index e89eb458b..661975582 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -598,7 +598,7 @@ private void done(Response resp) { } catch (ClassCastException ex) { // unexpected response type if (responseBody != null) { - callback.invoke("Unexpected FileStorage response file: " + responseBody.string(), null); + callback.invoke("Unexpected FileStorage response file: " + responseBody.body().string(), null); } else { callback.invoke("Unexpected FileStorage response with no file.", null); } From d06e2e92d99e035f36d66691ceabb91362427918 Mon Sep 17 00:00:00 2001 From: Tyler Pexton Date: Thu, 12 Mar 2020 11:44:30 -0600 Subject: [PATCH 158/182] fix io exception in RNFetchBlobReq --- .../src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 661975582..d2f2252a2 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -592,13 +592,19 @@ private void done(Response resp) { } RNFetchBlobFileResp rnFetchBlobFileResp; - + try { rnFetchBlobFileResp = (RNFetchBlobFileResp) responseBody; } catch (ClassCastException ex) { // unexpected response type if (responseBody != null) { - callback.invoke("Unexpected FileStorage response file: " + responseBody.body().string(), null); + String responseBodyString = null; + try { + responseBodyString = responseBody.string(); + } catch(IOException exception) { + exception.printStackTrace(); + } + callback.invoke("Unexpected FileStorage response file: " + responseBodyString, null); } else { callback.invoke("Unexpected FileStorage response with no file.", null); } From 29116262c6e8fd28ef5cafc4b2ee9bfbdfa05663 Mon Sep 17 00:00:00 2001 From: Nadav Luzzato Date: Tue, 26 May 2020 10:54:11 +0300 Subject: [PATCH 159/182] Fixed an issue with creating a file from base64 data --- ios/RNFetchBlob/RNFetchBlob.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNFetchBlob/RNFetchBlob.m b/ios/RNFetchBlob/RNFetchBlob.m index 258751ef8..d82739399 100644 --- a/ios/RNFetchBlob/RNFetchBlob.m +++ b/ios/RNFetchBlob/RNFetchBlob.m @@ -165,7 +165,7 @@ - (NSDictionary *)constantsToExport fileContent = [[NSData alloc] initWithData:[data dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]]; } else if([[encoding lowercaseString] isEqualToString:@"base64"]) { - fileContent = [[NSData alloc] initWithBase64EncodedData:data options:0]; + fileContent = [[NSData alloc] initWithBase64EncodedData:data options:NSDataBase64DecodingIgnoreUnknownCharacters]; } else if([[encoding lowercaseString] isEqualToString:@"uri"]) { NSString * orgPath = [data stringByReplacingOccurrencesOfString:FILE_PREFIX withString:@""]; From 39e4a454d5b86dfc8799a4dc3ca15beae158ce47 Mon Sep 17 00:00:00 2001 From: Ahmed AlAskalany Date: Wed, 15 Jul 2020 13:38:53 +0200 Subject: [PATCH 160/182] Fix #26 Avoid crashing the app when the event is called while the react context is not initialized. --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index d2f2252a2..5b89ebca0 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -727,8 +727,10 @@ private String getHeaderIgnoreCases(HashMap headers, String field } private void emitStateEvent(WritableMap args) { - RNFetchBlob.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(RNFetchBlobConst.EVENT_HTTP_STATE, args); + if (RNFetchBlob.RCTContext.hasActiveCatalystInstance()) { + RNFetchBlob.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(RNFetchBlobConst.EVENT_HTTP_STATE, args); + } } @Override From 7a576f005f04f784e6f82aff359733ef68e59224 Mon Sep 17 00:00:00 2001 From: Ahmed AlAskalany Date: Wed, 15 Jul 2020 13:48:24 +0200 Subject: [PATCH 161/182] Update RNFetchBlobReq.java --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 5b89ebca0..edcd97d78 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -727,9 +727,11 @@ private String getHeaderIgnoreCases(HashMap headers, String field } private void emitStateEvent(WritableMap args) { - if (RNFetchBlob.RCTContext.hasActiveCatalystInstance()) { + try { RNFetchBlob.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(RNFetchBlobConst.EVENT_HTTP_STATE, args); + } catch (Exception e) { + FLog.e("RNFetchBlobReq", "Error emitting state event", e); } } From 4ff2d8a293a9fb1f47192fb64340b479a76a4fda Mon Sep 17 00:00:00 2001 From: Artem Emelyanov Date: Tue, 4 Aug 2020 03:02:30 +0500 Subject: [PATCH 162/182] check if buffer data and content exists before trying get data from source --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index d2f2252a2..5fde54097 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -600,7 +600,11 @@ private void done(Response resp) { if (responseBody != null) { String responseBodyString = null; try { - responseBodyString = responseBody.string(); + boolean isBufferDataExists = responseBody.source().buffer().size() > 0; + boolean isContentExists = responseBody.contentLength() > 0; + if (isBufferDataExists && isContentExists) { + responseBodyString = responseBody.string(); + } } catch(IOException exception) { exception.printStackTrace(); } From 56f6069ad97401dded614e1c2551c4317e0bc7dd Mon Sep 17 00:00:00 2001 From: Chaitanya Anand Date: Fri, 7 Aug 2020 23:20:15 +0530 Subject: [PATCH 163/182] Added support for Android API 29 --- android/build.gradle | 8 +++---- .../gradle/wrapper/gradle-wrapper.properties | 4 ++-- .../java/com/RNFetchBlob/RNFetchBlob.java | 16 +++++-------- .../java/com/RNFetchBlob/RNFetchBlobFS.java | 24 +++++++++---------- .../com/RNFetchBlob/Utils/PathResolver.java | 3 +-- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index a4ca7a421..9b44e0c5d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -16,16 +16,16 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:4.0.1' } } android { - compileSdkVersion safeExtGet('compileSdkVersion', 28) + compileSdkVersion safeExtGet('compileSdkVersion', 30) buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3') defaultConfig { minSdkVersion safeExtGet('minSdkVersion', 16) - targetSdkVersion safeExtGet('targetSdkVersion', 28) + targetSdkVersion safeExtGet('targetSdkVersion', 30) versionCode 1 versionName "1.0" } @@ -41,6 +41,6 @@ android { dependencies { implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" - //compile 'com.squareup.okhttp3:okhttp:+' + //implementation 'com.squareup.okhttp3:okhttp:+' //{RNFetchBlob_PRE_0.28_DEPDENDENCY} } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index c75df059d..ecceb2dea 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 01 10:33:07 BRT 2018 +#Fri Aug 07 22:58:34 IST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 602d51d33..a972228ea 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -24,7 +24,8 @@ import com.facebook.react.modules.network.ForwardingCookieHandler; import com.facebook.react.modules.network.CookieJarContainer; import com.facebook.react.modules.network.OkHttpClientProvider; -import okhttp3.OkHttpClient; +import com.squareup.okhttp.OkHttpClient; + import okhttp3.JavaNetCookieJar; import java.io.File; @@ -60,18 +61,13 @@ public RNFetchBlob(ReactApplicationContext reactContext) { RCTContext = reactContext; reactContext.addActivityEventListener(new ActivityEventListener() { @Override - public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { + public void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == GET_CONTENT_INTENT && resultCode == RESULT_OK) { Uri d = data.getData(); promiseTable.get(GET_CONTENT_INTENT).resolve(d.toString()); promiseTable.remove(GET_CONTENT_INTENT); } } - - @Override - public void onNewIntent(Intent intent) { - - } }); } @@ -108,7 +104,7 @@ public void run() { @ReactMethod public void actionViewIntent(String path, String mime, final Promise promise) { try { - Uri uriForFile = FileProvider.getUriForFile(getCurrentActivity(), + Uri uriForFile = FileProvider.getUriForFile(this.getReactApplicationContext(), this.getReactApplicationContext().getPackageName() + ".provider", new File(path)); if (Build.VERSION.SDK_INT >= 24) { @@ -336,7 +332,7 @@ public void df(final Callback callback) { fsThreadPool.execute(new Runnable() { @Override public void run() { - RNFetchBlobFS.df(callback); + RNFetchBlobFS.df(callback, getReactApplicationContext()); } }); } @@ -404,7 +400,7 @@ public void addCompleteDownload (ReadableMap config, Promise promise) { @ReactMethod public void getSDCardDir(Promise promise) { - RNFetchBlobFS.getSDCardDir(promise); + RNFetchBlobFS.getSDCardDir(this.getReactApplicationContext(), promise); } @ReactMethod diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java index a4d70153f..124bb81d7 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java @@ -252,16 +252,16 @@ static Map getSystemfolders(ReactApplicationContext ctx) { res.put("DocumentDir", ctx.getFilesDir().getAbsolutePath()); res.put("CacheDir", ctx.getCacheDir().getAbsolutePath()); - res.put("DCIMDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath()); - res.put("PictureDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()); - res.put("MusicDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath()); - res.put("DownloadDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()); - res.put("MovieDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath()); - res.put("RingtoneDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES).getAbsolutePath()); + res.put("DCIMDir", ctx.getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath()); + res.put("PictureDir", ctx.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath()); + res.put("MusicDir", ctx.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath()); + res.put("DownloadDir", ctx.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()); + res.put("MovieDir", ctx.getExternalFilesDir(Environment.DIRECTORY_MOVIES).getAbsolutePath()); + res.put("RingtoneDir", ctx.getExternalFilesDir(Environment.DIRECTORY_RINGTONES).getAbsolutePath()); String state; state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { - res.put("SDCardDir", Environment.getExternalStorageDirectory().getAbsolutePath()); + res.put("SDCardDir", ctx.getExternalFilesDir(null).getAbsolutePath()); File externalDirectory = ctx.getExternalFilesDir(null); @@ -276,9 +276,9 @@ static Map getSystemfolders(ReactApplicationContext ctx) { return res; } - static public void getSDCardDir(Promise promise) { + static public void getSDCardDir(ReactApplicationContext ctx, Promise promise) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - promise.resolve(Environment.getExternalStorageDirectory().getAbsolutePath()); + promise.resolve(ctx.getExternalFilesDir(null).getAbsolutePath()); } else { promise.reject("RNFetchBlob.getSDCardDir", "External storage not mounted"); } @@ -986,13 +986,13 @@ static void createFileASCII(String path, ReadableArray data, Promise promise) { } } - static void df(Callback callback) { - StatFs stat = new StatFs(Environment.getDataDirectory().getPath()); + static void df(Callback callback, ReactApplicationContext ctx) { + StatFs stat = new StatFs(ctx.getFilesDir().getPath()); WritableMap args = Arguments.createMap(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { args.putString("internal_free", String.valueOf(stat.getFreeBytes())); args.putString("internal_total", String.valueOf(stat.getTotalBytes())); - StatFs statEx = new StatFs(Environment.getExternalStorageDirectory().getPath()); + StatFs statEx = new StatFs(ctx.getExternalFilesDir(null).getPath()); args.putString("external_free", String.valueOf(statEx.getFreeBytes())); args.putString("external_total", String.valueOf(statEx.getTotalBytes())); diff --git a/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java b/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java index c83fdbaf6..c20c1943b 100644 --- a/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java +++ b/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java @@ -8,7 +8,6 @@ import android.provider.DocumentsContract; import android.provider.MediaStore; import android.content.ContentUris; -import android.os.Environment; import android.content.ContentResolver; import com.RNFetchBlob.RNFetchBlobUtils; import java.io.File; @@ -30,7 +29,7 @@ public static String getRealPathFromURI(final Context context, final Uri uri) { final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { - return Environment.getExternalStorageDirectory() + "/" + split[1]; + return context.getExternalFilesDir(null) + "/" + split[1]; } // TODO handle non-primary volumes From e221b0afa07aa059d2013e713e6e68dc299aea68 Mon Sep 17 00:00:00 2001 From: Chaitanya Anand Date: Sat, 8 Aug 2020 00:02:19 +0530 Subject: [PATCH 164/182] Added support for Android API 29 --- android/build.gradle | 6 ++++-- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 9b44e0c5d..7c0392bc4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -41,6 +41,8 @@ android { dependencies { implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" - //implementation 'com.squareup.okhttp3:okhttp:+' - //{RNFetchBlob_PRE_0.28_DEPDENDENCY} + implementation 'com.squareup.okhttp3:okhttp:+' + implementation 'com.squareup.okhttp3:logging-interceptor:+' + implementation 'com.squareup.okhttp3:okhttp-urlconnection:+' +// {RNFetchBlob_PRE_0.28_DEPDENDENCY} } diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index a972228ea..02ba0eca7 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -24,9 +24,9 @@ import com.facebook.react.modules.network.ForwardingCookieHandler; import com.facebook.react.modules.network.CookieJarContainer; import com.facebook.react.modules.network.OkHttpClientProvider; -import com.squareup.okhttp.OkHttpClient; import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; import java.io.File; import java.util.Map; From dccab7e9667d3a7c5287c8840c1291e1ade8fb0a Mon Sep 17 00:00:00 2001 From: Chaitanya Anand Date: Sat, 8 Aug 2020 00:05:23 +0530 Subject: [PATCH 165/182] Added support for Android API 29 --- android/src/main/java/com/RNFetchBlob/RNFetchBlob.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 02ba0eca7..b53c68453 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -61,13 +61,18 @@ public RNFetchBlob(ReactApplicationContext reactContext) { RCTContext = reactContext; reactContext.addActivityEventListener(new ActivityEventListener() { @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { + public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { if(requestCode == GET_CONTENT_INTENT && resultCode == RESULT_OK) { Uri d = data.getData(); promiseTable.get(GET_CONTENT_INTENT).resolve(d.toString()); promiseTable.remove(GET_CONTENT_INTENT); } } + + @Override + public void onNewIntent(Intent intent) { + + } }); } From e4a545a485fc9a8fd4a8977f5b926eb1781fb502 Mon Sep 17 00:00:00 2001 From: Abraham Przewodnik Date: Mon, 14 Sep 2020 12:02:16 +0200 Subject: [PATCH 166/182] Remove IOS7 polyfill for containsString --- ios/IOS7Polyfill.h | 27 ----------------------- ios/RNFetchBlob.xcodeproj/project.pbxproj | 2 -- ios/RNFetchBlobFS.m | 3 +-- ios/RNFetchBlobReqBuilder.m | 7 +++--- ios/RNFetchBlobRequest.m | 11 +++++---- 5 files changed, 9 insertions(+), 41 deletions(-) delete mode 100644 ios/IOS7Polyfill.h diff --git a/ios/IOS7Polyfill.h b/ios/IOS7Polyfill.h deleted file mode 100644 index 04a4bfaaf..000000000 --- a/ios/IOS7Polyfill.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// IOS7Polyfill.h -// RNFetchBlob -// -// Created by Ben Hsieh on 2016/9/6. -// Copyright © 2016年 wkh237.github.io. All rights reserved. -// - -#ifndef IOS7Polyfill_h -#define IOS7Polyfill_h - -@interface NSString (Contains) - -- (BOOL)RNFBContainsString:(NSString*)other; - -@end - -@implementation NSString (Contains) - -- (BOOL)RNFBContainsString:(NSString*)other { - NSRange range = [self rangeOfString:other]; - return range.length != 0; -} - - -@end -#endif /* IOS7Polyfill_h */ diff --git a/ios/RNFetchBlob.xcodeproj/project.pbxproj b/ios/RNFetchBlob.xcodeproj/project.pbxproj index 4fbdc00ea..e08dc8e1e 100644 --- a/ios/RNFetchBlob.xcodeproj/project.pbxproj +++ b/ios/RNFetchBlob.xcodeproj/project.pbxproj @@ -45,7 +45,6 @@ A19B48241D98102400E6868A /* RNFetchBlobProgress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobProgress.m; sourceTree = ""; }; A1AAE2971D300E3E0051D11C /* RNFetchBlobReqBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobReqBuilder.h; sourceTree = ""; }; A1AAE2981D300E4D0051D11C /* RNFetchBlobReqBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobReqBuilder.m; sourceTree = ""; }; - A1F950181D7E9134002A95A6 /* IOS7Polyfill.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOS7Polyfill.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -71,7 +70,6 @@ children = ( A19B48241D98102400E6868A /* RNFetchBlobProgress.m */, A19B48231D98100800E6868A /* RNFetchBlobProgress.h */, - A1F950181D7E9134002A95A6 /* IOS7Polyfill.h */, A1AAE2981D300E4D0051D11C /* RNFetchBlobReqBuilder.m */, A1AAE2971D300E3E0051D11C /* RNFetchBlobReqBuilder.h */, A158F42E1D0539CE006FFD38 /* RNFetchBlobNetwork.h */, diff --git a/ios/RNFetchBlobFS.m b/ios/RNFetchBlobFS.m index e597ee5d5..c013d80e4 100644 --- a/ios/RNFetchBlobFS.m +++ b/ios/RNFetchBlobFS.m @@ -10,7 +10,6 @@ #import "RNFetchBlob.h" #import "RNFetchBlobFS.h" #import "RNFetchBlobConst.h" -#import "IOS7Polyfill.h" @import AssetsLibrary; #import @@ -375,7 +374,7 @@ + (void) writeFile:(NSString *)path NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:path]; NSData * content = nil; - if([encoding RNFBContainsString:@"base64"]) { + if([encoding containsString:@"base64"]) { content = [[NSData alloc] initWithBase64EncodedString:data options:0]; } else if([encoding isEqualToString:@"uri"]) { diff --git a/ios/RNFetchBlobReqBuilder.m b/ios/RNFetchBlobReqBuilder.m index 16963bb5f..68ee34f71 100644 --- a/ios/RNFetchBlobReqBuilder.m +++ b/ios/RNFetchBlobReqBuilder.m @@ -11,7 +11,6 @@ #import "RNFetchBlobNetwork.h" #import "RNFetchBlobConst.h" #import "RNFetchBlobFS.h" -#import "IOS7Polyfill.h" #if __has_include() #import @@ -117,7 +116,7 @@ +(void) buildOctetRequest:(NSDictionary *)options orgPath = [RNFetchBlobFS getPathOfAsset:orgPath]; if([orgPath hasPrefix:AL_PREFIX]) { - + [RNFetchBlobFS readFile:orgPath encoding:nil onComplete:^(id content, NSString* code, NSString * err) { if(err != nil) { @@ -131,7 +130,7 @@ +(void) buildOctetRequest:(NSDictionary *)options onComplete(request, [((NSData *)content) length]); } }]; - + return; } size = [[[NSFileManager defaultManager] attributesOfItemAtPath:orgPath error:nil] fileSize]; @@ -150,7 +149,7 @@ +(void) buildOctetRequest:(NSDictionary *)options __block NSString * cType = [[self class]getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders]; // when content-type is application/octet* decode body string using BASE64 decoder - if([[cType lowercaseString] hasPrefix:@"application/octet"] || [[cType lowercaseString] RNFBContainsString:@";base64"]) + if([[cType lowercaseString] hasPrefix:@"application/octet"] || [[cType lowercaseString] containsString:@";base64"]) { __block NSString * ncType = [[cType stringByReplacingOccurrencesOfString:@";base64" withString:@""]stringByReplacingOccurrencesOfString:@";BASE64" withString:@""]; if([mheaders valueForKey:@"content-type"] != nil) diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index cdbe6b1e5..8db644453 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -12,7 +12,6 @@ #import "RNFetchBlobConst.h" #import "RNFetchBlobReqBuilder.h" -#import "IOS7Polyfill.h" #import @@ -214,20 +213,20 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat return; } else { - self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"]; + self.isServerPush = [[respCType lowercaseString] containsString:@"multipart/x-mixed-replace;"]; } if(respCType) { NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE]; - if ([respCType RNFBContainsString:@"text/"]) { + if ([respCType containsString:@"text/"]) { respType = @"text"; - } else if ([respCType RNFBContainsString:@"application/json"]) { + } else if ([respCType containsString:@"application/json"]) { respType = @"json"; } else if(extraBlobCTypes) { // If extra blob content type is not empty, check if response type matches for (NSString * substr in extraBlobCTypes) { - if ([respCType RNFBContainsString:[substr lowercaseString]]) { + if ([respCType containsString:[substr lowercaseString]]) { respType = @"blob"; respFile = YES; destPath = [RNFetchBlobFS getTempPath:taskId withExtension:nil]; @@ -285,7 +284,7 @@ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dat // if not set overwrite in options, defaults to TRUE BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue]; - BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"]; + BOOL appendToExistingFile = [destPath containsString:@"?append=true"]; appendToExistingFile = !overwrite; From 7c0ff463eb6d206dd9c666f1a7640af38eceed21 Mon Sep 17 00:00:00 2001 From: JX Wang Date: Tue, 22 Sep 2020 20:07:20 +0800 Subject: [PATCH 167/182] use lodash/reduce replace lodash import --- index.js | 4 ++-- package.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 8ab5e9685..03063fe12 100644 --- a/index.js +++ b/index.js @@ -21,7 +21,7 @@ import fs from './fs' import getUUID from './utils/uuid' import base64 from 'base-64' import polyfill from './polyfill' -import _ from 'lodash' +import reduce from 'lodash/reduce' import android from './android' import ios from './ios' import JSONStream from './json-stream' @@ -224,7 +224,7 @@ function fetch(...args:any):Promise { // # 241 normalize null or undefined headers, in case nil or null string // pass to native context - headers = _.reduce(headers, (result, value, key) => { + headers = reduce(headers, (result, value, key) => { result[key] = value || '' return result }, {}); diff --git a/package.json b/package.json index a0fa1b5c9..b77048b4c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ }, "dependencies": { "base-64": "0.1.0", - "glob": "7.0.6" + "glob": "7.0.6", + "lodash": "4.17.15" }, "keywords": [ "react-native", From 029cf17e1d6985243469d0a928f314a8243d84b2 Mon Sep 17 00:00:00 2001 From: Christian Guy Date: Fri, 16 Oct 2020 10:58:34 +0200 Subject: [PATCH 168/182] Fix actionViewIntent for Android <= 6 --- .../java/com/RNFetchBlob/RNFetchBlob.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java index 602d51d33..e64e90b5a 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java @@ -111,28 +111,23 @@ public void actionViewIntent(String path, String mime, final Promise promise) { Uri uriForFile = FileProvider.getUriForFile(getCurrentActivity(), this.getReactApplicationContext().getPackageName() + ".provider", new File(path)); - if (Build.VERSION.SDK_INT >= 24) { - // Create the intent with data and type - Intent intent = new Intent(Intent.ACTION_VIEW) - .setDataAndType(uriForFile, mime); - - // Set flag to give temporary permission to external app to use FileProvider - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - // All the activity to be opened outside of an activity - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - // Validate that the device can open the file - PackageManager pm = getCurrentActivity().getPackageManager(); - if (intent.resolveActivity(pm) != null) { - this.getReactApplicationContext().startActivity(intent); - } - - } else { - Intent intent = new Intent(Intent.ACTION_VIEW) - .setDataAndType(Uri.parse("file://" + path), mime).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - + // Create the intent with data and type + Intent intent = new Intent(Intent.ACTION_VIEW) + .setDataAndType(uriForFile, mime); + + // Set flag to give temporary permission to external app to use FileProvider + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + // All the activity to be opened outside of an activity + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // Validate that the device can open the file + PackageManager pm = getCurrentActivity().getPackageManager(); + if (intent.resolveActivity(pm) != null) { this.getReactApplicationContext().startActivity(intent); + } else { + promise.reject("EUNSPECIFIED", "Cannot open the URL."); } + ActionViewVisible = true; final LifecycleEventListener listener = new LifecycleEventListener() { From ae41bff762c7fc8093002b6164e485a0b81829c4 Mon Sep 17 00:00:00 2001 From: Alex Naiman Date: Thu, 22 Oct 2020 23:33:56 +0300 Subject: [PATCH 169/182] fix: 183 requiring cycles --- polyfill/Blob.js | 3 ++- polyfill/Fetch.js | 3 ++- polyfill/XMLHttpRequest.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/polyfill/Blob.js b/polyfill/Blob.js index 53662a798..c99754dc2 100644 --- a/polyfill/Blob.js +++ b/polyfill/Blob.js @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style license that can be // found in the LICENSE file. -import RNFetchBlob from '../index.js' +import {NativeModules} from 'react-native'; import fs from '../fs.js' import getUUID from '../utils/uuid' import Log from '../utils/log.js' import EventTarget from './EventTarget' +const RNFetchBlob = NativeModules.RNFetchBlob const log = new Log('Blob') const blobCacheDir = fs.dirs.DocumentDir + '/RNFetchBlob-blobs/' diff --git a/polyfill/Fetch.js b/polyfill/Fetch.js index 3ecb5915c..8cc9f08e6 100644 --- a/polyfill/Fetch.js +++ b/polyfill/Fetch.js @@ -1,9 +1,10 @@ -import RNFetchBlob from '../index.js' +import {NativeModules} from 'react-native'; import Log from '../utils/log.js' import fs from '../fs' import unicode from '../utils/unicode' import Blob from './Blob' +const RNFetchBlob = NativeModules.RNFetchBlob const log = new Log('FetchPolyfill') log.disable() diff --git a/polyfill/XMLHttpRequest.js b/polyfill/XMLHttpRequest.js index 9036b2bc8..d52e47e19 100644 --- a/polyfill/XMLHttpRequest.js +++ b/polyfill/XMLHttpRequest.js @@ -2,13 +2,14 @@ // Use of this source code is governed by a MIT-style license that can be // found in the LICENSE file. -import RNFetchBlob from '../index.js' +import {NativeModules} from 'react-native'; import XMLHttpRequestEventTarget from './XMLHttpRequestEventTarget.js' import Log from '../utils/log.js' import Blob from './Blob.js' import ProgressEvent from './ProgressEvent.js' import URIUtil from '../utils/uri' +const RNFetchBlob = NativeModules.RNFetchBlob const log = new Log('XMLHttpRequest') log.disable() From dcbde6f7e12b666b9fe1c8c4a8e2cb04e0048326 Mon Sep 17 00:00:00 2001 From: Travis Nuttall Date: Thu, 19 Nov 2020 16:28:02 -0700 Subject: [PATCH 170/182] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b5ca84c45..a016b72b3 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ A project committed to making file access and data transfer easier and more efficient for React Native developers. +# ⚠️ Unmaintained ⚠️ + # 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 From 4800aba220d24d9bc8b9f328dd4cfd24d00d97b2 Mon Sep 17 00:00:00 2001 From: Teodor Ciuraru Date: Mon, 5 Apr 2021 13:16:54 +0300 Subject: [PATCH 171/182] Solve network requests not completing in Release [iOS] --- ios/RNFetchBlobRequest.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ios/RNFetchBlobRequest.m b/ios/RNFetchBlobRequest.m index cdbe6b1e5..bfa246dad 100644 --- a/ios/RNFetchBlobRequest.m +++ b/ios/RNFetchBlobRequest.m @@ -161,8 +161,9 @@ - (void) sendRequest:(__weak NSDictionary * _Nullable )options respFile = NO; } - self.task = [session dataTaskWithRequest:req]; - [self.task resume]; + NSURLSessionDataTask *task = [session dataTaskWithRequest:req]; + [task resume]; + self.task = task; // network status indicator if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) { From f563d50fe3d90af6e11215f19c72faa5bb27d6fd Mon Sep 17 00:00:00 2001 From: Julia Neidert Date: Wed, 1 Sep 2021 12:52:01 -0700 Subject: [PATCH 172/182] fix addAndroidDownloads for paths containing % --- android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 5fde54097..d51f55cac 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -177,7 +177,7 @@ public void run() { req.setDescription(options.addAndroidDownloads.getString("description")); } if(options.addAndroidDownloads.hasKey("path")) { - req.setDestinationUri(Uri.parse("file://" + options.addAndroidDownloads.getString("path"))); + req.setDestinationUri(Uri.fromFile(new File(options.addAndroidDownloads.getString("path")))); } // #391 Add MIME type to the request if(options.addAndroidDownloads.hasKey("mime")) { From bb6cb9294d1e5501866bd4835252ab764394e92b Mon Sep 17 00:00:00 2001 From: Ionita Mihai Sebastian Date: Thu, 16 Sep 2021 15:40:32 +0300 Subject: [PATCH 173/182] As jcenter is being shut down, we should use mavenCentral instead. --- android/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index a4ca7a421..d2527c7e6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,13 +6,12 @@ def safeExtGet(prop, fallback) { repositories { mavenCentral() - jcenter() google() } buildscript { repositories { - jcenter() + mavenCentral() google() } dependencies { From 8b874f97aa87f1aa0853a8d30d1cf7a67b58c23c Mon Sep 17 00:00:00 2001 From: Ron Radtke Date: Wed, 29 Sep 2021 14:43:01 +0200 Subject: [PATCH 174/182] fixes #64 --- android/.project | 28 +++++++++++++++++++ .../org.eclipse.buildship.core.prefs | 13 +++++++++ .../java/com/RNFetchBlob/RNFetchBlobReq.java | 21 ++++++++++---- 3 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 android/.project create mode 100644 android/.settings/org.eclipse.buildship.core.prefs diff --git a/android/.project b/android/.project new file mode 100644 index 000000000..5c0128a89 --- /dev/null +++ b/android/.project @@ -0,0 +1,28 @@ + + + android + Project android created by Buildship. + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.buildship.core.gradleprojectnature + + + + 1634215444278 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 000000000..98515123a --- /dev/null +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 5fde54097..64cfd18db 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -392,8 +392,9 @@ public Response intercept(Chain chain) throws IOException { clientBuilder.addInterceptor(new Interceptor() { @Override public Response intercept(@NonNull Chain chain) throws IOException { + Response originalResponse = null; try { - Response originalResponse = chain.proceed(req); + originalResponse = chain.proceed(req); ResponseBody extended; switch (responseType) { case KeepInMemory: @@ -423,13 +424,21 @@ public Response intercept(@NonNull Chain chain) throws IOException { } catch(SocketException e) { timeout = true; - } - catch (SocketTimeoutException e ){ + if (originalResponse != null) { + originalResponse.close(); + } + } catch (SocketTimeoutException e) { timeout = true; - //RNFetchBlobUtils.emitWarningEvent("RNFetchBlob error when sending request : " + e.getLocalizedMessage()); - } catch(Exception ex) { - + if (originalResponse != null) { + originalResponse.close(); + } + //ReactNativeBlobUtilUtils.emitWarningEvent("ReactNativeBlobUtil error when sending request : " + e.getLocalizedMessage()); + } catch (Exception ex) { + if (originalResponse != null) { + originalResponse.close(); + } } + return chain.proceed(chain.request()); } }); From 18d882ea0cf0433c47dc1b6ac3179f091a465a28 Mon Sep 17 00:00:00 2001 From: Theo Date: Tue, 2 Nov 2021 17:13:55 +0800 Subject: [PATCH 175/182] fix: callback invoke --- .../java/com/RNFetchBlob/RNFetchBlobReq.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java index 5fde54097..13eb0fc57 100644 --- a/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java +++ b/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java @@ -751,8 +751,13 @@ public void onReceive(Context context, Intent intent) { Cursor c = dm.query(query); // #236 unhandled null check for DownloadManager.query() return value if (c == null) { - this.callback.invoke("Download manager failed to download from " + this.url + ". Query was unsuccessful ", null, null); - return; + try { + this.callback.invoke("Download manager failed to download from " + this.url + ". Query was unsuccessful ", null, null); + return; + } + catch(Exception e) { + return; + } } String filePath = null; @@ -762,8 +767,13 @@ public void onReceive(Context context, Intent intent) { // #297 handle failed request int statusCode = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); if(statusCode == DownloadManager.STATUS_FAILED) { - this.callback.invoke("Download manager failed to download from " + this.url + ". Status Code = " + statusCode, null, null); - return; + try { + this.callback.invoke("Download manager failed to download from " + this.url + ". Query was unsuccessful ", null, null); + return; + } + catch(Exception e) { + return; + } } String contentUri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); if ( contentUri != null && From eff92b102f60a7c651eb0dec3b444d6cd6bc0c0e Mon Sep 17 00:00:00 2001 From: Chaitanya Anand <35635015+chaits98@users.noreply.github.com> Date: Thu, 3 Feb 2022 15:04:33 +0530 Subject: [PATCH 176/182] Added support to get okhttp library version from rootProject --- android/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 7c0392bc4..ded0482a7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -41,8 +41,8 @@ android { dependencies { implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" - implementation 'com.squareup.okhttp3:okhttp:+' - implementation 'com.squareup.okhttp3:logging-interceptor:+' - implementation 'com.squareup.okhttp3:okhttp-urlconnection:+' + implementation "com.squareup.okhttp3:okhttp:${safeExtGet('okhttp', '+')}" + implementation "com.squareup.okhttp3:logging-interceptor:${safeExtGet('okhttp', '+')}" + implementation "com.squareup.okhttp3:okhttp-urlconnection:${safeExtGet('okhttp', '+')}" // {RNFetchBlob_PRE_0.28_DEPDENDENCY} } From 7ebb9a45f44d482927ab90dcf315e73714609f68 Mon Sep 17 00:00:00 2001 From: rpenfold Date: Tue, 22 Feb 2022 21:12:10 -0700 Subject: [PATCH 177/182] Removed "unmaintained" banner --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a016b72b3..b5ca84c45 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,6 @@ A project committed to making file access and data transfer easier and more efficient for React Native developers. -# ⚠️ Unmaintained ⚠️ - # 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 From 988aea97ef187a8a18a2422dd727069f4b92fc47 Mon Sep 17 00:00:00 2001 From: Ryan Penfold Date: Tue, 22 Feb 2022 21:24:25 -0700 Subject: [PATCH 178/182] rev v13 beta version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b77048b4c..6cf9cc4df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.12.0", + "version": "0.13.0-beta1", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 4a2f8c4b2e470a18e9ceaa7f365fe0076e319d14 Mon Sep 17 00:00:00 2001 From: Ryan Penfold Date: Mon, 4 Apr 2022 07:37:20 -0600 Subject: [PATCH 179/182] version fix for consistency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6cf9cc4df..e537a6374 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.13.0-beta1", + "version": "0.13.0-beta-1", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From 9d74c78a07247bc07436e368123e6fb411c0263d Mon Sep 17 00:00:00 2001 From: Ryan Penfold Date: Mon, 6 Jun 2022 19:51:50 -0600 Subject: [PATCH 180/182] npmignore --- .npmignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 000000000..1b63e0419 --- /dev/null +++ b/.npmignore @@ -0,0 +1,8 @@ +CONTRIBUTORS.md +CONTRIBUTING.md +CODE_OF_CONDUCT.md + +.github/ +components/ +img/ +scripts/ From a0b26a2c63c30e60d83604538320af2f9370ab92 Mon Sep 17 00:00:00 2001 From: Ryan Penfold Date: Mon, 6 Jun 2022 21:06:03 -0600 Subject: [PATCH 181/182] 0.13.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e537a6374..7de11230e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rn-fetch-blob", - "version": "0.13.0-beta-1", + "version": "0.13.0-beta.1", "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.", "main": "index.js", "scripts": { From fead8a21b1e3d488f9574cb62d3c03ca973978bb Mon Sep 17 00:00:00 2001 From: David Wisner Date: Tue, 28 Jun 2022 09:58:46 +0800 Subject: [PATCH 182/182] remove config for 0.69.0, update readme --- .gitignore | 1 + README.md | 598 +++++++++++++++++++++++------------------ react-native.config.js | 7 - scripts/prelink.js | 71 ----- 4 files changed, 336 insertions(+), 341 deletions(-) delete mode 100644 react-native.config.js delete mode 100644 scripts/prelink.js diff --git a/.gitignore b/.gitignore index 418c56e5c..1e25f4d3d 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ local.properties # node_modules/ npm-debug.log +yarn.lock # BUCK buck-out/ diff --git a/README.md b/README.md index b5ca84c45..584845ccd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # rn-fetch-blob + [![release](https://img.shields.io/github/release/joltup/rn-fetch-blob.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/releases) [![npm](https://img.shields.io/npm/v/rn-fetch-blob.svg?style=flat-square)](https://www.npmjs.com/package/rn-fetch-blob) ![](https://img.shields.io/badge/PR-Welcome-brightgreen.svg?style=flat-square) [![](https://img.shields.io/badge/Wiki-Public-brightgreen.svg?style=flat-square)](https://github.com/joltup/rn-fetch-blob/wiki) [![npm](https://img.shields.io/npm/l/rn-fetch-blob.svg?maxAge=2592000&style=flat-square)]() A project committed to making file access and data transfer easier and more efficient for React Native developers. @@ -8,6 +9,7 @@ A project committed to making file access and data transfer easier and more effi 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 @@ -16,28 +18,29 @@ rn-fetch-blob version 0.10.16 is only compatible with react native 0.60 and up. - JSON stream supported base on [Oboe.js](https://github.com/jimhigson/oboe.js/) @jimhigson ## TOC (visit [Wiki](https://github.com/joltup/rn-fetch-blob/wiki) to get the complete documentation) -* [About](#user-content-about) -* [Installation](#user-content-installation) -* [HTTP Data Transfer](#user-content-http-data-transfer) - * [Regular Request](#user-content-regular-request) - * [Download file](#download-example-fetch-files-that-need-authorization-token) - * [Upload file](#user-content-upload-example--dropbox-files-upload-api) - * [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data) - * [Upload/Download progress](#user-content-uploaddownload-progress) - * [Cancel HTTP request](#user-content-cancel-request) - * [Android Media Scanner, and Download Manager Support](#user-content-android-media-scanner-and-download-manager-support) - * [Self-Signed SSL Server](#user-content-self-signed-ssl-server) - * [Transfer Encoding](#user-content-transfer-encoding) - * [Drop-in Fetch Replacement](#user-content-drop-in-fetch-replacement) -* [File System](#user-content-file-system) - * [File access](#user-content-file-access) - * [File stream](#user-content-file-stream) - * [Manage cached files](#user-content-cache-file-management) -* [Web API Polyfills](#user-content-web-api-polyfills) -* [Performance Tips](#user-content-performance-tips) -* [API References](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API) -* [Caveats](#user-content-caveats) -* [Development](#user-content-development) + +- [About](#user-content-about) +- [Installation](#user-content-installation) +- [HTTP Data Transfer](#user-content-http-data-transfer) +- [Regular Request](#user-content-regular-request) +- [Download file](#download-example-fetch-files-that-need-authorization-token) +- [Upload file](#user-content-upload-example--dropbox-files-upload-api) +- [Multipart/form upload](#user-content-multipartform-data-example--post-form-data-with-file-and-data) +- [Upload/Download progress](#user-content-uploaddownload-progress) +- [Cancel HTTP request](#user-content-cancel-request) +- [Android Media Scanner, and Download Manager Support](#user-content-android-media-scanner-and-download-manager-support) +- [Self-Signed SSL Server](#user-content-self-signed-ssl-server) +- [Transfer Encoding](#user-content-transfer-encoding) +- [Drop-in Fetch Replacement](#user-content-drop-in-fetch-replacement) +- [File System](#user-content-file-system) +- [File access](#user-content-file-access) +- [File stream](#user-content-file-stream) +- [Manage cached files](#user-content-cache-file-management) +- [Web API Polyfills](#user-content-web-api-polyfills) +- [Performance Tips](#user-content-performance-tips) +- [API References](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API) +- [Caveats](#user-content-caveats) +- [Development](#user-content-development) ## About @@ -47,7 +50,6 @@ It is committed to making file access and transfer easier and more efficient for 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](https://github.com/joltup/rn-firebase-storage-upload-sample) - ## Installation Install package from npm @@ -76,28 +78,47 @@ If automatically linking doesn't work for you, see instructions on [manually lin **Automatically Link Native Modules** -For 0.29.2+ projects, simply link native packages via the following command (note: rnpm has been merged into react-native) +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 ```sh rnpm link ``` -Optionally, use the following command to add Android permissions to `AndroidManifest.xml` automatically +You also might need add the following lines to `AndroidManifest.xml` -```sh -RNFB_ANDROID_PERMISSIONS=true react-native link rn-fetch-blob +```diff + + + ++ + ... + + ++ + ... ``` -pre 0.29 projects +For projects < 0.28 -```sh -RNFB_ANDROID_PERMISSIONS=true rnpm link +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` + +```diff +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](https://github.com/joltup/rn-fetch-blob/wiki/Manually-Link-Package) to link the package manually. @@ -152,7 +173,7 @@ ES6 The module uses ES6 style export statement, simply use `import` to load the module. ```js -import RNFetchBlob from 'rn-fetch-blob' +import RNFetchBlob from "rn-fetch-blob"; ``` ES5 @@ -165,7 +186,6 @@ 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 @@ -176,8 +196,8 @@ 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. +- 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'` @@ -189,21 +209,20 @@ To sum up: 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. ```js - // 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 .. - }) +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) { + if (status == 200) { // the conversion is done in native code - let base64Str = res.base64() + let base64Str = res.base64(); // the following conversions are done in js, it's SYNC - let text = res.text() - let json = res.json() + let text = res.text(); + let json = res.json(); } else { // handle other status codes } @@ -211,7 +230,7 @@ RNFetchBlob.fetch('GET', 'http://www.example.com/images/img1.png', { // Something went wrong: .catch((errorMessage, statusCode) => { // error handling - }) + }); ``` ### Download to storage directly @@ -221,19 +240,18 @@ If the response data is large, that would be a bad idea to convert it into BASE6 **These files won't be removed automatically, please refer to [Cache File Management](#user-content-cache-file-management)** ```js -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', { +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()) - }) + console.log("The file saved to ", res.path()); + }); ``` **Set Temp File Extension** @@ -241,71 +259,82 @@ RNFetchBlob 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`. ```js -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', { +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()) + 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 = - }) + imageView = ( + + ); + }); ``` **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](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#dirs) in v0.5.0 which represents commonly used directories. +If you prefer a particular file path rather than randomly generated one, you can use `path` option. We've added [several constants](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#dirs) in v0.5.0 which represents commonly used directories. ```js -let dirs = RNFetchBlob.fs.dirs -RNFetchBlob -.config({ +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()) + 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](#user-content-cache-file-management)** -#### Upload example : Dropbox [files-upload](https://www.dropbox.com/developers/documentation/http/documentation#files-upload) API +#### Upload example : Dropbox [files-upload](https://www.dropbox.com/developers/documentation/http/documentation#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. ```js - -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 +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', + "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) + }, + base64ImageString +) .then((res) => { - console.log(res.text()) + console.log(res.text()); }) .catch((err) => { // error handling .. - }) + }); ``` ### Upload a file from storage @@ -313,25 +342,30 @@ RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', { If you're going to use a `file` as request body, just wrap the path with `wrap` API. ```js -RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', { +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 + 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', + "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)) + }, + RNFetchBlob.wrap(PATH_TO_THE_FILE) +) .then((res) => { - console.log(res.text()) + console.log(res.text()); }) .catch((err) => { // error handling .. - }) + }); ``` ### Multipart/form-data example: Post form data with file and data @@ -341,29 +375,48 @@ In `version >= 0.3.0` you can also post files with form data, just put an array Elements have property `filename` will be transformed into binary format, otherwise, it turns into utf8 string. ```js - - RNFetchBlob.fetch('POST', 'http://www.example.com/upload-form', { - Authorization : "Bearer access-token", - otherHeader : "foo", - 'Content-Type' : 'multipart/form-data', - }, [ +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}, + { name: "avatar", filename: "avatar.png", data: binaryDataInBase64 }, // custom content type - { name : 'avatar-png', filename : 'avatar-png.png', type:'image/png', data: binaryDataInBase64}, + { + 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)}, + { + 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 : 'example@example.com', - tel : '12345678' - })}, - ]).then((resp) => { - // ... - }).catch((err) => { + { name: "name", data: "user" }, + { + name: "info", + data: JSON.stringify({ + mail: "example@example.com", + tel: "12345678", + }), + }, + ] +) + .then((resp) => { // ... }) + .catch((err) => { + // ... + }); ``` What if you want to append a file to form data? Just like [upload a file from storage](#user-content-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](https://github.com/joltup/rn-fetch-blob/issues/94)). @@ -410,48 +463,57 @@ What if you want to append a file to form data? Just like [upload a file from st 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. ```js - 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) => { - // ... - }) +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. - +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. ```js - 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) => { - // ... - }) +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 @@ -488,20 +550,20 @@ If you want to make a file in `External Storage` becomes visible in Picture, Dow 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. ```js - -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 - }) +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** @@ -515,23 +577,22 @@ When using DownloadManager, `fileCache` and `path` properties in `config` will n When download complete, DownloadManager will generate a file path so that you can deal with it. ```js -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() - }) +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](https://github.com/wkh237/react-native-fetch-blob/issues/236). @@ -541,7 +602,6 @@ Your app might not have right to remove/change the file created by Download Mana - 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`. ```js @@ -571,29 +631,31 @@ This is a new feature added in `0.9.0` if you're going to open a file path using Download and install an APK programmatically ```js - -const android = RNFetchBlob.android +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`) + 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') - }) + android.actionViewIntent( + res.path(), + "application/vnd.android.package-archive" + ); + }); ``` Or show an image in image viewer ```js - android.actionViewIntent(PATH_OF_IMG, 'image/png') +android.actionViewIntent(PATH_OF_IMG, "image/png"); ``` ## File System @@ -605,6 +667,7 @@ File access APIs were made when developing `v0.5.0`, which helping us write test Before start using file APIs, we recommend read [Differences between File Source](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#differences-between-file-source) first. File Access APIs + - [asset (0.6.2)](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#assetfilenamestringstring) - [dirs](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#dirs) - [createFile](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-API#createfilepath-data-encodingpromise) @@ -630,7 +693,7 @@ See [File API](https://github.com/joltup/rn-fetch-blob/wiki/File-System-Access-A ### 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**. +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](#user-content-performance-tips)) @@ -667,56 +730,62 @@ When using `writeStream`, the stream object becomes writable, and you can then p Since version 0.10.9 `write()` resolves with the `RNFetchBlob` instance so you can promise-chain write calls: ```js -RNFetchBlob.fs.writeStream( +RNFetchBlob.fs + .writeStream( PATH_TO_FILE, // encoding, should be one of `base64`, `utf8`, `ascii` - 'utf8', + "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) + ) + .then((ofstream) => ofstream.write("foo")) + .then((ofstream) => ofstream.write("bar")) + .then((ofstream) => ofstream.write("foobar")) + .then((ofstream) => ofstream.close()) + .catch(console.error); ``` or ```js -RNFetchBlob.fs.writeStream( +RNFetchBlob.fs + .writeStream( PATH_TO_FILE, // encoding, should be one of `base64`, `utf8`, `ascii` - 'utf8', + "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) + ) + .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: ```js -RNFetchBlob.fs.writeStream( +RNFetchBlob.fs + .writeStream( PATH_TO_FILE, // encoding, should be one of `base64`, `utf8`, `ascii` - 'utf8', + "utf8", // should data append to existing content ? - true) -.then((ofstream) => { + 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! + 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". @@ -728,22 +797,20 @@ That code may _seem_ to work if there are no errors, but those writes are of the 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 ```js +// 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 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(() => { - // ... - }) - +// 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. @@ -785,7 +852,12 @@ You can also group requests by using `session` API and use `dispose` to remove t 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`. ```js -RNFetchBlob.fetch('POST', 'http://example.com/upload', { 'Transfer-Encoding' : 'Chunked' }, bodyData) +RNFetchBlob.fetch( + "POST", + "http://example.com/upload", + { "Transfer-Encoding": "Chunked" }, + bodyData +); ``` ### Self-Signed SSL Server @@ -794,12 +866,12 @@ By default, rn-fetch-blob does NOT allow connection to unknown certification pro ```js RNFetchBlob.config({ - trusty : true -}) -.fetch('GET', 'https://mysite.com') -.then((resp) => { - // ... + trusty: true, }) + .fetch("GET", "https://mysite.com") + .then((resp) => { + // ... + }); ``` ### WiFi only requests @@ -810,17 +882,17 @@ on API version 21 (Lollipop, Android 5.0) or above. APIs below 21 will ignore th ```js RNFetchBlob.config({ - wifiOnly : true -}) -.fetch('GET', 'https://mysite.com') -.then((resp) => { - // ... + 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. +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) @@ -831,7 +903,7 @@ Here's a [sample app](https://github.com/joltup/rn-firebase-storage-upload-sampl **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. +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** @@ -853,11 +925,11 @@ If you're going to concatenate files, you don't have to read the data to JS cont ## Caveats -* This library does not urlencode unicode characters in URL automatically, see [#146](https://github.com/wkh237/react-native-fetch-blob/issues/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](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API#fetchprogressconfig-eventlistenerpromisernfetchblobresponse) to limit its frequency. -* When passing a file path to the library, remove `file://` prefix. +- This library does not urlencode unicode characters in URL automatically, see [#146](https://github.com/wkh237/react-native-fetch-blob/issues/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](https://github.com/joltup/rn-fetch-blob/wiki/Fetch-API#fetchprogressconfig-eventlistenerpromisernfetchblobresponse) 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](https://github.com/joltup/rn-fetch-blob/wiki/Trouble-Shooting) or [issues labeled Trouble Shooting](https://github.com/joltup/rn-fetch-blob/issues?utf8=✓&q=label:%22trouble%20shooting%22%20), there'd be some helpful information. diff --git a/react-native.config.js b/react-native.config.js deleted file mode 100644 index 03c61b6ec..000000000 --- a/react-native.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - dependency: { - hooks: { - prelink: 'node ./node_modules/rn-fetch-blob/scripts/prelink.js', - }, - }, -}; diff --git a/scripts/prelink.js b/scripts/prelink.js deleted file mode 100644 index e2c3ac483..000000000 --- a/scripts/prelink.js +++ /dev/null @@ -1,71 +0,0 @@ -try { - var fs = require('fs'); - var glob = require('glob'); - var addAndroidPermissions = process.env.RNFB_ANDROID_PERMISSIONS == 'true'; - var MANIFEST_PATH = glob.sync(process.cwd() + '/android/app/src/main/**/AndroidManifest.xml')[0]; - var PACKAGE_JSON = process.cwd() + '/package.json'; - var package = JSON.parse(fs.readFileSync(PACKAGE_JSON)); - var APP_NAME = package.name; - var PACKAGE_GRADLE = process.cwd() + '/node_modules/rn-fetch-blob/android/build.gradle' - var VERSION = checkVersion(); - - console.log('RNFetchBlob detected app version => ' + VERSION); - - if(VERSION < 0.28) { - console.log('You project version is '+ VERSION + ' which may not compatible to rn-fetch-blob 7.0+, please consider upgrade your application template to react-native 0.27+.') - // add OkHttp3 dependency fo pre 0.28 project - var main = fs.readFileSync(PACKAGE_GRADLE); - console.log('adding OkHttp3 dependency to pre 0.28 project .. ') - main = String(main).replace('//{RNFetchBlob_PRE_0.28_DEPDENDENCY}', "compile 'com.squareup.okhttp3:okhttp:3.4.1'"); - fs.writeFileSync(PACKAGE_GRADLE, main); - console.log('adding OkHttp3 dependency to pre 0.28 project .. ok') - } - - console.log('Add Android permissions => ' + (addAndroidPermissions == "true")) - - if(addAndroidPermissions) { - - // set file access permission for Android < 6.0 - fs.readFile(MANIFEST_PATH, function(err, data) { - - if(err) - console.log('failed to locate AndroidManifest.xml file, you may have to add file access permission manually.'); - else { - - console.log('RNFetchBlob patching AndroidManifest.xml .. '); - // append fs permission - data = String(data).replace( - '', - '\n ' - ) - // append DOWNLOAD_COMPLETE intent permission - data = String(data).replace( - '', - '\n ' - ) - fs.writeFileSync(MANIFEST_PATH, data); - console.log('RNFetchBlob patching AndroidManifest.xml .. ok'); - - } - - }) - } - else { - console.log( - '\033[95mrn-fetch-blob \033[97mwill not automatically add Android permissions after \033[92m0.9.4 '+ - '\033[97mplease run the following command if you want to add default permissions :\n\n' + - '\033[96m\tRNFB_ANDROID_PERMISSIONS=true react-native link \n') - } - - function checkVersion() { - console.log('RNFetchBlob checking app version ..'); - return parseFloat(/\d\.\d+(?=\.)/.exec(package.dependencies['react-native'])); - } - -} catch(err) { - console.log( - '\033[95mrn-fetch-blob\033[97m link \033[91mFAILED \033[97m\nCould not automatically link package :'+ - err.stack + - 'please follow the instructions to manually link the library : ' + - '\033[4mhttps://github.com/joltup/rn-fetch-blob/wiki/Manually-Link-Package\n') -}