mirror of
https://github.com/zoriya/react-native-background-downloader.git
synced 2025-12-06 06:56:10 +00:00
Sync issue fix, added error code, handled enque failure
Sync issue fix, added error code, handled enque failure
This commit is contained in:
@@ -22,6 +22,7 @@ static CompletionHandler storedCompletionHandler;
|
||||
NSMutableDictionary<NSString *, NSNumber *> *idToPercentMap;
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *progressReports;
|
||||
NSDate *lastProgressReport;
|
||||
NSNumber *sharedLock;
|
||||
}
|
||||
|
||||
RCT_EXPORT_MODULE();
|
||||
@@ -66,6 +67,7 @@ RCT_EXPORT_MODULE();
|
||||
sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessonIdentifier];
|
||||
progressReports = [[NSMutableDictionary alloc] init];
|
||||
lastProgressReport = [[NSDate alloc] init];
|
||||
sharedLock = [NSNumber numberWithInt:1];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -77,19 +79,21 @@ RCT_EXPORT_MODULE();
|
||||
}
|
||||
|
||||
- (void)removeTaskFromMap: (NSURLSessionTask *)task {
|
||||
NSNumber *taskId = @(task.taskIdentifier);
|
||||
RNBGDTaskConfig *taskConfig = taskToConfigMap[taskId];
|
||||
@synchronized (taskToConfigMap) {
|
||||
@synchronized (sharedLock) {
|
||||
NSNumber *taskId = @(task.taskIdentifier);
|
||||
RNBGDTaskConfig *taskConfig = taskToConfigMap[taskId];
|
||||
|
||||
[taskToConfigMap removeObjectForKey:taskId];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[self serialize: taskToConfigMap] forKey:ID_TO_CONFIG_MAP_KEY];
|
||||
}
|
||||
if (taskConfig) {
|
||||
[idToTaskMap removeObjectForKey:taskConfig.id];
|
||||
[idToPercentMap removeObjectForKey:taskConfig.id];
|
||||
}
|
||||
if (taskToConfigMap.count == 0) {
|
||||
[urlSession invalidateAndCancel];
|
||||
urlSession = nil;
|
||||
|
||||
if (taskConfig) {
|
||||
[idToTaskMap removeObjectForKey:taskConfig.id];
|
||||
[idToPercentMap removeObjectForKey:taskConfig.id];
|
||||
}
|
||||
if (taskToConfigMap.count == 0) {
|
||||
[urlSession invalidateAndCancel];
|
||||
urlSession = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,37 +125,45 @@ RCT_EXPORT_METHOD(download: (NSDictionary *) options) {
|
||||
}
|
||||
}
|
||||
|
||||
NSURLSessionDownloadTask __strong *task = [urlSession downloadTaskWithRequest:request];
|
||||
RNBGDTaskConfig *taskConfig = [[RNBGDTaskConfig alloc] initWithDictionary: @{@"id": identifier, @"destination": destination}];
|
||||
@synchronized(taskToConfigMap) {
|
||||
@synchronized (sharedLock) {
|
||||
NSURLSessionDownloadTask __strong *task = [urlSession downloadTaskWithRequest:request];
|
||||
RNBGDTaskConfig *taskConfig = [[RNBGDTaskConfig alloc] initWithDictionary: @{@"id": identifier, @"destination": destination}];
|
||||
|
||||
taskToConfigMap[@(task.taskIdentifier)] = taskConfig;
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[self serialize: taskToConfigMap] forKey:ID_TO_CONFIG_MAP_KEY];
|
||||
}
|
||||
idToTaskMap[identifier] = task;
|
||||
idToPercentMap[identifier] = @0.0;
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(pauseTask: (NSString *)identifier) {
|
||||
NSURLSessionDownloadTask *task = idToTaskMap[identifier];
|
||||
if (task != nil && task.state == NSURLSessionTaskStateRunning) {
|
||||
[task suspend];
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(resumeTask: (NSString *)identifier) {
|
||||
NSURLSessionDownloadTask *task = idToTaskMap[identifier];
|
||||
if (task != nil && task.state == NSURLSessionTaskStateSuspended) {
|
||||
idToTaskMap[identifier] = task;
|
||||
idToPercentMap[identifier] = @0.0;
|
||||
|
||||
[task resume];
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(pauseTask: (NSString *)identifier) {
|
||||
@synchronized (sharedLock) {
|
||||
NSURLSessionDownloadTask *task = idToTaskMap[identifier];
|
||||
if (task != nil && task.state == NSURLSessionTaskStateRunning) {
|
||||
[task suspend];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(resumeTask: (NSString *)identifier) {
|
||||
@synchronized (sharedLock) {
|
||||
NSURLSessionDownloadTask *task = idToTaskMap[identifier];
|
||||
if (task != nil && task.state == NSURLSessionTaskStateSuspended) {
|
||||
[task resume];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(stopTask: (NSString *)identifier) {
|
||||
NSURLSessionDownloadTask *task = idToTaskMap[identifier];
|
||||
if (task != nil) {
|
||||
[task cancel];
|
||||
[self removeTaskFromMap:task];
|
||||
@synchronized (sharedLock) {
|
||||
NSURLSessionDownloadTask *task = idToTaskMap[identifier];
|
||||
if (task != nil) {
|
||||
[task cancel];
|
||||
[self removeTaskFromMap:task];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,56 +171,60 @@ RCT_EXPORT_METHOD(checkForExistingDownloads: (RCTPromiseResolveBlock)resolve rej
|
||||
[self lazyInitSession];
|
||||
[urlSession getTasksWithCompletionHandler:^(NSArray<NSURLSessionDataTask *> * _Nonnull dataTasks, NSArray<NSURLSessionUploadTask *> * _Nonnull uploadTasks, NSArray<NSURLSessionDownloadTask *> * _Nonnull downloadTasks) {
|
||||
NSMutableArray *idsFound = [[NSMutableArray alloc] init];
|
||||
for (NSURLSessionDownloadTask *foundTask in downloadTasks) {
|
||||
NSURLSessionDownloadTask __strong *task = foundTask;
|
||||
RNBGDTaskConfig *taskConfig = taskToConfigMap[@(task.taskIdentifier)];
|
||||
if (taskConfig) {
|
||||
if (task.state == NSURLSessionTaskStateCompleted && task.countOfBytesReceived < task.countOfBytesExpectedToReceive) {
|
||||
if (task.error && task.error.code == -999 && task.error.userInfo[NSURLSessionDownloadTaskResumeData] != nil) {
|
||||
task = [urlSession downloadTaskWithResumeData:task.error.userInfo[NSURLSessionDownloadTaskResumeData]];
|
||||
} else {
|
||||
task = [urlSession downloadTaskWithURL:foundTask.currentRequest.URL];
|
||||
@synchronized (sharedLock) {
|
||||
for (NSURLSessionDownloadTask *foundTask in downloadTasks) {
|
||||
NSURLSessionDownloadTask __strong *task = foundTask;
|
||||
RNBGDTaskConfig *taskConfig = taskToConfigMap[@(task.taskIdentifier)];
|
||||
if (taskConfig) {
|
||||
if (task.state == NSURLSessionTaskStateCompleted && task.countOfBytesReceived < task.countOfBytesExpectedToReceive) {
|
||||
if (task.error && task.error.code == -999 && task.error.userInfo[NSURLSessionDownloadTaskResumeData] != nil) {
|
||||
task = [urlSession downloadTaskWithResumeData:task.error.userInfo[NSURLSessionDownloadTaskResumeData]];
|
||||
} else {
|
||||
task = [urlSession downloadTaskWithURL:foundTask.currentRequest.URL];
|
||||
}
|
||||
[task resume];
|
||||
}
|
||||
[task resume];
|
||||
NSNumber *percent = foundTask.countOfBytesExpectedToReceive > 0 ? [NSNumber numberWithFloat:(float)task.countOfBytesReceived/(float)foundTask.countOfBytesExpectedToReceive] : @0.0;
|
||||
[idsFound addObject:@{
|
||||
@"id": taskConfig.id,
|
||||
@"state": [NSNumber numberWithInt: task.state],
|
||||
@"bytesWritten": [NSNumber numberWithLongLong:task.countOfBytesReceived],
|
||||
@"totalBytes": [NSNumber numberWithLongLong:foundTask.countOfBytesExpectedToReceive],
|
||||
@"percent": percent
|
||||
}];
|
||||
taskConfig.reportedBegin = YES;
|
||||
taskToConfigMap[@(task.taskIdentifier)] = taskConfig;
|
||||
idToTaskMap[taskConfig.id] = task;
|
||||
idToPercentMap[taskConfig.id] = percent;
|
||||
} else {
|
||||
[task cancel];
|
||||
}
|
||||
NSNumber *percent = foundTask.countOfBytesExpectedToReceive > 0 ? [NSNumber numberWithFloat:(float)task.countOfBytesReceived/(float)foundTask.countOfBytesExpectedToReceive] : @0.0;
|
||||
[idsFound addObject:@{
|
||||
@"id": taskConfig.id,
|
||||
@"state": [NSNumber numberWithInt: task.state],
|
||||
@"bytesWritten": [NSNumber numberWithLongLong:task.countOfBytesReceived],
|
||||
@"totalBytes": [NSNumber numberWithLongLong:foundTask.countOfBytesExpectedToReceive],
|
||||
@"percent": percent
|
||||
}];
|
||||
taskConfig.reportedBegin = YES;
|
||||
taskToConfigMap[@(task.taskIdentifier)] = taskConfig;
|
||||
idToTaskMap[taskConfig.id] = task;
|
||||
idToPercentMap[taskConfig.id] = percent;
|
||||
} else {
|
||||
[task cancel];
|
||||
}
|
||||
resolve(idsFound);
|
||||
}
|
||||
resolve(idsFound);
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionDownloadDelegate methods
|
||||
- (void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location {
|
||||
RNBGDTaskConfig *taskCofig = taskToConfigMap[@(downloadTask.taskIdentifier)];
|
||||
if (taskCofig != nil) {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSURL *destURL = [NSURL fileURLWithPath:taskCofig.destination];
|
||||
[fileManager createDirectoryAtURL:[destURL URLByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
[fileManager removeItemAtURL:destURL error:nil];
|
||||
NSError *moveError;
|
||||
BOOL moved = [fileManager moveItemAtURL:location toURL:destURL error:&moveError];
|
||||
if (self.bridge) {
|
||||
if (moved) {
|
||||
[self sendEventWithName:@"downloadComplete" body:@{@"id": taskCofig.id}];
|
||||
} else {
|
||||
[self sendEventWithName:@"downloadFailed" body:@{@"id": taskCofig.id, @"error": [moveError localizedDescription]}];
|
||||
@synchronized (sharedLock) {
|
||||
RNBGDTaskConfig *taskCofig = taskToConfigMap[@(downloadTask.taskIdentifier)];
|
||||
if (taskCofig != nil) {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSURL *destURL = [NSURL fileURLWithPath:taskCofig.destination];
|
||||
[fileManager createDirectoryAtURL:[destURL URLByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
[fileManager removeItemAtURL:destURL error:nil];
|
||||
NSError *moveError;
|
||||
BOOL moved = [fileManager moveItemAtURL:location toURL:destURL error:&moveError];
|
||||
if (self.bridge) {
|
||||
if (moved) {
|
||||
[self sendEventWithName:@"downloadComplete" body:@{@"id": taskCofig.id}];
|
||||
} else {
|
||||
[self sendEventWithName:@"downloadFailed" body:@{@"id": taskCofig.id, @"error": [moveError localizedDescription]}];
|
||||
}
|
||||
}
|
||||
[self removeTaskFromMap:downloadTask];
|
||||
}
|
||||
[self removeTaskFromMap:downloadTask];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +232,7 @@ RCT_EXPORT_METHOD(checkForExistingDownloads: (RCTPromiseResolveBlock)resolve rej
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
|
||||
@synchronized (self) {
|
||||
@synchronized (sharedLock) {
|
||||
RNBGDTaskConfig *taskCofig = taskToConfigMap[@(downloadTask.taskIdentifier)];
|
||||
if (taskCofig != nil) {
|
||||
if (!taskCofig.reportedBegin) {
|
||||
@@ -244,12 +260,14 @@ RCT_EXPORT_METHOD(checkForExistingDownloads: (RCTPromiseResolveBlock)resolve rej
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
|
||||
RNBGDTaskConfig *taskCofig = taskToConfigMap[@(task.taskIdentifier)];
|
||||
if (error != nil && error.code != -999 && taskCofig != nil) {
|
||||
if (self.bridge) {
|
||||
[self sendEventWithName:@"downloadFailed" body:@{@"id": taskCofig.id, @"error": [error localizedDescription]}];
|
||||
@synchronized (sharedLock) {
|
||||
RNBGDTaskConfig *taskCofig = taskToConfigMap[@(task.taskIdentifier)];
|
||||
if (error != nil && error.code != -999 && taskCofig != nil) {
|
||||
if (self.bridge) {
|
||||
[self sendEventWithName:@"downloadFailed" body:@{@"id": taskCofig.id, @"error": [error localizedDescription]}];
|
||||
}
|
||||
[self removeTaskFromMap:task];
|
||||
}
|
||||
[self removeTaskFromMap:task];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user