2
2
#import < MobileCoreServices/MobileCoreServices.h>
3
3
#import < React/RCTEventEmitter.h>
4
4
#import < React/RCTBridgeModule.h>
5
+ #import < Photos/Photos.h>
5
6
6
7
@interface VydiaRNFileUploader : RCTEventEmitter <RCTBridgeModule, NSURLSessionTaskDelegate >
7
8
{
@@ -56,15 +57,13 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body {
56
57
@try {
57
58
NSURL *fileUri = [NSURL URLWithString: path];
58
59
NSString *pathWithoutProtocol = [fileUri path ];
59
-
60
60
NSString *name = [fileUri lastPathComponent ];
61
61
NSString *extension = [name pathExtension ];
62
62
bool exists = [[NSFileManager defaultManager ] fileExistsAtPath: pathWithoutProtocol];
63
63
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys: name, @" name" , nil ];
64
-
65
64
[params setObject: extension forKey: @" extension" ];
66
65
[params setObject: [NSNumber numberWithBool: exists] forKey: @" exists" ];
67
-
66
+
68
67
if (exists)
69
68
{
70
69
[params setObject: [self guessMIMETypeFromFileName: name] forKey: @" mimeType" ];
@@ -76,7 +75,6 @@ - (void)_sendEventWithName:(NSString *)eventName body:(id)body {
76
75
[params setObject: [NSNumber numberWithLong: fileSize] forKey: @" size" ];
77
76
}
78
77
}
79
-
80
78
resolve (params);
81
79
}
82
80
@catch (NSException *exception) {
@@ -97,6 +95,36 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName {
97
95
return (__bridge NSString *)(MIMEType);
98
96
}
99
97
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
+
100
128
/*
101
129
* Starts a file upload.
102
130
* Options are passed in as the first argument as a js hash:
@@ -117,7 +145,7 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName {
117
145
}
118
146
119
147
NSString *uploadUrl = options[@" url" ];
120
- NSString *fileURI = options[@" path" ];
148
+ __block NSString *fileURI = options[@" path" ];
121
149
NSString *method = options[@" method" ] ?: @" POST" ;
122
150
NSString *uploadType = options[@" type" ] ?: @" raw" ;
123
151
NSString *fieldName = options[@" field" ];
@@ -137,6 +165,23 @@ - (NSString *)guessMIMETypeFromFileName: (NSString *)fileName {
137
165
}
138
166
}];
139
167
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
+
140
185
NSURLSessionDataTask *uploadTask;
141
186
142
187
if ([uploadType isEqualToString: @" multipart" ]) {
@@ -189,7 +234,6 @@ - (NSData *)createBodyWithBoundary:(NSString *)boundary
189
234
NSString *pathWithoutProtocol = [fileUri path ];
190
235
191
236
NSData *data = [[NSFileManager defaultManager ] contentsAtPath: pathWithoutProtocol];
192
-
193
237
NSString *filename = [path lastPathComponent ];
194
238
NSString *mimetype = [self guessMIMETypeFromFileName: path];
195
239
@@ -208,7 +252,7 @@ - (NSURLSession *)urlSession {
208
252
if (_urlSession == nil ) {
209
253
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: BACKGROUND_SESSION_ID];
210
254
_urlSession = [NSURLSession sessionWithConfiguration: sessionConfiguration delegate: self delegateQueue: nil ];
211
- }
255
+ }
212
256
return _urlSession;
213
257
}
214
258
@@ -223,7 +267,7 @@ - (void)URLSession:(NSURLSession *)session
223
267
if (response != nil )
224
268
{
225
269
[data setObject: [NSNumber numberWithInteger: response.statusCode] forKey: @" responseCode" ];
226
- }
270
+ }
227
271
// Add data that was collected earlier by the didReceiveData method
228
272
NSMutableData *responseData = _responsesData[@(task.taskIdentifier)];
229
273
if (responseData) {
@@ -259,7 +303,6 @@ - (void)URLSession:(NSURLSession *)session
259
303
{
260
304
progress = 100.0 * (float )totalBytesSent / (float )totalBytesExpectedToSend;
261
305
}
262
-
263
306
[self _sendEventWithName: @" RNFileUploader-progress" body: @{ @" id" : task.taskDescription , @" progress" : [NSNumber numberWithFloat: progress] }];
264
307
}
265
308
0 commit comments