22#import < MobileCoreServices/MobileCoreServices.h>
33#import < React/RCTEventEmitter.h>
44#import < React/RCTBridgeModule.h>
5+ #import < Photos/Photos.h>
56
67@interface VydiaRNFileUploader : RCTEventEmitter <RCTBridgeModule, NSURLSessionTaskDelegate >
78{
@@ -56,15 +57,13 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body {
5657 @try {
5758 NSURL *fileUri = [NSURL URLWithString: path];
5859 NSString *pathWithoutProtocol = [fileUri path ];
59-
6060 NSString *name = [fileUri lastPathComponent ];
6161 NSString *extension = [name pathExtension ];
6262 bool exists = [[NSFileManager defaultManager ] fileExistsAtPath: pathWithoutProtocol];
6363 NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys: name, @" name" , nil ];
64-
6564 [params setObject: extension forKey: @" extension" ];
6665 [params setObject: [NSNumber numberWithBool: exists] forKey: @" exists" ];
67-
66+
6867 if (exists)
6968 {
7069 [params setObject: [self guessMIMETypeFromFileName: name] forKey: @" mimeType" ];
@@ -76,7 +75,6 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body {
7675 [params setObject: [NSNumber numberWithLong: fileSize] forKey: @" size" ];
7776 }
7877 }
79-
8078 resolve (params);
8179 }
8280 @catch (NSException *exception) {
@@ -97,6 +95,36 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName {
9795 return (__bridge NSString *)(MIMEType);
9896}
9997
98+ /*
99+ Utility method to copy a PHAsset file into a local temp file, which can then be uploaded.
100+ */
101+ - (void )copyAssetToFile : (NSString *)assetUrl completionHandler : (void (^)(NSString *__nullable tempFileUrl, NSError *__nullable error))completionHandler {
102+ NSURL *url = [NSURL URLWithString: assetUrl];
103+ PHAsset *asset = [PHAsset fetchAssetsWithALAssetURLs: @[url] options: nil ].lastObject ;
104+ if (!asset) {
105+ NSMutableDictionary * details = [NSMutableDictionary dictionary ];
106+ [details setValue: @" Asset could not be fetched. Are you missing permissions?" forKey: NSLocalizedDescriptionKey ];
107+ completionHandler (nil , [NSError errorWithDomain: @" RNUploader" code: 5 userInfo: details]);
108+ return ;
109+ }
110+ PHAssetResource *assetResource = [[PHAssetResource assetResourcesForAsset: asset] firstObject ];
111+ NSString *pathToWrite = [NSTemporaryDirectory () stringByAppendingPathComponent: [[NSUUID UUID ] UUIDString ]];
112+ NSURL *pathUrl = [NSURL fileURLWithPath: pathToWrite];
113+ NSString *fileURI = pathUrl.absoluteString ;
114+
115+ PHAssetResourceRequestOptions *options = [PHAssetResourceRequestOptions new ];
116+ options.networkAccessAllowed = YES ;
117+
118+ [[PHAssetResourceManager defaultManager ] writeDataForAssetResource: assetResource toFile: pathUrl options: options completionHandler: ^(NSError * _Nullable e) {
119+ if (e == nil ) {
120+ completionHandler (fileURI, nil );
121+ }
122+ else {
123+ completionHandler (nil , e);
124+ }
125+ }];
126+ }
127+
100128/*
101129 * Starts a file upload.
102130 * Options are passed in as the first argument as a js hash:
@@ -117,7 +145,7 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName {
117145 }
118146
119147 NSString *uploadUrl = options[@" url" ];
120- NSString *fileURI = options[@" path" ];
148+ __block NSString *fileURI = options[@" path" ];
121149 NSString *method = options[@" method" ] ?: @" POST" ;
122150 NSString *uploadType = options[@" type" ] ?: @" raw" ;
123151 NSString *fieldName = options[@" field" ];
@@ -137,6 +165,23 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName {
137165 }
138166 }];
139167
168+
169+ // asset library files have to be copied over to a temp file. they can't be uploaded directly
170+ if ([fileURI hasPrefix: @" assets-library" ]) {
171+ dispatch_group_t group = dispatch_group_create ();
172+ dispatch_group_enter (group);
173+ [self copyAssetToFile: fileURI completionHandler: ^(NSString * _Nullable tempFileUrl, NSError * _Nullable error) {
174+ if (error) {
175+ dispatch_group_leave (group);
176+ reject (@" RN Uploader" , @" Asset could not be copied to temp file." , nil );
177+ return ;
178+ }
179+ fileURI = tempFileUrl;
180+ dispatch_group_leave (group);
181+ }];
182+ dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
183+ }
184+
140185 NSURLSessionDataTask *uploadTask;
141186
142187 if ([uploadType isEqualToString: @" multipart" ]) {
@@ -189,7 +234,6 @@ - (NSData *)createBodyWithBoundary:(NSString *)boundary
189234 NSString *pathWithoutProtocol = [fileUri path ];
190235
191236 NSData *data = [[NSFileManager defaultManager ] contentsAtPath: pathWithoutProtocol];
192-
193237 NSString *filename = [path lastPathComponent ];
194238 NSString *mimetype = [self guessMIMETypeFromFileName: path];
195239
@@ -208,7 +252,7 @@ - (NSURLSession *)urlSession {
208252 if (_urlSession == nil ) {
209253 NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: BACKGROUND_SESSION_ID];
210254 _urlSession = [NSURLSession sessionWithConfiguration: sessionConfiguration delegate: self delegateQueue: nil ];
211- }
255+ }
212256 return _urlSession;
213257}
214258
@@ -223,7 +267,7 @@ - (void)URLSession:(NSURLSession *)session
223267 if (response != nil )
224268 {
225269 [data setObject: [NSNumber numberWithInteger: response.statusCode] forKey: @" responseCode" ];
226- }
270+ }
227271 // Add data that was collected earlier by the didReceiveData method
228272 NSMutableData *responseData = _responsesData[@(task.taskIdentifier)];
229273 if (responseData) {
@@ -259,7 +303,6 @@ - (void)URLSession:(NSURLSession *)session
259303 {
260304 progress = 100.0 * (float )totalBytesSent / (float )totalBytesExpectedToSend;
261305 }
262-
263306 [self _sendEventWithName: @" RNFileUploader-progress" body: @{ @" id" : task.taskDescription , @" progress" : [NSNumber numberWithFloat: progress] }];
264307}
265308
0 commit comments