From 9a6359ed7aaf25af653859b68c4627ff269fb236 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Fri, 2 Feb 2018 14:33:54 -0500 Subject: [PATCH 1/7] start assets-library integration --- ios/VydiaRNFileUploader.m | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index 407884f7..d0ee3329 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -2,6 +2,7 @@ #import #import #import +#import @interface VydiaRNFileUploader : RCTEventEmitter { @@ -56,15 +57,15 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body { @try { NSURL *fileUri = [NSURL URLWithString: path]; NSString *pathWithoutProtocol = [fileUri path]; - + NSString *name = [fileUri lastPathComponent]; NSString *extension = [name pathExtension]; bool exists = [[NSFileManager defaultManager] fileExistsAtPath:pathWithoutProtocol]; NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys: name, @"name", nil]; - + [params setObject:extension forKey:@"extension"]; [params setObject:[NSNumber numberWithBool:exists] forKey:@"exists"]; - + if (exists) { [params setObject:[self guessMIMETypeFromFileName:name] forKey:@"mimeType"]; @@ -76,7 +77,7 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body { [params setObject:[NSNumber numberWithLong:fileSize] forKey:@"size"]; } } - + resolve(params); } @catch (NSException *exception) { @@ -149,6 +150,16 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { // I am sorry about warning, but Upload tasks from NSData are not supported in background sessions. uploadTask = [[self urlSession] uploadTaskWithRequest:request fromData: nil]; } else { + //https://stackoverflow.com/questions/33278540/phasset-afnetworking-upload-multiple-videos + if ([fileURI hasPrefix:@"assets-library"]) { + NSURL *url = [NSURL URLWithString:fileURI]; + PHAsset *capturedAsset = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil].lastObject; + if (capturedAsset) { + [self urlSession] uploadTaskWithRequest:request fromData:<#(nonnull NSData *)#> + } + } + + uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:[NSURL URLWithString: fileURI]]; } @@ -208,7 +219,7 @@ - (NSURLSession *)urlSession { if (_urlSession == nil) { NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:BACKGROUND_SESSION_ID]; _urlSession = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil]; - } + } return _urlSession; } @@ -223,7 +234,7 @@ - (void)URLSession:(NSURLSession *)session if (response != nil) { [data setObject:[NSNumber numberWithInteger:response.statusCode] forKey:@"responseCode"]; - } + } //Add data that was collected earlier by the didReceiveData method NSMutableData *responseData = _responsesData[@(task.taskIdentifier)]; if (responseData) { @@ -259,7 +270,7 @@ - (void)URLSession:(NSURLSession *)session { progress = 100.0 * (float)totalBytesSent / (float)totalBytesExpectedToSend; } - + [self _sendEventWithName:@"RNFileUploader-progress" body:@{ @"id": task.taskDescription, @"progress": [NSNumber numberWithFloat:progress] }]; } From a23f9e5a7b07229704dced417e371370cc97b4c6 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Wed, 7 Feb 2018 13:36:09 -0500 Subject: [PATCH 2/7] get assets-library initial support. needs cleanup --- ios/VydiaRNFileUploader.m | 49 ++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index d0ee3329..b91e308d 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -138,8 +138,11 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { } }]; - NSURLSessionDataTask *uploadTask; + __block NSURLSessionDataTask *uploadTask; + dispatch_group_t group = dispatch_group_create(); + dispatch_group_enter(group); + if ([uploadType isEqualToString:@"multipart"]) { NSString *uuidStr = [[NSUUID UUID] UUIDString]; [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", uuidStr] forHTTPHeaderField:@"Content-Type"]; @@ -149,20 +152,50 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { // I am sorry about warning, but Upload tasks from NSData are not supported in background sessions. uploadTask = [[self urlSession] uploadTaskWithRequest:request fromData: nil]; + dispatch_group_leave(group); } else { - //https://stackoverflow.com/questions/33278540/phasset-afnetworking-upload-multiple-videos +// //https://stackoverflow.com/questions/33278540/phasset-afnetworking-upload-multiple-videos if ([fileURI hasPrefix:@"assets-library"]) { NSURL *url = [NSURL URLWithString:fileURI]; - PHAsset *capturedAsset = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil].lastObject; - if (capturedAsset) { - [self urlSession] uploadTaskWithRequest:request fromData:<#(nonnull NSData *)#> + PHAsset *asset = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil].lastObject; + if (!asset) { + reject(@"RN Uploader", @"Asset could not be fetched. Are you missing permissions?", nil); + return; } + PHAssetResource *assetResource = [[PHAssetResource assetResourcesForAsset:asset] firstObject]; +// NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:assetResource.originalFilename]; + NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSURL *localpath = [NSURL fileURLWithPath:pathToWrite]; + + NSFileManager *fileManager = [NSFileManager defaultManager]; +// +// // Delete file if it already exists + if ([fileManager fileExistsAtPath:pathToWrite]) { + [fileManager removeItemAtURL:localpath error:nil]; + } + PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; + options.networkAccessAllowed = YES; + // to get this working, consider something like https://stackoverflow.com/questions/4326350/how-do-i-wait-for-an-asynchronously-dispatched-block-to-finish + //http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch + [[PHAssetResourceManager defaultManager] writeDataForAssetResource:assetResource toFile:localpath options:options completionHandler:^(NSError * _Nullable error) { + if (error) { + reject(@"RN Uploader", @"Asset could not be copied.", nil); + return; + } + uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:localpath]; + dispatch_group_leave(group); + }]; + } else { + uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:[NSURL URLWithString: fileURI]]; + dispatch_group_leave(group); } - - - uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:[NSURL URLWithString: fileURI]]; } + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); +// dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{ +// // Won't get here until everything has finished +// }); + uploadTask.taskDescription = customUploadId ? customUploadId : [NSString stringWithFormat:@"%i", thisUploadId]; [uploadTask resume]; From 8df7cd74c652ef80d146ef1ce33e33fc36e88b96 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Wed, 7 Feb 2018 20:34:49 -0500 Subject: [PATCH 3/7] refactor --- ios/VydiaRNFileUploader.m | 80 +++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index b91e308d..53fb9af6 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -138,11 +138,39 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { } }]; - __block NSURLSessionDataTask *uploadTask; - - dispatch_group_t group = dispatch_group_create(); - dispatch_group_enter(group); + // asset library files have to be copied over to a temp file. they cannot be uploaded directly + if ([fileURI hasPrefix:@"assets-library"]) { + NSURL *url = [NSURL URLWithString:fileURI]; + PHAsset *asset = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil].lastObject; + if (!asset) { + reject(@"RN Uploader", @"Asset could not be fetched. Are you missing permissions?", nil); + return; + } + PHAssetResource *assetResource = [[PHAssetResource assetResourcesForAsset:asset] firstObject]; + NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSURL *pathUrl = [NSURL fileURLWithPath:pathToWrite]; + fileURI = pathUrl.absoluteString; + + PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; + options.networkAccessAllowed = YES; + + dispatch_group_t group = dispatch_group_create(); + dispatch_group_enter(group); + + __block NSError *error; + [[PHAssetResourceManager defaultManager] writeDataForAssetResource:assetResource toFile:pathUrl options:options completionHandler:^(NSError * _Nullable e) { + error = e; + dispatch_group_leave(group); + }]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + if (error) { + reject(@"RN Uploader", @"Asset could not be copied.", nil); + return; + } + } + NSURLSessionDataTask *uploadTask; + if ([uploadType isEqualToString:@"multipart"]) { NSString *uuidStr = [[NSUUID UUID] UUIDString]; [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", uuidStr] forHTTPHeaderField:@"Content-Type"]; @@ -152,50 +180,10 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { // I am sorry about warning, but Upload tasks from NSData are not supported in background sessions. uploadTask = [[self urlSession] uploadTaskWithRequest:request fromData: nil]; - dispatch_group_leave(group); } else { -// //https://stackoverflow.com/questions/33278540/phasset-afnetworking-upload-multiple-videos - if ([fileURI hasPrefix:@"assets-library"]) { - NSURL *url = [NSURL URLWithString:fileURI]; - PHAsset *asset = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil].lastObject; - if (!asset) { - reject(@"RN Uploader", @"Asset could not be fetched. Are you missing permissions?", nil); - return; - } - PHAssetResource *assetResource = [[PHAssetResource assetResourcesForAsset:asset] firstObject]; -// NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingString:assetResource.originalFilename]; - NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; - NSURL *localpath = [NSURL fileURLWithPath:pathToWrite]; - - NSFileManager *fileManager = [NSFileManager defaultManager]; -// -// // Delete file if it already exists - if ([fileManager fileExistsAtPath:pathToWrite]) { - [fileManager removeItemAtURL:localpath error:nil]; - } - PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; - options.networkAccessAllowed = YES; - // to get this working, consider something like https://stackoverflow.com/questions/4326350/how-do-i-wait-for-an-asynchronously-dispatched-block-to-finish - //http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch - [[PHAssetResourceManager defaultManager] writeDataForAssetResource:assetResource toFile:localpath options:options completionHandler:^(NSError * _Nullable error) { - if (error) { - reject(@"RN Uploader", @"Asset could not be copied.", nil); - return; - } - uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:localpath]; - dispatch_group_leave(group); - }]; - } else { - uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:[NSURL URLWithString: fileURI]]; - dispatch_group_leave(group); - } + uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:[NSURL URLWithString: fileURI]]; } - - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); -// dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{ -// // Won't get here until everything has finished -// }); - + uploadTask.taskDescription = customUploadId ? customUploadId : [NSString stringWithFormat:@"%i", thisUploadId]; [uploadTask resume]; From bb26fcbd357b58d01c0b241dee44b8a3ef62a5e2 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Wed, 7 Feb 2018 20:37:41 -0500 Subject: [PATCH 4/7] cleanup --- ios/VydiaRNFileUploader.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index 53fb9af6..b1ee6408 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -57,12 +57,10 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body { @try { NSURL *fileUri = [NSURL URLWithString: path]; NSString *pathWithoutProtocol = [fileUri path]; - NSString *name = [fileUri lastPathComponent]; NSString *extension = [name pathExtension]; bool exists = [[NSFileManager defaultManager] fileExistsAtPath:pathWithoutProtocol]; NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys: name, @"name", nil]; - [params setObject:extension forKey:@"extension"]; [params setObject:[NSNumber numberWithBool:exists] forKey:@"exists"]; @@ -77,7 +75,6 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body { [params setObject:[NSNumber numberWithLong:fileSize] forKey:@"size"]; } } - resolve(params); } @catch (NSException *exception) { From 9e925cf8907c99f2ce98eeedaa50245c536c44f4 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Wed, 7 Feb 2018 20:38:23 -0500 Subject: [PATCH 5/7] cleanup --- ios/VydiaRNFileUploader.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index b1ee6408..48fa1441 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -147,7 +147,7 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; NSURL *pathUrl = [NSURL fileURLWithPath:pathToWrite]; fileURI = pathUrl.absoluteString; - + PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; options.networkAccessAllowed = YES; @@ -165,7 +165,7 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { return; } } - + NSURLSessionDataTask *uploadTask; if ([uploadType isEqualToString:@"multipart"]) { @@ -180,7 +180,7 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { } else { uploadTask = [[self urlSession] uploadTaskWithRequest:request fromFile:[NSURL URLWithString: fileURI]]; } - + uploadTask.taskDescription = customUploadId ? customUploadId : [NSString stringWithFormat:@"%i", thisUploadId]; [uploadTask resume]; @@ -218,7 +218,6 @@ - (NSData *)createBodyWithBoundary:(NSString *)boundary NSString *pathWithoutProtocol = [fileUri path]; NSData *data = [[NSFileManager defaultManager] contentsAtPath:pathWithoutProtocol]; - NSString *filename = [path lastPathComponent]; NSString *mimetype = [self guessMIMETypeFromFileName:path]; From 30c1326df69e6e3a51549ad2466adc86d9def8db Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Wed, 7 Feb 2018 20:38:47 -0500 Subject: [PATCH 6/7] cleanup --- ios/VydiaRNFileUploader.m | 1 - 1 file changed, 1 deletion(-) diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index 48fa1441..86b90831 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -287,7 +287,6 @@ - (void)URLSession:(NSURLSession *)session { progress = 100.0 * (float)totalBytesSent / (float)totalBytesExpectedToSend; } - [self _sendEventWithName:@"RNFileUploader-progress" body:@{ @"id": task.taskDescription, @"progress": [NSNumber numberWithFloat:progress] }]; } From 709228cb4b0a600374c4fd87d08f2f9cb1bc483d Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Thu, 8 Feb 2018 10:15:29 -0500 Subject: [PATCH 7/7] version bump --- ios/VydiaRNFileUploader.m | 64 ++++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index 86b90831..43369cb9 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -95,6 +95,36 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { return (__bridge NSString *)(MIMEType); } +/* + Utility method to copy a PHAsset file into a local temp file, which can then be uploaded. + */ +- (void)copyAssetToFile: (NSString *)assetUrl completionHandler: (void(^)(NSString *__nullable tempFileUrl, NSError *__nullable error))completionHandler { + NSURL *url = [NSURL URLWithString:assetUrl]; + PHAsset *asset = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil].lastObject; + if (!asset) { + NSMutableDictionary* details = [NSMutableDictionary dictionary]; + [details setValue:@"Asset could not be fetched. Are you missing permissions?" forKey:NSLocalizedDescriptionKey]; + completionHandler(nil, [NSError errorWithDomain:@"RNUploader" code:5 userInfo:details]); + return; + } + PHAssetResource *assetResource = [[PHAssetResource assetResourcesForAsset:asset] firstObject]; + NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSURL *pathUrl = [NSURL fileURLWithPath:pathToWrite]; + NSString *fileURI = pathUrl.absoluteString; + + PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; + options.networkAccessAllowed = YES; + + [[PHAssetResourceManager defaultManager] writeDataForAssetResource:assetResource toFile:pathUrl options:options completionHandler:^(NSError * _Nullable e) { + if (e == nil) { + completionHandler(fileURI, nil); + } + else { + completionHandler(nil, e); + } + }]; +} + /* * Starts a file upload. * Options are passed in as the first argument as a js hash: @@ -115,7 +145,7 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { } NSString *uploadUrl = options[@"url"]; - NSString *fileURI = options[@"path"]; + __block NSString *fileURI = options[@"path"]; NSString *method = options[@"method"] ?: @"POST"; NSString *uploadType = options[@"type"] ?: @"raw"; NSString *fieldName = options[@"field"]; @@ -135,35 +165,21 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { } }]; - // asset library files have to be copied over to a temp file. they cannot be uploaded directly - if ([fileURI hasPrefix:@"assets-library"]) { - NSURL *url = [NSURL URLWithString:fileURI]; - PHAsset *asset = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil].lastObject; - if (!asset) { - reject(@"RN Uploader", @"Asset could not be fetched. Are you missing permissions?", nil); - return; - } - PHAssetResource *assetResource = [[PHAssetResource assetResourcesForAsset:asset] firstObject]; - NSString *pathToWrite = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; - NSURL *pathUrl = [NSURL fileURLWithPath:pathToWrite]; - fileURI = pathUrl.absoluteString; - - PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new]; - options.networkAccessAllowed = YES; + // asset library files have to be copied over to a temp file. they can't be uploaded directly + if ([fileURI hasPrefix:@"assets-library"]) { dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); - - __block NSError *error; - [[PHAssetResourceManager defaultManager] writeDataForAssetResource:assetResource toFile:pathUrl options:options completionHandler:^(NSError * _Nullable e) { - error = e; + [self copyAssetToFile:fileURI completionHandler:^(NSString * _Nullable tempFileUrl, NSError * _Nullable error) { + if (error) { + dispatch_group_leave(group); + reject(@"RN Uploader", @"Asset could not be copied to temp file.", nil); + return; + } + fileURI = tempFileUrl; dispatch_group_leave(group); }]; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - if (error) { - reject(@"RN Uploader", @"Asset could not be copied.", nil); - return; - } } NSURLSessionDataTask *uploadTask; diff --git a/package.json b/package.json index e914fbc9..e1ad7db0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-background-upload", - "version": "4.2.0", + "version": "4.3.0", "description": "Cross platform http post file uploader with android and iOS background support", "main": "index.js", "scripts": {