diff --git a/Downloader.m b/Downloader.m index ed3abc65..bf102688 100644 --- a/Downloader.m +++ b/Downloader.m @@ -26,7 +26,7 @@ @implementation RNFSDownloader - (NSString *)downloadFile:(RNFSDownloadParams*)params { NSString *uuid = nil; - + _params = params; _lastProgressEmitTimestamp = 0; @@ -68,20 +68,20 @@ - (NSString *)downloadFile:(RNFSDownloadParams*)params _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; _task = [_session downloadTaskWithURL:url]; [_task resume]; - + return uuid; } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)downloadTask.response; - if (!_statusCode) { + if (_params.beginCallback && !_statusCode) { _statusCode = [NSNumber numberWithLong:httpResponse.statusCode]; _contentLength = [NSNumber numberWithLong:httpResponse.expectedContentLength]; return _params.beginCallback(_statusCode, _contentLength, httpResponse.allHeaderFields); } - if ([_statusCode isEqualToNumber:[NSNumber numberWithInt:200]]) { + if (_params.progressCallback && [_statusCode isEqualToNumber:[NSNumber numberWithInt:200]]) { _bytesWritten = @(totalBytesWritten); if(_params.progressInterval.integerValue > 0){ @@ -136,7 +136,9 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didComp if (error && error.code != NSURLErrorCancelled) { _resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData]; if (_resumeData != nil) { - _params.resumableCallback(); + if (_params.resumableCallback) { + _params.resumableCallback(); + } } else { _params.errorCallback(error); } @@ -149,14 +151,16 @@ - (void)stopDownload [_task cancelByProducingResumeData:^(NSData * _Nullable resumeData) { if (resumeData != nil) { self.resumeData = resumeData; - self->_params.resumableCallback(); + if (self->_params.resumableCallback) { + self->_params.resumableCallback(); + } } else { NSError *error = [NSError errorWithDomain:@"RNFS" code:0 //used to pass an NSString @"Aborted" here, but it needs an NSInteger userInfo:@{ NSLocalizedDescriptionKey: @"Download has been aborted" }]; - + self->_params.errorCallback(error); } }]; diff --git a/FS.common.js b/FS.common.js index aea32ff2..cb0e6d40 100755 --- a/FS.common.js +++ b/FS.common.js @@ -499,11 +499,17 @@ var RNFS = { var jobId = getJobId(); var subscriptions = []; - subscriptions.push(RNFS_NativeEventEmitter.addListener('DownloadBegin', options.begin || function() {})); + if (options.begin) { + subscriptions.push(RNFS_NativeEventEmitter.addListener('DownloadBegin', options.begin)); + } - subscriptions.push(RNFS_NativeEventEmitter.addListener('DownloadProgress', options.progress || function() {})); + if (options.progress) { + subscriptions.push(RNFS_NativeEventEmitter.addListener('DownloadProgress', options.progress)); + } - subscriptions.push(RNFS_NativeEventEmitter.addListener('DownloadResumable', options.resumable || function() {})); + if (options.resumable) { + subscriptions.push(RNFS_NativeEventEmitter.addListener('DownloadResumable', options.resumable)); + } var bridgeOptions = { jobId: jobId, @@ -515,7 +521,10 @@ var RNFS = { progressInterval: options.progressInterval || 0, readTimeout: options.readTimeout || 15000, connectionTimeout: options.connectionTimeout || 5000, - backgroundTimeout: options.backgroundTimeout || 3600000 // 1 hour + backgroundTimeout: options.backgroundTimeout || 3600000, // 1 hour + hasBeginCallback: options.begin instanceof Function, + hasProgressCallback: options.progress instanceof Function, + hasResumableCallback: options.resumable instanceof Function, }; return { @@ -548,17 +557,16 @@ var RNFS = { if (options.fields && typeof options.fields !== 'object') throw new Error('uploadFiles: Invalid value for property `fields`'); if (options.method && typeof options.method !== 'string') throw new Error('uploadFiles: Invalid value for property `method`'); - - subscriptions.push(RNFS_NativeEventEmitter.addListener('UploadBegin', options.begin || function() {})); - - if (options.beginCallback && options.beginCallback instanceof Function) { + if (options.begin) { + subscriptions.push(RNFS_NativeEventEmitter.addListener('UploadBegin', options.begin)); + } else if (options.beginCallback) { // Deprecated subscriptions.push(RNFS_NativeEventEmitter.addListener('UploadBegin', options.beginCallback)); } - subscriptions.push(RNFS_NativeEventEmitter.addListener('UploadProgress', options.progress || function() {})); - - if (options.progressCallback && options.progressCallback instanceof Function) { + if (options.progress) { + subscriptions.push(RNFS_NativeEventEmitter.addListener('UploadProgress', options.progress)); + } else if (options.progressCallback) { // Deprecated subscriptions.push(RNFS_NativeEventEmitter.addListener('UploadProgress', options.progressCallback)); } @@ -570,7 +578,9 @@ var RNFS = { binaryStreamOnly: options.binaryStreamOnly || false, headers: options.headers || {}, fields: options.fields || {}, - method: options.method || 'POST' + method: options.method || 'POST', + hasBeginCallback: options.begin instanceof Function || options.beginCallback instanceof Function, + hasProgressCallback: options.progress instanceof Function || options.progressCallback instanceof Function, }; return { diff --git a/RNFSManager.m b/RNFSManager.m index 66e982c0..105c2186 100755 --- a/RNFSManager.m +++ b/RNFSManager.m @@ -487,6 +487,9 @@ + (BOOL)requiresMainQueueSetup params.readTimeout = readTimeout; NSNumber* backgroundTimeout = options[@"backgroundTimeout"]; params.backgroundTimeout = backgroundTimeout; + bool hasBeginCallback = [options[@"hasBeginCallback"] boolValue]; + bool hasProgressCallback = [options[@"hasProgressCallback"] boolValue]; + bool hasResumableCallback = [options[@"hasResumableCallback"] boolValue]; __block BOOL callbackFired = NO; @@ -514,26 +517,32 @@ + (BOOL)requiresMainQueueSetup return [self reject:reject withError:error]; }; - params.beginCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSDictionary* headers) { - if (self.bridge != nil) - [self sendEventWithName:@"DownloadBegin" body:@{@"jobId": jobId, - @"statusCode": statusCode, - @"contentLength": contentLength, - @"headers": headers ?: [NSNull null]}]; - }; + if (hasBeginCallback) { + params.beginCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSDictionary* headers) { + if (self.bridge != nil) + [self sendEventWithName:@"DownloadBegin" body:@{@"jobId": jobId, + @"statusCode": statusCode, + @"contentLength": contentLength, + @"headers": headers ?: [NSNull null]}]; + }; + } - params.progressCallback = ^(NSNumber* contentLength, NSNumber* bytesWritten) { - if (self.bridge != nil) - [self sendEventWithName:@"DownloadProgress" - body:@{@"jobId": jobId, - @"contentLength": contentLength, - @"bytesWritten": bytesWritten}]; - }; - + if (hasProgressCallback) { + params.progressCallback = ^(NSNumber* contentLength, NSNumber* bytesWritten) { + if (self.bridge != nil) + [self sendEventWithName:@"DownloadProgress" + body:@{@"jobId": jobId, + @"contentLength": contentLength, + @"bytesWritten": bytesWritten}]; + }; + } + + if (hasResumableCallback) { params.resumableCallback = ^() { if (self.bridge != nil) [self sendEventWithName:@"DownloadResumable" body:nil]; }; + } if (!self.downloaders) self.downloaders = [[NSMutableDictionary alloc] init]; @@ -560,7 +569,7 @@ + (BOOL)requiresMainQueueSetup RCT_EXPORT_METHOD(resumeDownload:(nonnull NSNumber *)jobId) { RNFSDownloader* downloader = [self.downloaders objectForKey:[jobId stringValue]]; - + if (downloader != nil) { [downloader resumeDownload]; } @@ -572,7 +581,7 @@ + (BOOL)requiresMainQueueSetup ) { RNFSDownloader* downloader = [self.downloaders objectForKey:[jobId stringValue]]; - + if (downloader != nil) { resolve([NSNumber numberWithBool:[downloader isResumable]]); } else { @@ -605,13 +614,14 @@ + (BOOL)requiresMainQueueSetup params.toUrl = options[@"toUrl"]; params.files = options[@"files"]; params.binaryStreamOnly = [[options objectForKey:@"binaryStreamOnly"] boolValue]; - NSDictionary* headers = options[@"headers"]; NSDictionary* fields = options[@"fields"]; NSString* method = options[@"method"]; params.headers = headers; params.fields = fields; params.method = method; + bool hasBeginCallback = [options[@"hasBeginCallback"] boolValue]; + bool hasProgressCallback = [options[@"hasProgressCallback"] boolValue]; params.completeCallback = ^(NSString* body, NSURLResponse *resp) { [self.uploaders removeObjectForKey:[jobId stringValue]]; @@ -630,19 +640,23 @@ + (BOOL)requiresMainQueueSetup return [self reject:reject withError:error]; }; - params.beginCallback = ^() { - if (self.bridge != nil) - [self sendEventWithName:@"UploadBegin" - body:@{@"jobId": jobId}]; - }; + if (hasBeginCallback) { + params.beginCallback = ^() { + if (self.bridge != nil) + [self sendEventWithName:@"UploadBegin" + body:@{@"jobId": jobId}]; + }; + } - params.progressCallback = ^(NSNumber* totalBytesExpectedToSend, NSNumber* totalBytesSent) { - if (self.bridge != nil) - [self sendEventWithName:@"UploadProgress" - body:@{@"jobId": jobId, - @"totalBytesExpectedToSend": totalBytesExpectedToSend, - @"totalBytesSent": totalBytesSent}]; - }; + if (hasProgressCallback) { + params.progressCallback = ^(NSNumber* totalBytesExpectedToSend, NSNumber* totalBytesSent) { + if (self.bridge != nil) + [self sendEventWithName:@"UploadProgress" + body:@{@"jobId": jobId, + @"totalBytesExpectedToSend": totalBytesExpectedToSend, + @"totalBytesSent": totalBytesSent}]; + }; + } if (!self.uploaders) self.uploaders = [[NSMutableDictionary alloc] init]; @@ -840,15 +854,15 @@ + (BOOL)requiresMainQueueSetup //unused? //__block NSURL* videoURL = [NSURL URLWithString:destination]; __block NSError *error = nil; - + PHFetchResult *phAssetFetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil]; PHAsset *phAsset = [phAssetFetchResult firstObject]; - + PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; options.networkAccessAllowed = YES; options.version = PHVideoRequestOptionsVersionOriginal; options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; - + dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); diff --git a/Uploader.m b/Uploader.m index 4be87362..afc0d644 100644 --- a/Uploader.m +++ b/Uploader.m @@ -86,7 +86,7 @@ - (void)uploadFiles:(RNFSUploadParams*)params } [reqBody appendData:[[NSString stringWithFormat:@"Content-Length: %ld\r\n\r\n", (long)[fileData length]] dataUsingEncoding:NSUTF8StringEncoding]]; } - + [reqBody appendData:fileData]; if (!binaryStreamOnly) { [reqBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; @@ -109,7 +109,9 @@ - (void)uploadFiles:(RNFSUploadParams*)params return self->_params.completeCallback(str, response); }]; [_task resume]; - _params.beginCallback(); + if (_params.beginCallback) { + _params.beginCallback(); + } } - (NSString *)generateBoundaryString @@ -139,7 +141,9 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didComp - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(NSInteger)totalBytesExpectedToSend { - return _params.progressCallback([NSNumber numberWithLongLong:totalBytesExpectedToSend], [NSNumber numberWithLongLong:totalBytesSent]); + if (_params.progressCallback) { + _params.progressCallback([NSNumber numberWithLongLong:totalBytesExpectedToSend], [NSNumber numberWithLongLong:totalBytesSent]); + } } - (void)stopUpload diff --git a/android/src/main/java/com/rnfs/Downloader.java b/android/src/main/java/com/rnfs/Downloader.java index de5b117a..4da698eb 100644 --- a/android/src/main/java/com/rnfs/Downloader.java +++ b/android/src/main/java/com/rnfs/Downloader.java @@ -97,7 +97,9 @@ private void download(DownloadParams param, DownloadResult res) throws Exception } } - mParam.onDownloadBegin.onDownloadBegin(statusCode, lengthOfFile, headersFlat); + if (mParam.onDownloadBegin != null) { + mParam.onDownloadBegin.onDownloadBegin(statusCode, lengthOfFile, headersFlat); + } input = new BufferedInputStream(connection.getInputStream(), 8 * 1024); output = new FileOutputStream(param.dest); @@ -107,29 +109,34 @@ private void download(DownloadParams param, DownloadResult res) throws Exception int count; double lastProgressValue = 0; long lastProgressEmitTimestamp = 0; + boolean hasProgressCallback = mParam.onDownloadProgress != null; while ((count = input.read(data)) != -1) { if (mAbort.get()) throw new Exception("Download has been aborted"); total += count; - if (param.progressInterval > 0) { - long timestamp = System.currentTimeMillis(); - if (timestamp - lastProgressEmitTimestamp > param.progressInterval) { - lastProgressEmitTimestamp = timestamp; - publishProgress(new long[]{lengthOfFile, total}); - } - } else if (param.progressDivider <= 0) { - publishProgress(new long[]{lengthOfFile, total}); - } else { - double progress = Math.round(((double) total * 100) / lengthOfFile); - if (progress % param.progressDivider == 0) { - if ((progress != lastProgressValue) || (total == lengthOfFile)) { - Log.d("Downloader", "EMIT: " + String.valueOf(progress) + ", TOTAL:" + String.valueOf(total)); - lastProgressValue = progress; + + if (hasProgressCallback) { + if (param.progressInterval > 0) { + long timestamp = System.currentTimeMillis(); + if (timestamp - lastProgressEmitTimestamp > param.progressInterval) { + lastProgressEmitTimestamp = timestamp; publishProgress(new long[]{lengthOfFile, total}); } + } else if (param.progressDivider <= 0) { + publishProgress(new long[]{lengthOfFile, total}); + } else { + double progress = Math.round(((double) total * 100) / lengthOfFile); + if (progress % param.progressDivider == 0) { + if ((progress != lastProgressValue) || (total == lengthOfFile)) { + Log.d("Downloader", "EMIT: " + String.valueOf(progress) + ", TOTAL:" + String.valueOf(total)); + lastProgressValue = progress; + publishProgress(new long[]{lengthOfFile, total}); + } + } } } + output.write(data, 0, count); } @@ -158,7 +165,9 @@ protected void stop() { @Override protected void onProgressUpdate(long[]... values) { super.onProgressUpdate(values); - mParam.onDownloadProgress.onDownloadProgress(values[0][0], values[0][1]); + if (mParam.onDownloadProgress != null) { + mParam.onDownloadProgress.onDownloadProgress(values[0][0], values[0][1]); + } } protected void onPostExecute(Exception ex) { diff --git a/android/src/main/java/com/rnfs/RNFSManager.java b/android/src/main/java/com/rnfs/RNFSManager.java index 5c149868..1fd3fd20 100755 --- a/android/src/main/java/com/rnfs/RNFSManager.java +++ b/android/src/main/java/com/rnfs/RNFSManager.java @@ -702,6 +702,8 @@ public void downloadFile(final ReadableMap options, final Promise promise) { int progressDivider = options.getInt("progressDivider"); int readTimeout = options.getInt("readTimeout"); int connectionTimeout = options.getInt("connectionTimeout"); + boolean hasBeginCallback = options.getBoolean("hasBeginCallback"); + boolean hasProgressCallback = options.getBoolean("hasProgressCallback"); DownloadParams params = new DownloadParams(); @@ -729,36 +731,40 @@ public void onTaskCompleted(DownloadResult res) { } }; - params.onDownloadBegin = new DownloadParams.OnDownloadBegin() { - public void onDownloadBegin(int statusCode, long contentLength, Map headers) { - WritableMap headersMap = Arguments.createMap(); + if (hasBeginCallback) { + params.onDownloadBegin = new DownloadParams.OnDownloadBegin() { + public void onDownloadBegin(int statusCode, long contentLength, Map headers) { + WritableMap headersMap = Arguments.createMap(); - for (Map.Entry entry : headers.entrySet()) { - headersMap.putString(entry.getKey(), entry.getValue()); - } + for (Map.Entry entry : headers.entrySet()) { + headersMap.putString(entry.getKey(), entry.getValue()); + } - WritableMap data = Arguments.createMap(); + WritableMap data = Arguments.createMap(); - data.putInt("jobId", jobId); - data.putInt("statusCode", statusCode); - data.putDouble("contentLength", (double)contentLength); - data.putMap("headers", headersMap); + data.putInt("jobId", jobId); + data.putInt("statusCode", statusCode); + data.putDouble("contentLength", (double)contentLength); + data.putMap("headers", headersMap); - sendEvent(getReactApplicationContext(), "DownloadBegin", data); - } - }; + sendEvent(getReactApplicationContext(), "DownloadBegin", data); + } + }; + } - params.onDownloadProgress = new DownloadParams.OnDownloadProgress() { - public void onDownloadProgress(long contentLength, long bytesWritten) { - WritableMap data = Arguments.createMap(); + if (hasProgressCallback) { + params.onDownloadProgress = new DownloadParams.OnDownloadProgress() { + public void onDownloadProgress(long contentLength, long bytesWritten) { + WritableMap data = Arguments.createMap(); - data.putInt("jobId", jobId); - data.putDouble("contentLength", (double)contentLength); - data.putDouble("bytesWritten", (double)bytesWritten); + data.putInt("jobId", jobId); + data.putDouble("contentLength", (double)contentLength); + data.putDouble("bytesWritten", (double)bytesWritten); - sendEvent(getReactApplicationContext(), "DownloadProgress", data); - } - }; + sendEvent(getReactApplicationContext(), "DownloadProgress", data); + } + }; + } Downloader downloader = new Downloader(); @@ -790,6 +796,9 @@ public void uploadFiles(final ReadableMap options, final Promise promise) { ReadableMap fields = options.getMap("fields"); String method = options.getString("method"); boolean binaryStreamOnly = options.getBoolean("binaryStreamOnly"); + boolean hasBeginCallback = options.getBoolean("hasBeginCallback"); + boolean hasProgressCallback = options.getBoolean("hasProgressCallback"); + ArrayList fileList = new ArrayList<>(); UploadParams params = new UploadParams(); for(int i =0;i