diff --git a/ios/VydiaRNFileUploader.m b/ios/VydiaRNFileUploader.m index 407884f7..43369cb9 100644 --- a/ios/VydiaRNFileUploader.m +++ b/ios/VydiaRNFileUploader.m @@ -2,6 +2,7 @@ #import #import #import +#import @interface VydiaRNFileUploader : RCTEventEmitter { @@ -56,15 +57,13 @@ - (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 +75,6 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body { [params setObject:[NSNumber numberWithLong:fileSize] forKey:@"size"]; } } - resolve(params); } @catch (NSException *exception) { @@ -97,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: @@ -117,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"]; @@ -137,6 +165,23 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName { } }]; + + // 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); + [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); + } + NSURLSessionDataTask *uploadTask; if ([uploadType isEqualToString:@"multipart"]) { @@ -189,7 +234,6 @@ - (NSData *)createBodyWithBoundary:(NSString *)boundary NSString *pathWithoutProtocol = [fileUri path]; NSData *data = [[NSFileManager defaultManager] contentsAtPath:pathWithoutProtocol]; - NSString *filename = [path lastPathComponent]; NSString *mimetype = [self guessMIMETypeFromFileName:path]; @@ -208,7 +252,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 +267,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 +303,6 @@ - (void)URLSession:(NSURLSession *)session { progress = 100.0 * (float)totalBytesSent / (float)totalBytesExpectedToSend; } - [self _sendEventWithName:@"RNFileUploader-progress" body:@{ @"id": task.taskDescription, @"progress": [NSNumber numberWithFloat:progress] }]; } 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": {