From dc84759aa66e4c75ddb6171d2612dae48b234b89 Mon Sep 17 00:00:00 2001 From: Sergius Beller Date: Thu, 18 Jul 2019 16:18:21 +0200 Subject: [PATCH] Add option progressInterval for downloadFile --- Downloader.h | 1 + Downloader.m | 10 +++++++++- FS.common.js | 3 +++ README.md | 4 ++++ RNFSManager.m | 2 ++ android/src/main/java/com/rnfs/DownloadParams.java | 1 + android/src/main/java/com/rnfs/Downloader.java | 11 +++++++++-- android/src/main/java/com/rnfs/RNFSManager.java | 2 ++ index.d.ts | 1 + 9 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Downloader.h b/Downloader.h index 9c0a6031..e22478c1 100644 --- a/Downloader.h +++ b/Downloader.h @@ -19,6 +19,7 @@ typedef void (^ResumableCallback)(); @property bool background; // Whether to continue download when app is in background @property bool discretionary; // Whether the file may be downloaded at the OS's discretion (iOS only) @property bool cacheable; // Whether the file may be stored in the shared NSURLCache (iOS only) +@property (copy) NSNumber* progressInterval; @property (copy) NSNumber* progressDivider; @property (copy) NSNumber* readTimeout; diff --git a/Downloader.m b/Downloader.m index 91ba9883..6e9c4d3e 100644 --- a/Downloader.m +++ b/Downloader.m @@ -11,6 +11,7 @@ @interface RNFSDownloader() @property (retain) NSURLSession* session; @property (retain) NSURLSessionDownloadTask* task; @property (retain) NSNumber* statusCode; +@property (assign) NSTimeInterval lastProgressEmitTimestamp; @property (retain) NSNumber* lastProgressValue; @property (retain) NSNumber* contentLength; @property (retain) NSNumber* bytesWritten; @@ -28,6 +29,7 @@ - (NSString *)downloadFile:(RNFSDownloadParams*)params _params = params; + _lastProgressEmitTimestamp = 0; _bytesWritten = 0; NSURL* url = [NSURL URLWithString:_params.fromUrl]; @@ -81,7 +83,13 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas if ([_statusCode isEqualToNumber:[NSNumber numberWithInt:200]]) { _bytesWritten = @(totalBytesWritten); - if (_params.progressDivider.integerValue <= 0) { + if(_params.progressInterval.integerValue > 0){ + NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970]; + if(timestamp - _lastProgressEmitTimestamp > _params.progressInterval.integerValue / 1000.0){ + _lastProgressEmitTimestamp = timestamp; + return _params.progressCallback(_contentLength, _bytesWritten); + } + }else if (_params.progressDivider.integerValue <= 0) { return _params.progressCallback(_contentLength, _bytesWritten); } else { double doubleBytesWritten = (double)[_bytesWritten longValue]; diff --git a/FS.common.js b/FS.common.js index d8ba4e45..b9b4b445 100755 --- a/FS.common.js +++ b/FS.common.js @@ -68,6 +68,7 @@ type DownloadFileOptions = { background?: boolean; // Continue the download in the background after the app terminates (iOS only) discretionary?: boolean; // Allow the OS to control the timing and speed of the download to improve perceived performance (iOS only) cacheable?: boolean; // Whether the download can be stored in the shared NSURLCache (iOS only) + progressInterval?: number; progressDivider?: number; begin?: (res: DownloadBeginCallbackResult) => void; progress?: (res: DownloadProgressCallbackResult) => void; @@ -487,6 +488,7 @@ var RNFS = { if (options.headers && typeof options.headers !== 'object') throw new Error('downloadFile: Invalid value for property `headers`'); if (options.background && typeof options.background !== 'boolean') throw new Error('downloadFile: Invalid value for property `background`'); if (options.progressDivider && typeof options.progressDivider !== 'number') throw new Error('downloadFile: Invalid value for property `progressDivider`'); + if (options.progressInterval && typeof options.progressInterval !== 'number') throw new Error('downloadFile: Invalid value for property `progressInterval`'); if (options.readTimeout && typeof options.readTimeout !== 'number') throw new Error('downloadFile: Invalid value for property `readTimeout`'); if (options.connectionTimeout && typeof options.connectionTimeout !== 'number') throw new Error('downloadFile: Invalid value for property `connectionTimeout`'); @@ -512,6 +514,7 @@ var RNFS = { headers: options.headers || {}, background: !!options.background, progressDivider: options.progressDivider || 0, + progressInterval: options.progressInterval || 0, readTimeout: options.readTimeout || 15000, connectionTimeout: options.connectionTimeout || 5000 }; diff --git a/README.md b/README.md index b3ef5471..e020b3ed 100644 --- a/README.md +++ b/README.md @@ -505,6 +505,7 @@ type DownloadFileOptions = { background?: boolean; // Continue the download in the background after the app terminates (iOS only) discretionary?: boolean; // Allow the OS to control the timing and speed of the download to improve perceived performance (iOS only) cacheable?: boolean; // Whether the download can be stored in the shared NSURLCache (iOS only, defaults to true) + progressInterval?: number; progressDivider?: number; begin?: (res: DownloadBeginCallbackResult) => void; progress?: (res: DownloadProgressCallbackResult) => void; @@ -544,6 +545,9 @@ type DownloadProgressCallbackResult = { }; ``` +If `options.progressInterval` is provided, it will return progress events in the maximum frequency of `progressDivider`. +For example, if `progressInterval` = 100, you will not receive callbacks more often than every 100th millisecond. + If `options.progressDivider` is provided, it will return progress events that divided by `progressDivider`. For example, if `progressDivider` = 10, you will receive only ten callbacks for this values of progress: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 diff --git a/RNFSManager.m b/RNFSManager.m index 68a0d810..8b21ac7c 100755 --- a/RNFSManager.m +++ b/RNFSManager.m @@ -469,6 +469,8 @@ + (BOOL)requiresMainQueueSetup params.discretionary = [discretionary boolValue]; NSNumber* cacheable = options[@"cacheable"]; params.cacheable = cacheable ? [cacheable boolValue] : YES; + NSNumber* progressInterval= options[@"progressInterval"]; + params.progressInterval = progressInterval; NSNumber* progressDivider = options[@"progressDivider"]; params.progressDivider = progressDivider; NSNumber* readTimeout = options[@"readTimeout"]; diff --git a/android/src/main/java/com/rnfs/DownloadParams.java b/android/src/main/java/com/rnfs/DownloadParams.java index 32a81aac..18658c39 100644 --- a/android/src/main/java/com/rnfs/DownloadParams.java +++ b/android/src/main/java/com/rnfs/DownloadParams.java @@ -22,6 +22,7 @@ public interface OnDownloadProgress { public URL src; public File dest; public ReadableMap headers; + public int progressInterval; public float progressDivider; public int readTimeout; public int connectionTimeout; diff --git a/android/src/main/java/com/rnfs/Downloader.java b/android/src/main/java/com/rnfs/Downloader.java index 3764bd17..2a653439 100644 --- a/android/src/main/java/com/rnfs/Downloader.java +++ b/android/src/main/java/com/rnfs/Downloader.java @@ -110,12 +110,19 @@ private void download(DownloadParams param, DownloadResult res) throws Exception long total = 0; int count; double lastProgressValue = 0; + long lastProgressEmitTimestamp = 0; while ((count = input.read(data)) != -1) { if (mAbort.get()) throw new Exception("Download has been aborted"); total += count; - if (param.progressDivider <= 0) { + 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); @@ -134,7 +141,7 @@ private void download(DownloadParams param, DownloadResult res) throws Exception res.bytesWritten = total; } res.statusCode = statusCode; - } finally { + } finally { if (output != null) output.close(); if (input != null) input.close(); if (connection != null) connection.disconnect(); diff --git a/android/src/main/java/com/rnfs/RNFSManager.java b/android/src/main/java/com/rnfs/RNFSManager.java index a605d2ca..0af8fd51 100755 --- a/android/src/main/java/com/rnfs/RNFSManager.java +++ b/android/src/main/java/com/rnfs/RNFSManager.java @@ -699,6 +699,7 @@ public void downloadFile(final ReadableMap options, final Promise promise) { URL url = new URL(options.getString("fromUrl")); final int jobId = options.getInt("jobId"); ReadableMap headers = options.getMap("headers"); + int progressInterval = options.getInt("progressInterval"); int progressDivider = options.getInt("progressDivider"); int readTimeout = options.getInt("readTimeout"); int connectionTimeout = options.getInt("connectionTimeout"); @@ -708,6 +709,7 @@ public void downloadFile(final ReadableMap options, final Promise promise) { params.src = url; params.dest = file; params.headers = headers; + params.progressInterval = progressInterval; params.progressDivider = progressDivider; params.readTimeout = readTimeout; params.connectionTimeout = connectionTimeout; diff --git a/index.d.ts b/index.d.ts index 7d90d44b..959ced2b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -39,6 +39,7 @@ type DownloadFileOptions = { background?: boolean // Continue the download in the background after the app terminates (iOS only) discretionary?: boolean // Allow the OS to control the timing and speed of the download to improve perceived performance (iOS only) cacheable?: boolean // Whether the download can be stored in the shared NSURLCache (iOS only) + progressInterval: number progressDivider?: number begin?: (res: DownloadBeginCallbackResult) => void progress?: (res: DownloadProgressCallbackResult) => void