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>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
typedef void (^DownloaderCallback)(NSNumber*, NSNumber*);
|
||||||
typedef void (^ErrorCallback)(NSError*);
|
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>
|
@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
|
@end
|
||||||
|
|
44
Downloader.m
44
Downloader.m
|
@ -1,11 +1,14 @@
|
||||||
#import "Downloader.h"
|
#import "Downloader.h"
|
||||||
|
|
||||||
|
@implementation DownloadParams
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface Downloader()
|
@interface Downloader()
|
||||||
|
|
||||||
@property (copy) DownloaderCallback callback;
|
@property (copy) DownloadParams* params;
|
||||||
@property (copy) ErrorCallback errorCallback;
|
|
||||||
@property (copy) DownloaderCallback progressCallback;
|
|
||||||
|
|
||||||
|
@property (retain) NSURLConnection* connection;
|
||||||
@property (retain) NSNumber* statusCode;
|
@property (retain) NSNumber* statusCode;
|
||||||
@property (retain) NSNumber* contentLength;
|
@property (retain) NSNumber* contentLength;
|
||||||
@property (retain) NSNumber* bytesWritten;
|
@property (retain) NSNumber* bytesWritten;
|
||||||
|
@ -16,42 +19,40 @@
|
||||||
|
|
||||||
@implementation Downloader
|
@implementation Downloader
|
||||||
|
|
||||||
- (void)downloadFile:(NSString*)urlStr toFile:(NSString*)downloadPath callback:(DownloaderCallback)callback errorCallback:(ErrorCallback)errorCallback progressCallback:(DownloaderCallback)progressCallback
|
- (void)downloadFile:(DownloadParams*)params
|
||||||
{
|
{
|
||||||
_callback = callback;
|
_params = params;
|
||||||
_errorCallback = errorCallback;
|
|
||||||
_progressCallback = progressCallback;
|
|
||||||
|
|
||||||
_bytesWritten = 0;
|
_bytesWritten = 0;
|
||||||
|
|
||||||
NSURL* url = [NSURL URLWithString:urlStr];
|
NSURL* url = [NSURL URLWithString:_params.fromUrl];
|
||||||
|
|
||||||
NSMutableURLRequest* downloadRequest = [NSMutableURLRequest requestWithURL:url
|
NSMutableURLRequest* downloadRequest = [NSMutableURLRequest requestWithURL:url
|
||||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||||
timeoutInterval:30];
|
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) {
|
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
|
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
|
||||||
{
|
{
|
||||||
[_fileHandle closeFile];
|
[_fileHandle closeFile];
|
||||||
|
|
||||||
return _errorCallback(error);
|
return _params.errorCallback(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
|
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
|
||||||
|
@ -60,6 +61,8 @@
|
||||||
|
|
||||||
_statusCode = [NSNumber numberWithLong:httpUrlResponse.statusCode];
|
_statusCode = [NSNumber numberWithLong:httpUrlResponse.statusCode];
|
||||||
_contentLength = [NSNumber numberWithLong: httpUrlResponse.expectedContentLength];
|
_contentLength = [NSNumber numberWithLong: httpUrlResponse.expectedContentLength];
|
||||||
|
|
||||||
|
return _params.beginCallback(_statusCode, _contentLength, httpUrlResponse.allHeaderFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
|
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
|
||||||
|
@ -69,7 +72,7 @@
|
||||||
|
|
||||||
_bytesWritten = [NSNumber numberWithUnsignedInteger:[_bytesWritten unsignedIntegerValue] + data.length];
|
_bytesWritten = [NSNumber numberWithUnsignedInteger:[_bytesWritten unsignedIntegerValue] + data.length];
|
||||||
|
|
||||||
return _progressCallback(_statusCode, _contentLength, _bytesWritten);
|
return _params.progressCallback(_contentLength, _bytesWritten);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +80,12 @@
|
||||||
{
|
{
|
||||||
[_fileHandle closeFile];
|
[_fileHandle closeFile];
|
||||||
|
|
||||||
return _callback(_statusCode, _contentLength, _bytesWritten);
|
return _params.callback(_statusCode, _bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopDownload
|
||||||
|
{
|
||||||
|
[_connection cancel];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
19
FS.common.js
19
FS.common.js
|
@ -138,19 +138,30 @@ var RNFS = {
|
||||||
.catch(convertError);
|
.catch(convertError);
|
||||||
},
|
},
|
||||||
|
|
||||||
downloadFile(url, filepath, progress) {
|
downloadFile(fromUrl, toFile, begin, progress) {
|
||||||
var jobId = getJobId();
|
var jobId = getJobId();
|
||||||
var subscriptionIos, subscriptionAndroid;
|
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....
|
// Two different styles of subscribing to events for different platforms, hmmm....
|
||||||
if (NativeAppEventEmitter.addListener)
|
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)
|
if (NativeAppEventEmitter.addListener)
|
||||||
|
subscriptionIos = NativeAppEventEmitter.addListener('DownloadProgress-' + jobId, progress);
|
||||||
|
if (DeviceEventEmitter.addListener)
|
||||||
subscriptionAndroid = DeviceEventEmitter.addListener('DownloadProgress-' + jobId, progress);
|
subscriptionAndroid = DeviceEventEmitter.addListener('DownloadProgress-' + jobId, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _downloadFile(url, filepath, jobId)
|
return _downloadFile(fromUrl, toFile, jobId)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (subscriptionIos) subscriptionIos.remove();
|
if (subscriptionIos) subscriptionIos.remove();
|
||||||
if (subscriptionAndroid) subscriptionAndroid.remove();
|
if (subscriptionAndroid) subscriptionAndroid.remove();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* 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 */; };
|
F1E59BDF1ADD662800ACA28A /* RNFSManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F1E59BDE1ADD662800ACA28A /* RNFSManager.m */; };
|
||||||
F1EB08BB1AFD0E6A008F8F2B /* NSArray+Map.m in Sources */ = {isa = PBXBuildFile; fileRef = F1EB08BA1AFD0E6A008F8F2B /* NSArray+Map.m */; };
|
F1EB08BB1AFD0E6A008F8F2B /* NSArray+Map.m in Sources */ = {isa = PBXBuildFile; fileRef = F1EB08BA1AFD0E6A008F8F2B /* NSArray+Map.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
@ -24,6 +25,8 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference 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; };
|
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>"; };
|
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>"; };
|
F1E59BDE1ADD662800ACA28A /* RNFSManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFSManager.m; sourceTree = "<group>"; };
|
||||||
|
@ -49,6 +52,8 @@
|
||||||
F1EB08BA1AFD0E6A008F8F2B /* NSArray+Map.m */,
|
F1EB08BA1AFD0E6A008F8F2B /* NSArray+Map.m */,
|
||||||
F1E59BDD1ADD662800ACA28A /* RNFSManager.h */,
|
F1E59BDD1ADD662800ACA28A /* RNFSManager.h */,
|
||||||
F1E59BDE1ADD662800ACA28A /* RNFSManager.m */,
|
F1E59BDE1ADD662800ACA28A /* RNFSManager.m */,
|
||||||
|
8BF740751C033A2E0057A1E7 /* Downloader.h */,
|
||||||
|
8BF740761C033A2E0057A1E7 /* Downloader.m */,
|
||||||
F12AFB9C1ADAF8F800E0535D /* Products */,
|
F12AFB9C1ADAF8F800E0535D /* Products */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -119,6 +124,7 @@
|
||||||
files = (
|
files = (
|
||||||
F1E59BDF1ADD662800ACA28A /* RNFSManager.m in Sources */,
|
F1E59BDF1ADD662800ACA28A /* RNFSManager.m in Sources */,
|
||||||
F1EB08BB1AFD0E6A008F8F2B /* NSArray+Map.m in Sources */,
|
F1EB08BB1AFD0E6A008F8F2B /* NSArray+Map.m in Sources */,
|
||||||
|
8BF740771C033A2E0057A1E7 /* Downloader.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,12 @@
|
||||||
#import "Downloader.h"
|
#import "Downloader.h"
|
||||||
#import "RCTEventDispatcher.h"
|
#import "RCTEventDispatcher.h"
|
||||||
|
|
||||||
|
@interface RNFSManager()
|
||||||
|
|
||||||
|
@property (retain) NSMutableDictionary* downloaders;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation RNFSManager
|
@implementation RNFSManager
|
||||||
|
|
||||||
@synthesize bridge = _bridge;
|
@synthesize bridge = _bridge;
|
||||||
|
@ -148,24 +154,51 @@ RCT_EXPORT_METHOD(downloadFile:(NSString *)urlStr
|
||||||
callback:(RCTResponseSenderBlock)callback)
|
callback:(RCTResponseSenderBlock)callback)
|
||||||
{
|
{
|
||||||
|
|
||||||
DownloaderCallback downloaderSuccessCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSNumber* bytesWritten) {
|
DownloadParams* params = [DownloadParams alloc];
|
||||||
return callback(@[[NSNull null], [NSNumber numberWithBool:YES], filepath]);
|
|
||||||
|
params.fromUrl = urlStr;
|
||||||
|
params.toFile = 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]);
|
return callback([self makeErrorPayload:error]);
|
||||||
};
|
};
|
||||||
|
|
||||||
DownloaderCallback downloaderProgressCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSNumber* bytesWritten) {
|
params.beginCallback = ^(NSNumber* statusCode, NSNumber* contentLength, NSDictionary* headers) {
|
||||||
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadProgress-%@", jobId]
|
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadBegin-%@", jobId]
|
||||||
body:@{@"statusCode": statusCode,
|
body:@{@"jobId": jobId,
|
||||||
|
@"statusCode": statusCode,
|
||||||
@"contentLength": contentLength,
|
@"contentLength": contentLength,
|
||||||
|
@"headers": headers}];
|
||||||
|
};
|
||||||
|
|
||||||
|
params.progressCallback = ^(NSNumber* contentLength, NSNumber* bytesWritten) {
|
||||||
|
[self.bridge.eventDispatcher sendAppEventWithName:[NSString stringWithFormat:@"DownloadProgress-%@", jobId]
|
||||||
|
body:@{@"contentLength": contentLength,
|
||||||
@"bytesWritten": bytesWritten}];
|
@"bytesWritten": bytesWritten}];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (self.downloaders) self.downloaders = [NSMutableDictionary alloc];
|
||||||
|
|
||||||
Downloader* downloader = [Downloader 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
|
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;
|
package com.rnfs;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -9,6 +10,7 @@ import android.os.AsyncTask;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
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.WritableMap;
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.WritableArray;
|
import com.facebook.react.bridge.WritableArray;
|
||||||
|
|
||||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||||
|
|
||||||
public class RNFSManager extends ReactContextBaseJavaModule {
|
public class RNFSManager extends ReactContextBaseJavaModule {
|
||||||
|
@ -42,6 +43,8 @@ public class RNFSManager extends ReactContextBaseJavaModule {
|
||||||
private static final String NSFileTypeRegular = "NSFileTypeRegular";
|
private static final String NSFileTypeRegular = "NSFileTypeRegular";
|
||||||
private static final String NSFileTypeDirectory = "NSFileTypeDirectory";
|
private static final String NSFileTypeDirectory = "NSFileTypeDirectory";
|
||||||
|
|
||||||
|
private SparseArray<Downloader> downloaders = new SparseArray<Downloader>();
|
||||||
|
|
||||||
public RNFSManager(ReactApplicationContext reactContext) {
|
public RNFSManager(ReactApplicationContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
@ -193,110 +196,72 @@ public class RNFSManager extends ReactContextBaseJavaModule {
|
||||||
URL url = new URL(urlStr);
|
URL url = new URL(urlStr);
|
||||||
|
|
||||||
DownloadParams params = new DownloadParams();
|
DownloadParams params = new DownloadParams();
|
||||||
|
|
||||||
params.src = url;
|
params.src = url;
|
||||||
params.dest = file;
|
params.dest = file;
|
||||||
params.onTaskCompleted = new OnTaskCompleted() {
|
|
||||||
public void onTaskCompleted(Exception ex) {
|
params.onTaskCompleted = new DownloadParams.OnTaskCompleted() {
|
||||||
if (ex == null) {
|
public void onTaskCompleted(DownloadResult res) {
|
||||||
boolean success = true;
|
if (res.exception == null) {
|
||||||
callback.invoke(null, success, filepath);
|
WritableMap infoMap = Arguments.createMap();
|
||||||
|
|
||||||
|
infoMap.putInt("jobId", jobId);
|
||||||
|
infoMap.putInt("statusCode", res.statusCode);
|
||||||
|
infoMap.putInt("bytesWritten", res.bytesWritten);
|
||||||
|
|
||||||
|
callback.invoke(null, infoMap);
|
||||||
} else {
|
} 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();
|
WritableMap data = Arguments.createMap();
|
||||||
|
|
||||||
|
data.putInt("jobId", jobId);
|
||||||
data.putInt("statusCode", statusCode);
|
data.putInt("statusCode", statusCode);
|
||||||
data.putInt("contentLength", contentLength);
|
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);
|
data.putInt("bytesWritten", bytesWritten);
|
||||||
|
|
||||||
sendEvent(getReactApplicationContext(), "DownloadProgress-" + jobId, data);
|
sendEvent(getReactApplicationContext(), "DownloadProgress-" + jobId, data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DownloadTask downloadTask = new DownloadTask();
|
Downloader downloader = new Downloader();
|
||||||
downloadTask.execute(params);
|
|
||||||
|
downloader.execute(params);
|
||||||
|
|
||||||
|
this.downloaders.put(jobId, downloader);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
callback.invoke(makeErrorPayload(ex));
|
callback.invoke(makeErrorPayload(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DownloadParams {
|
@ReactMethod
|
||||||
public URL src;
|
public void stopDownload(int jobId) {
|
||||||
public File dest;
|
Downloader downloader = this.downloaders.get(jobId);
|
||||||
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) {
|
|
||||||
|
|
||||||
|
if (downloader != null) {
|
||||||
|
downloader.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES6",
|
||||||
|
"module": "commonjs"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue