Browse Source

support upload task + recieve finish event from background

Guy Blank 6 years ago
parent
commit
3aec4191f9
3 changed files with 74 additions and 59 deletions
  1. 2
    8
      ios/RNFetchBlobNetwork.m
  2. 4
    1
      ios/RNFetchBlobRequest.h
  3. 68
    50
      ios/RNFetchBlobRequest.m

+ 2
- 8
ios/RNFetchBlobNetwork.m View File

63
 + (RNFetchBlobNetwork* _Nullable)sharedInstance {
63
 + (RNFetchBlobNetwork* _Nullable)sharedInstance {
64
     static id _sharedInstance = nil;
64
     static id _sharedInstance = nil;
65
     static dispatch_once_t onceToken;
65
     static dispatch_once_t onceToken;
66
-
66
+    
67
     dispatch_once(&onceToken, ^{
67
     dispatch_once(&onceToken, ^{
68
         _sharedInstance = [[self alloc] init];
68
         _sharedInstance = [[self alloc] init];
69
     });
69
     });
135
 
135
 
136
 - (void) cancelRequest:(NSString *)taskId
136
 - (void) cancelRequest:(NSString *)taskId
137
 {
137
 {
138
-    NSURLSessionDataTask * task;
139
-    
140
     @synchronized ([RNFetchBlobNetwork class]) {
138
     @synchronized ([RNFetchBlobNetwork class]) {
141
-        task = [self.requestsTable objectForKey:taskId].task;
142
-    }
143
-    
144
-    if (task && task.state == NSURLSessionTaskStateRunning) {
145
-        [task cancel];
139
+        [[self.requestsTable objectForKey:taskId] cancelRequest:taskId];
146
     }
140
     }
147
 }
141
 }
148
 
142
 

+ 4
- 1
ios/RNFetchBlobRequest.h View File

32
 @property (nullable, nonatomic) NSError * error;
32
 @property (nullable, nonatomic) NSError * error;
33
 @property (nullable, nonatomic) RNFetchBlobProgress *progressConfig;
33
 @property (nullable, nonatomic) RNFetchBlobProgress *progressConfig;
34
 @property (nullable, nonatomic) RNFetchBlobProgress *uploadProgressConfig;
34
 @property (nullable, nonatomic) RNFetchBlobProgress *uploadProgressConfig;
35
-@property (nullable, nonatomic, weak) NSURLSessionDataTask *task;
35
+//@property (nullable, nonatomic, weak) NSURLSessionDataTask *task;
36
+@property (nonatomic, strong) __block NSURLSession * session;
36
 
37
 
37
 - (void) sendRequest:(NSDictionary  * _Nullable )options
38
 - (void) sendRequest:(NSDictionary  * _Nullable )options
38
        contentLength:(long)contentLength
39
        contentLength:(long)contentLength
42
   taskOperationQueue:(NSOperationQueue * _Nonnull)operationQueue
43
   taskOperationQueue:(NSOperationQueue * _Nonnull)operationQueue
43
             callback:(_Nullable RCTResponseSenderBlock) callback;
44
             callback:(_Nullable RCTResponseSenderBlock) callback;
44
 
45
 
46
+- (void) cancelRequest:(NSString *)taskId;
47
+
45
 @end
48
 @end
46
 
49
 
47
 #endif /* RNFetchBlobRequest_h */
50
 #endif /* RNFetchBlobRequest_h */

+ 68
- 50
ios/RNFetchBlobRequest.m View File

11
 #import "RNFetchBlobFS.h"
11
 #import "RNFetchBlobFS.h"
12
 #import "RNFetchBlobConst.h"
12
 #import "RNFetchBlobConst.h"
13
 #import "RNFetchBlobReqBuilder.h"
13
 #import "RNFetchBlobReqBuilder.h"
14
+#if __has_include(<React/RCTLog.h>)
15
+#import <React/RCTLog.h>
16
+#else
17
+#import "RCTLog.h"
18
+#endif
14
 
19
 
15
 #import "IOS7Polyfill.h"
20
 #import "IOS7Polyfill.h"
16
 #import <CommonCrypto/CommonDigest.h>
21
 #import <CommonCrypto/CommonDigest.h>
17
 
22
 
23
+NSMapTable * taskTable;
24
+
25
+__attribute__((constructor))
26
+static void initialize_tables() {
27
+    if(taskTable == nil)
28
+    {
29
+        taskTable = [[NSMapTable alloc] init];
30
+    }
31
+}
18
 
32
 
19
 typedef NS_ENUM(NSUInteger, ResponseFormat) {
33
 typedef NS_ENUM(NSUInteger, ResponseFormat) {
20
     UTF8,
34
     UTF8,
36
     ResponseFormat responseFormat;
50
     ResponseFormat responseFormat;
37
     BOOL followRedirect;
51
     BOOL followRedirect;
38
     BOOL backgroundTask;
52
     BOOL backgroundTask;
53
+    BOOL uploadTask;
39
 }
54
 }
40
 
55
 
41
 @end
56
 @end
82
     self.options = options;
97
     self.options = options;
83
     
98
     
84
     backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue];
99
     backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue];
100
+    uploadTask = [options valueForKey:@"IOSUploadTask"] == nil ? NO : [[options valueForKey:@"IOSUploadTask"] boolValue];
101
+    
102
+    NSString * filepath = [options valueForKey:@"uploadFilePath"];
103
+    
85
     // when followRedirect not set in options, defaults to TRUE
104
     // when followRedirect not set in options, defaults to TRUE
86
     followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue];
105
     followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue];
87
     isIncrement = [[options valueForKey:@"increment"] boolValue];
106
     isIncrement = [[options valueForKey:@"increment"] boolValue];
104
     
123
     
105
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
124
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
106
     NSString * key = [self.options valueForKey:CONFIG_KEY];
125
     NSString * key = [self.options valueForKey:CONFIG_KEY];
107
-    NSURLSession * session;
108
     
126
     
109
     bodyLength = contentLength;
127
     bodyLength = contentLength;
110
     
128
     
117
         defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId];
135
         defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId];
118
     }
136
     }
119
     
137
     
138
+    
120
     // request timeout, -1 if not set in options
139
     // request timeout, -1 if not set in options
121
     float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue];
140
     float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue];
122
     
141
     
125
     }
144
     }
126
     
145
     
127
     defaultConfigObject.HTTPMaximumConnectionsPerHost = 10;
146
     defaultConfigObject.HTTPMaximumConnectionsPerHost = 10;
128
-    session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue];
147
+    _session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue];
129
     
148
     
130
     if (path || [self.options valueForKey:CONFIG_USE_TEMP]) {
149
     if (path || [self.options valueForKey:CONFIG_USE_TEMP]) {
131
         respFile = YES;
150
         respFile = YES;
157
         respFile = NO;
176
         respFile = NO;
158
     }
177
     }
159
     
178
     
160
-    self.task = [session dataTaskWithRequest:req];
161
-    [self.task resume];
179
+    __block NSURLSessionTask * task;
180
+    
181
+    if(uploadTask)
182
+    {
183
+        task = [_session uploadTaskWithRequest:req fromFile:[NSURL URLWithString:filepath]];
184
+    }
185
+    else
186
+    {
187
+        task = [_session dataTaskWithRequest:req];
188
+    }
189
+    
190
+    [taskTable setObject:task forKey:taskId];
191
+    [task resume];
162
     
192
     
163
     // network status indicator
193
     // network status indicator
164
     if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
194
     if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
182
 // set expected content length on response received
212
 // set expected content length on response received
183
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
213
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
184
 {
214
 {
215
+    NSLog(@"sess didReceiveResponse");
185
     expectedBytes = [response expectedContentLength];
216
     expectedBytes = [response expectedContentLength];
186
     
217
     
187
     NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
218
     NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
207
             
238
             
208
             partBuffer = [[NSMutableData alloc] init];
239
             partBuffer = [[NSMutableData alloc] init];
209
             completionHandler(NSURLSessionResponseAllow);
240
             completionHandler(NSURLSessionResponseAllow);
210
-
241
+            
211
             return;
242
             return;
212
         } else {
243
         } else {
213
             self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"];
244
             self.isServerPush = [[respCType lowercaseString] RNFBContainsString:@"multipart/x-mixed-replace;"];
269
         NSLog(@"oops");
300
         NSLog(@"oops");
270
     }
301
     }
271
     
302
     
272
-    if (respFile)
273
-    {
274
-        @try{
275
-            NSFileManager * fm = [NSFileManager defaultManager];
276
-            NSString * folder = [destPath stringByDeletingLastPathComponent];
277
-            
278
-            if (![fm fileExistsAtPath:folder]) {
279
-                [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
280
-            }
281
-            
282
-            // if not set overwrite in options, defaults to TRUE
283
-            BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue];
284
-            BOOL appendToExistingFile = [destPath RNFBContainsString:@"?append=true"];
285
-            
286
-            appendToExistingFile = !overwrite;
287
-            
288
-            // For solving #141 append response data if the file already exists
289
-            // base on PR#139 @kejinliang
290
-            if (appendToExistingFile) {
291
-                destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""];
292
-            }
293
-            
294
-            if (![fm fileExistsAtPath:destPath]) {
295
-                [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
296
-            }
297
-            
298
-            writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile];
299
-            [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
300
-            [writeStream open];
301
-        }
302
-        @catch(NSException * ex)
303
-        {
304
-            NSLog(@"write file error");
305
-        }
306
-    }
307
-    
308
     completionHandler(NSURLSessionResponseAllow);
303
     completionHandler(NSURLSessionResponseAllow);
309
 }
304
 }
310
 
305
 
328
         chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
323
         chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
329
     }
324
     }
330
     
325
     
331
-    if (respFile) {
332
-        [writeStream write:[data bytes] maxLength:[data length]];
333
-    } else {
334
-        [respData appendData:data];
335
-    }
326
+    [respData appendData:data];
336
     
327
     
337
     if (expectedBytes == 0) {
328
     if (expectedBytes == 0) {
338
         return;
329
         return;
353
     }
344
     }
354
 }
345
 }
355
 
346
 
347
+- (void) cancelRequest:(NSString *)taskId
348
+{
349
+    NSURLSessionDataTask * task = [taskTable objectForKey:taskId];
350
+    if(task != nil && task.state == NSURLSessionTaskStateRunning)
351
+        [task cancel];
352
+}
353
+
356
 - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error
354
 - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error
357
 {
355
 {
356
+    RCTLog(@"[RNFetchBlobRequest] session didBecomeInvalidWithError %@", [error description]);
358
     if ([session isEqual:session]) {
357
     if ([session isEqual:session]) {
359
         session = nil;
358
         session = nil;
360
     }
359
     }
363
 
362
 
364
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
363
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
365
 {
364
 {
366
-    
365
+    RCTLog(@"[RNFetchBlobRequest] session didCompleteWithError %@", [error description]);
367
     self.error = error;
366
     self.error = error;
368
     NSString * errMsg;
367
     NSString * errMsg;
369
     NSString * respStr;
368
     NSString * respStr;
416
                respStr ?: [NSNull null]
415
                respStr ?: [NSNull null]
417
                ]);
416
                ]);
418
     
417
     
418
+    @synchronized(taskTable)
419
+    {
420
+        if([taskTable objectForKey:taskId] == nil)
421
+            NSLog(@"object released by ARC.");
422
+        else
423
+            [taskTable removeObjectForKey:taskId];
424
+    }
425
+    
419
     respData = nil;
426
     respData = nil;
420
     receivedBytes = 0;
427
     receivedBytes = 0;
421
     [session finishTasksAndInvalidate];
428
     [session finishTasksAndInvalidate];
422
-    
423
 }
429
 }
424
 
430
 
425
 // upload progress handler
431
 // upload progress handler
430
     }
436
     }
431
     
437
     
432
     NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)];
438
     NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)];
433
-
439
+    
434
     if ([self.uploadProgressConfig shouldReport:now]) {
440
     if ([self.uploadProgressConfig shouldReport:now]) {
435
         [self.bridge.eventDispatcher
441
         [self.bridge.eventDispatcher
436
          sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD
442
          sendDeviceEventWithName:EVENT_PROGRESS_UPLOAD
456
 
462
 
457
 - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
463
 - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
458
 {
464
 {
459
-    NSLog(@"sess done in background");
465
+    RCTLog(@"[RNFetchBlobRequest] session done in background");
466
+    dispatch_async(dispatch_get_main_queue(), ^{
467
+        id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
468
+        SEL selector = NSSelectorFromString(@"backgroundTransferCompletionHandler");
469
+        if ([appDelegate respondsToSelector:selector]) {
470
+            void(^completionHandler)() = [appDelegate performSelector:selector];
471
+            if (completionHandler != nil) {
472
+                completionHandler();
473
+                completionHandler = nil;
474
+            }
475
+        }
476
+        
477
+    });
460
 }
478
 }
461
 
479
 
462
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler
480
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler