Refactored downloadFile, added stopDownload
This commit is contained in:
parent
de4f913bff
commit
b603084ce7
18
Downloader.h
18
Downloader.h
|
@ -1,10 +1,24 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef void (^DownloaderCallback)(NSNumber*, NSNumber*);
|
||||
typedef void (^ErrorCallback)(NSError*);
|
||||
typedef void (^DownloaderCallback)(NSNumber*, NSNumber*, NSNumber*);
|
||||
typedef void (^BeginCallback)(NSNumber*, NSNumber*, NSDictionary*);
|
||||
typedef void (^ProgressCallback)(NSNumber*, NSNumber*);
|
||||
|
||||
@interface DownloadParams : NSObject
|
||||
|
||||
@property (copy) NSString* fromUrl;
|
||||
@property (copy) NSString* toFile;
|
||||
@property (copy) DownloaderCallback callback; // Download has finished (data written)
|
||||
@property (copy) ErrorCallback errorCallback; // Something went wrong
|
||||
@property (copy) BeginCallback beginCallback; // Download has started (headers received)
|
||||
@property (copy) ProgressCallback progressCallback; // Download is progressing
|
||||
|
||||
@end
|
||||
|
||||
@interface Downloader : NSObject <NSURLConnectionDelegate>
|
||||
|
||||
- (void)downloadFile:(NSString*)urlStr toFile:(NSString*)downloadPath callback:(DownloaderCallback)callback errorCallback:(ErrorCallback)errorCallback progressCallback:(DownloaderCallback)progressCallback;
|
||||
- (void)downloadFile:(DownloadParams*)params;
|
||||
- (void)stopDownload;
|
||||
|
||||
@end
|
||||
|
|
46
Downloader.m
46
Downloader.m
|
@ -1,11 +1,14 @@
|
|||
#import "Downloader.h"
|
||||
|
||||
@implementation DownloadParams
|
||||
|
||||
@end
|
||||
|
||||
@interface Downloader()
|
||||
|
||||
@property (copy) DownloaderCallback callback;
|
||||
@property (copy) ErrorCallback errorCallback;
|
||||
@property (copy) DownloaderCallback progressCallback;
|
||||
@property (copy) DownloadParams* params;
|
||||
|
||||
@property (retain) NSURLConnection* connection;
|
||||
@property (retain) NSNumber* statusCode;
|
||||
@property (retain) NSNumber* contentLength;
|
||||
@property (retain) NSNumber* bytesWritten;
|
||||
|
@ -16,42 +19,40 @@
|
|||
|
||||
@implementation Downloader
|
||||
|
||||
- (void)downloadFile:(NSString*)urlStr toFile:(NSString*)downloadPath callback:(DownloaderCallback)callback errorCallback:(ErrorCallback)errorCallback progressCallback:(DownloaderCallback)progressCallback
|
||||
- (void)downloadFile:(DownloadParams*)params
|
||||
{
|
||||
_callback = callback;
|
||||
_errorCallback = errorCallback;
|
||||
_progressCallback = progressCallback;
|
||||
|
||||
_params = params;
|
||||
|
||||
_bytesWritten = 0;
|
||||
|
||||
NSURL* url = [NSURL URLWithString:urlStr];
|
||||
NSURL* url = [NSURL URLWithString:_params.fromUrl];
|
||||
|
||||
NSMutableURLRequest* downloadRequest = [NSMutableURLRequest requestWithURL:url
|
||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval:30];
|
||||
|
||||
[[NSFileManager defaultManager] createFileAtPath:downloadPath contents:nil attributes:nil];
|
||||
[[NSFileManager defaultManager] createFileAtPath:_params.toFile contents:nil attributes:nil];
|
||||
|
||||
_fileHandle = [NSFileHandle fileHandleForWritingAtPath:downloadPath];
|
||||
_fileHandle = [NSFileHandle fileHandleForWritingAtPath:_params.toFile];
|
||||
|
||||
if (!_fileHandle) {
|
||||
NSError* error = [NSError errorWithDomain:@"Downloader" code:NSURLErrorFileDoesNotExist userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"Failed to create target file at path: %@", downloadPath]}];
|
||||
NSError* error = [NSError errorWithDomain:@"Downloader" code:NSURLErrorFileDoesNotExist userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"Failed to create target file at path: %@", _params.toFile]}];
|
||||
|
||||
return _errorCallback(error);
|
||||
return _params.errorCallback(error);
|
||||
}
|
||||
|
||||
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:downloadRequest delegate:self startImmediately:NO];
|
||||
_connection = [[NSURLConnection alloc] initWithRequest:downloadRequest delegate:self startImmediately:NO];
|
||||
|
||||
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
[_connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
|
||||
[connection start];
|
||||
[_connection start];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
|
||||
{
|
||||
[_fileHandle closeFile];
|
||||
|
||||
return _errorCallback(error);
|
||||
return _params.errorCallback(error);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
|
||||
|
@ -60,6 +61,8 @@
|
|||
|
||||
_statusCode = [NSNumber numberWithLong:httpUrlResponse.statusCode];
|
||||
_contentLength = [NSNumber numberWithLong: httpUrlResponse.expectedContentLength];
|
||||
|
||||
return _params.beginCallback(_statusCode, _contentLength, httpUrlResponse.allHeaderFields);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
|
||||
|
@ -69,7 +72,7 @@
|
|||
|
||||
_bytesWritten = [NSNumber numberWithUnsignedInteger:[_bytesWritten unsignedIntegerValue] + data.length];
|
||||
|
||||
return _progressCallback(_statusCode, _contentLength, _bytesWritten);
|
||||
return _params.progressCallback(_contentLength, _bytesWritten);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +80,12 @@
|
|||
{
|
||||
[_fileHandle closeFile];
|
||||
|
||||
return _callback(_statusCode, _contentLength, _bytesWritten);
|
||||
return _params.callback(_statusCode, _bytesWritten);
|
||||
}
|
||||
|
||||
- (void)stopDownload
|
||||
{
|
||||
[_connection cancel];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
19
FS.common.js
19
FS.common.js
|
@ -138,19 +138,30 @@ var RNFS = {
|
|||
.catch(convertError);
|
||||
},
|
||||
|
||||
downloadFile(url, filepath, progress) {
|
||||
downloadFile(fromUrl, toFile, begin, progress) {
|
||||
var jobId = getJobId();
|
||||
var subscriptionIos, subscriptionAndroid;
|
||||
|
||||
if (progress) {
|
||||
if (!begin) begin = (info) => {
|
||||
console.log('Download begun:', info);
|
||||
};
|
||||
|
||||
if (begin) {
|
||||
// Two different styles of subscribing to events for different platforms, hmmm....
|
||||
if (NativeAppEventEmitter.addListener)
|
||||
subscriptionIos = NativeAppEventEmitter.addListener('DownloadProgress-' + jobId, progress);
|
||||
subscriptionIos = NativeAppEventEmitter.addListener('DownloadBegin-' + jobId, begin);
|
||||
if (DeviceEventEmitter.addListener)
|
||||
subscriptionAndroid = DeviceEventEmitter.addListener('DownloadBegin-' + jobId, begin);
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
if (NativeAppEventEmitter.addListener)
|
||||
subscriptionIos = NativeAppEventEmitter.addListener('DownloadProgress-' + jobId, progress);
|
||||
if (DeviceEventEmitter.addListener)
|
||||
subscriptionAndroid = DeviceEventEmitter.addListener('DownloadProgress-' + jobId, progress);
|
||||
}
|
||||
|
||||
return _downloadFile(url, filepath, jobId)
|
||||
return _downloadFile(fromUrl, toFile, jobId)
|
||||
.then(res => {
|
||||
if (subscriptionIos) subscriptionIos.remove();
|
||||
if (subscriptionAndroid) subscriptionAndroid.remove();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8BF740771C033A2E0057A1E7 /* Downloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF740761C033A2E0057A1E7 /* Downloader.m */; };
|
||||
F1E59BDF1ADD662800ACA28A /* RNFSManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F1E59BDE1ADD662800ACA28A /* RNFSManager.m */; };
|
||||
F1EB08BB1AFD0E6A008F8F2B /* NSArray+Map.m in Sources */ = {isa = PBXBuildFile; fileRef = F1EB08BA1AFD0E6A008F8F2B /* NSArray+Map.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
@ -24,6 +25,8 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
8BF740751C033A2E0057A1E7 /* Downloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Downloader.h; sourceTree = "<group>"; };
|
||||
8BF740761C033A2E0057A1E7 /* Downloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Downloader.m; sourceTree = "<group>"; };
|
||||
F12AFB9B1ADAF8F800E0535D /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFS.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F1E59BDD1ADD662800ACA28A /* RNFSManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNFSManager.h; sourceTree = "<group>"; };
|
||||
F1E59BDE1ADD662800ACA28A /* RNFSManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFSManager.m; sourceTree = "<group>"; };
|
||||
|
@ -49,6 +52,8 @@
|
|||
F1EB08BA1AFD0E6A008F8F2B /* NSArray+Map.m */,
|
||||
F1E59BDD1ADD662800ACA28A /* RNFSManager.h */,
|
||||
F1E59BDE1ADD662800ACA28A /* RNFSManager.m */,
|
||||
8BF740751C033A2E0057A1E7 /* Downloader.h */,
|
||||
8BF740761C033A2E0057A1E7 /* Downloader.m */,
|
||||
F12AFB9C1ADAF8F800E0535D /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
|
@ -119,6 +124,7 @@
|
|||
files = (
|
||||
F1E59BDF1ADD662800ACA28A /* RNFSManager.m in Sources */,
|
||||
F1EB08BB1AFD0E6A008F8F2B /* NSArray+Map.m in Sources */,
|
||||
8BF740771C033A2E0057A1E7 /* Downloader.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
#import "Downloader.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
|
||||
@interface RNFSManager()
|
||||
|
||||
@property (retain) NSMutableDictionary* downloaders;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RNFSManager
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
@ -147,25 +153,52 @@ RCT_EXPORT_METHOD(downloadFile:(NSString *)urlStr
|
|||
jobId:(nonnull NSNumber *)jobId
|
||||
callback:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
|
||||
DownloadParams* params = [DownloadParams alloc];
|
||||
|
||||
params.fromUrl = urlStr;
|
||||
params.toFile = filepath;
|
||||
|
||||
DownloaderCallback downloaderSuccessCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSNumber* bytesWritten) {
|
||||
return callback(@[[NSNull null], [NSNumber numberWithBool:YES], filepath]);
|
||||
params.callback = ^(NSNumber* statusCode, NSNumber* bytesWritten) {
|
||||
return callback(@[[NSNull null], @{@"jobId": jobId,
|
||||
@"statusCode": statusCode,
|
||||
@"bytesWritten": bytesWritten}]);
|
||||
};
|
||||
|
||||
ErrorCallback downloaderErrorCallback = ^(NSError* error) {
|
||||
params.errorCallback = ^(NSError* error) {
|
||||
return callback([self makeErrorPayload:error]);
|
||||
};
|
||||
|
||||
DownloaderCallback downloaderProgressCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSNumber* bytesWritten) {
|
||||
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadProgress-%@", jobId]
|
||||
body:@{@"statusCode": statusCode,
|
||||
|
||||
params.beginCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSDictionary* headers) {
|
||||
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadBegin-%@", jobId]
|
||||
body:@{@"jobId": jobId,
|
||||
@"statusCode": statusCode,
|
||||
@"contentLength": contentLength,
|
||||
@"headers": headers}];
|
||||
};
|
||||
|
||||
params.progressCallback = ^(NSNumber* contentLength, NSNumber* bytesWritten) {
|
||||
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadProgress-%@", jobId]
|
||||
body:@{@"contentLength": contentLength,
|
||||
@"bytesWritten": bytesWritten}];
|
||||
};
|
||||
|
||||
if (self.downloaders) self.downloaders = [NSMutableDictionary alloc];
|
||||
|
||||
Downloader* downloader = [Downloader alloc];
|
||||
|
||||
[downloader downloadFile:urlStr toFile:filepath callback:downloaderSuccessCallback errorCallback:downloaderErrorCallback progressCallback:downloaderProgressCallback];
|
||||
[downloader downloadFile:params];
|
||||
|
||||
[self.downloaders setValue:downloader forKey:[jobId stringValue]];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(stopDownload:(NSNumber *)jobId)
|
||||
{
|
||||
Downloader* downloader = [self.downloaders objectForKey:[jobId stringValue]];
|
||||
|
||||
if (downloader != nil) {
|
||||
[downloader stopDownload];
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(pathForBundle:(NSString *)bundleNamed
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package com.rnfs;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public class DownloadParams {
|
||||
public interface OnTaskCompleted {
|
||||
void onTaskCompleted(DownloadResult res);
|
||||
}
|
||||
|
||||
public interface OnDownloadBegin {
|
||||
void onDownloadBegin(int statusCode, int contentLength, Map<String, String> headers);
|
||||
}
|
||||
|
||||
public interface OnDownloadProgress {
|
||||
void onDownloadProgress(int contentLength, int bytesWritten);
|
||||
}
|
||||
|
||||
public URL src;
|
||||
public File dest;
|
||||
public OnTaskCompleted onTaskCompleted;
|
||||
public OnDownloadBegin onDownloadBegin;
|
||||
public OnDownloadProgress onDownloadProgress;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.rnfs;
|
||||
|
||||
public class DownloadResult {
|
||||
public int statusCode;
|
||||
public int bytesWritten;
|
||||
public Exception exception;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package com.rnfs;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
public class Downloader extends AsyncTask<DownloadParams, int[], DownloadResult> {
|
||||
private DownloadParams mParam;
|
||||
private AtomicBoolean mAbort = new AtomicBoolean(false);
|
||||
|
||||
protected DownloadResult doInBackground(DownloadParams... params) {
|
||||
mParam = params[0];
|
||||
|
||||
DownloadResult res = new DownloadResult();
|
||||
|
||||
try {
|
||||
this.download(mParam, res);
|
||||
mParam.onTaskCompleted.onTaskCompleted(res);
|
||||
} catch (Exception ex) {
|
||||
res.exception = ex;
|
||||
mParam.onTaskCompleted.onTaskCompleted(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private void download(DownloadParams param, DownloadResult res) throws IOException {
|
||||
InputStream input = null;
|
||||
OutputStream output = null;
|
||||
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection)param.src.openConnection();
|
||||
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.connect();
|
||||
|
||||
int statusCode = connection.getResponseCode();
|
||||
int lengthOfFile = connection.getContentLength();
|
||||
|
||||
Map<String, List<String>> headers = connection.getHeaderFields();
|
||||
|
||||
Map<String, String> headersFlat = new HashMap<String, String>();
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
String headerKey = entry.getKey();
|
||||
String valueKey = entry.getValue().get(0);
|
||||
|
||||
if (headerKey != null && valueKey != null) {
|
||||
headersFlat.put(headerKey, valueKey);
|
||||
}
|
||||
}
|
||||
|
||||
mParam.onDownloadBegin.onDownloadBegin(statusCode, lengthOfFile, headersFlat);
|
||||
|
||||
input = new BufferedInputStream(param.src.openStream(), 8 * 1024);
|
||||
output = new FileOutputStream(param.dest);
|
||||
|
||||
byte data[] = new byte[8 * 1024];
|
||||
int total = 0;
|
||||
int count;
|
||||
|
||||
while ((count = input.read(data)) != -1) {
|
||||
if (mAbort.get()) {
|
||||
break;
|
||||
}
|
||||
|
||||
total += count;
|
||||
publishProgress(new int[] { lengthOfFile, total });
|
||||
output.write(data, 0, count);
|
||||
}
|
||||
|
||||
output.flush();
|
||||
|
||||
res.statusCode = statusCode;
|
||||
res.bytesWritten = total;
|
||||
} finally {
|
||||
if (output != null) output.close();
|
||||
if (input != null) input.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void stop() {
|
||||
mAbort.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(int[]... values) {
|
||||
super.onProgressUpdate(values);
|
||||
mParam.onDownloadProgress.onDownloadProgress(values[0][0], values[0][1]);
|
||||
}
|
||||
|
||||
protected void onPostExecute(Exception ex) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.rnfs;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
|
@ -9,6 +10,7 @@ import android.os.AsyncTask;
|
|||
import android.util.Base64;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -31,7 +33,6 @@ import com.facebook.react.bridge.ReadableMap;
|
|||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
public class RNFSManager extends ReactContextBaseJavaModule {
|
||||
|
@ -41,6 +42,8 @@ public class RNFSManager extends ReactContextBaseJavaModule {
|
|||
|
||||
private static final String NSFileTypeRegular = "NSFileTypeRegular";
|
||||
private static final String NSFileTypeDirectory = "NSFileTypeDirectory";
|
||||
|
||||
private SparseArray<Downloader> downloaders = new SparseArray<Downloader>();
|
||||
|
||||
public RNFSManager(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
|
@ -182,8 +185,8 @@ public class RNFSManager extends ReactContextBaseJavaModule {
|
|||
|
||||
private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
|
||||
reactContext
|
||||
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||
.emit(eventName, params);
|
||||
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||
.emit(eventName, params);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
|
@ -193,110 +196,72 @@ public class RNFSManager extends ReactContextBaseJavaModule {
|
|||
URL url = new URL(urlStr);
|
||||
|
||||
DownloadParams params = new DownloadParams();
|
||||
|
||||
params.src = url;
|
||||
params.dest = file;
|
||||
params.onTaskCompleted = new OnTaskCompleted() {
|
||||
public void onTaskCompleted(Exception ex) {
|
||||
if (ex == null) {
|
||||
boolean success = true;
|
||||
callback.invoke(null, success, filepath);
|
||||
|
||||
params.onTaskCompleted = new DownloadParams.OnTaskCompleted() {
|
||||
public void onTaskCompleted(DownloadResult res) {
|
||||
if (res.exception == null) {
|
||||
WritableMap infoMap = Arguments.createMap();
|
||||
|
||||
infoMap.putInt("jobId", jobId);
|
||||
infoMap.putInt("statusCode", res.statusCode);
|
||||
infoMap.putInt("bytesWritten", res.bytesWritten);
|
||||
|
||||
callback.invoke(null, infoMap);
|
||||
} else {
|
||||
callback.invoke(makeErrorPayload(ex));
|
||||
callback.invoke(makeErrorPayload(res.exception));
|
||||
}
|
||||
}
|
||||
};
|
||||
params.onDownloadProgress = new OnDownloadProgress() {
|
||||
public void onDownloadProgress(int statusCode, int contentLength, int bytesWritten) {
|
||||
|
||||
params.onDownloadBegin = new DownloadParams.OnDownloadBegin() {
|
||||
public void onDownloadBegin(int statusCode, int contentLength, Map<String, String> headers) {
|
||||
WritableMap headersMap = Arguments.createMap();
|
||||
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
headersMap.putString(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
WritableMap data = Arguments.createMap();
|
||||
|
||||
data.putInt("jobId", jobId);
|
||||
data.putInt("statusCode", statusCode);
|
||||
data.putInt("contentLength", contentLength);
|
||||
data.putMap("headers", headersMap);
|
||||
|
||||
sendEvent(getReactApplicationContext(), "DownloadBegin-" + jobId, data);
|
||||
}
|
||||
};
|
||||
|
||||
params.onDownloadProgress = new DownloadParams.OnDownloadProgress() {
|
||||
public void onDownloadProgress(int contentLength, int bytesWritten) {
|
||||
WritableMap data = Arguments.createMap();
|
||||
data.putInt("contentLength", contentLength);
|
||||
data.putInt("bytesWritten", bytesWritten);
|
||||
|
||||
sendEvent(getReactApplicationContext(), "DownloadProgress-" + jobId, data);
|
||||
}
|
||||
};
|
||||
|
||||
DownloadTask downloadTask = new DownloadTask();
|
||||
downloadTask.execute(params);
|
||||
Downloader downloader = new Downloader();
|
||||
|
||||
downloader.execute(params);
|
||||
|
||||
this.downloaders.put(jobId, downloader);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
callback.invoke(makeErrorPayload(ex));
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadParams {
|
||||
public URL src;
|
||||
public File dest;
|
||||
public OnTaskCompleted onTaskCompleted;
|
||||
public OnDownloadProgress onDownloadProgress;
|
||||
}
|
||||
|
||||
public interface OnTaskCompleted {
|
||||
void onTaskCompleted(Exception ex);
|
||||
}
|
||||
|
||||
public interface OnDownloadProgress {
|
||||
void onDownloadProgress(int statusCode, int contentLength, int bytesWritten);
|
||||
}
|
||||
|
||||
private class DownloadTask extends AsyncTask<DownloadParams, int[], Exception> {
|
||||
private DownloadParams mParam;
|
||||
|
||||
protected Exception doInBackground(DownloadParams... params) {
|
||||
mParam = params[0];
|
||||
|
||||
try {
|
||||
this.download(mParam);
|
||||
mParam.onTaskCompleted.onTaskCompleted(null);
|
||||
} catch (Exception ex) {
|
||||
mParam.onTaskCompleted.onTaskCompleted(ex);
|
||||
return ex;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void download(DownloadParams param) throws IOException {
|
||||
InputStream input = null;
|
||||
OutputStream output = null;
|
||||
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection)param.src.openConnection();
|
||||
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.connect();
|
||||
|
||||
int statusCode = connection.getResponseCode();
|
||||
int lengthOfFile = connection.getContentLength();
|
||||
|
||||
input = new BufferedInputStream(param.src.openStream(), 8 * 1024);
|
||||
output = new FileOutputStream(param.dest);
|
||||
|
||||
byte data[] = new byte[8 * 1024];
|
||||
int total = 0;
|
||||
int count;
|
||||
|
||||
while ((count = input.read(data)) != -1) {
|
||||
total += count;
|
||||
publishProgress(new int[] { statusCode, lengthOfFile, total });
|
||||
output.write(data, 0, count);
|
||||
}
|
||||
|
||||
output.flush();
|
||||
} finally {
|
||||
if (output != null) output.close();
|
||||
if (input != null) input.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(int[]... values) {
|
||||
super.onProgressUpdate(values);
|
||||
mParam.onDownloadProgress.onDownloadProgress(values[0][0], values[0][1], values[0][2]);
|
||||
}
|
||||
|
||||
protected void onPostExecute(Exception ex) {
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void stopDownload(int jobId) {
|
||||
Downloader downloader = this.downloaders.get(jobId);
|
||||
|
||||
if (downloader != null) {
|
||||
downloader.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue