瀏覽代碼

#3 Add ios from-file upload support

Ben Hsieh 8 年之前
父節點
當前提交
b2e9e6202c
共有 2 個檔案被更改,包括 102 行新增64 行删除
  1. 10
    1
      src/ios/RNFetchBlob/RNFetchBlob.h
  2. 92
    63
      src/ios/RNFetchBlob/RNFetchBlob.m

+ 10
- 1
src/ios/RNFetchBlob/RNFetchBlob.h 查看文件

@@ -14,6 +14,7 @@ extern NSString *const MSG_EVENT;
14 14
 extern NSString *const MSG_EVENT_LOG;
15 15
 extern NSString *const MSG_EVENT_WARN;
16 16
 extern NSString *const MSG_EVENT_ERROR;
17
+extern NSString *const FILE_PREFIX;
17 18
 
18 19
 // config
19 20
 extern NSString *const CONFIG_USE_TEMP;
@@ -87,7 +88,15 @@ extern NSString *const FS_EVENT_ERROR;
87 88
 @end
88 89
 
89 90
 
90
-@interface RNFetchBlob : NSObject <RCTBridgeModule>
91
+@interface RNFetchBlob : NSObject <RCTBridgeModule> {
92
+
93
+    NSString * filePathPrefix;
94
+
95
+}
96
+
97
+@property (nonatomic) NSString * filePathPrefix;
98
+
99
+
91 100
 
92 101
 @end
93 102
 

+ 92
- 63
src/ios/RNFetchBlob/RNFetchBlob.m 查看文件

@@ -11,6 +11,8 @@
11 11
 #import "RCTBridge.h"
12 12
 #import "RCTEventDispatcher.h"
13 13
 
14
+NSString *const FILE_PREFIX = @"RNFetchBlob-file://";
15
+
14 16
 // fetch configs
15 17
 NSString *const CONFIG_USE_TEMP = @"fileCache";
16 18
 NSString *const CONFIG_FILE_PATH = @"path";
@@ -241,7 +243,7 @@ void runOnMainQueueWithoutDeadlocking(void (^block)(void))
241 243
              sendDeviceEventWithName:streamEventCode
242 244
              body:@{
243 245
                     @"event": FS_EVENT_ERROR,
244
-                    @"detail": @"error when read file with stream"
246
+                    @"detail": @"RNFetchBlob error when read file with stream, file may not exists"
245 247
                 }
246 248
              ];
247 249
             break;
@@ -330,7 +332,7 @@ void runOnMainQueueWithoutDeadlocking(void (^block)(void))
330 332
 
331 333
 
332 334
 - (void) connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
333
-    receivedBytes += data.length;
335
+    receivedBytes += [data length];
334 336
     
335 337
     Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
336 338
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
@@ -435,10 +437,17 @@ void runOnMainQueueWithoutDeadlocking(void (^block)(void))
435 437
 
436 438
 @implementation RNFetchBlob
437 439
 
440
+@synthesize filePathPrefix;
438 441
 @synthesize bridge = _bridge;
439 442
 
440 443
 RCT_EXPORT_MODULE();
441 444
 
445
+- (id) init {
446
+    self = [super init];
447
+    self.filePathPrefix = FILE_PREFIX;
448
+    return self;
449
+}
450
+
442 451
 // Fetch blob data request
443 452
 RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
444 453
                   taskId:(NSString *)taskId
@@ -462,53 +471,62 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
462 471
     
463 472
     // generate boundary
464 473
     NSString * boundary = [NSString stringWithFormat:@"RNFetchBlob%d", timeStampObj];
465
-    
466
-    // if method is POST or PUT, convert data string format
467
-    if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
474
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
475
+        // if method is POST or PUT, convert data string format
476
+        if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
468 477
         NSMutableData * postData = [[NSMutableData alloc] init];
469 478
         
470
-        // combine multipart/form-data body
471
-        for(id field in form) {
472
-            NSString * name = [field valueForKey:@"name"];
473
-            NSString * content = [field valueForKey:@"data"];
474
-            // field is a text field
475
-            if([field valueForKey:@"filename"] == nil || content == [NSNull null]) {
476
-                [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
477
-                [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
478
-                [postData appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
479
-                [postData appendData:[[NSString stringWithFormat:@"%@\r\n", content] dataUsingEncoding:NSUTF8StringEncoding]];
480
-            }
481
-            // field contains a file
482
-            else {
483
-                NSData* blobData = [[NSData alloc] initWithBase64EncodedString:content options:0];
484
-                NSString * filename = [field valueForKey:@"filename"];
485
-                [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
486
-                [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
487
-                [postData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
488
-                [postData appendData:blobData];
489
-                [postData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
479
+            // combine multipart/form-data body
480
+            for(id field in form) {
481
+                NSString * name = [field valueForKey:@"name"];
482
+                NSString * content = [field valueForKey:@"data"];
483
+                // field is a text field
484
+                if([field valueForKey:@"filename"] == nil || content == [NSNull null]) {
485
+                    [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
486
+                    [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
487
+                    [postData appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
488
+                    [postData appendData:[[NSString stringWithFormat:@"%@\r\n", content] dataUsingEncoding:NSUTF8StringEncoding]];
489
+                }
490
+                // field contains a file
491
+                else {
492
+                    NSMutableData * blobData = [NSMutableData alloc];
493
+                    if(content != nil) {
494
+                        if([content hasPrefix:self.filePathPrefix]) {
495
+                            NSString * orgPath = [content substringFromIndex:[self.filePathPrefix length]];
496
+                            [blobData initWithContentsOfFile:orgPath];
497
+                        }
498
+                        else
499
+                            [blobData initWithBase64EncodedString:content options:0];
500
+                    }
501
+                    NSString * filename = [field valueForKey:@"filename"];
502
+                    [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
503
+                    [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
504
+                    [postData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
505
+                    [postData appendData:blobData];
506
+                    [postData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
507
+                }
508
+                
490 509
             }
491
-            
510
+        
511
+            // close form data
512
+            [postData appendData: [[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
513
+            [request setHTTPBody:postData];
514
+            // set content-length
515
+            [mheaders setValue:[NSString stringWithFormat:@"%d",[postData length]] forKey:@"Content-Length"];
516
+            [mheaders setValue:[NSString stringWithFormat:@"100-continue",[postData length]] forKey:@"Expect"];
517
+            // appaned boundary to content-type
518
+            [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forKey:@"content-type"];
519
+        
492 520
         }
493
-        // close form data
494
-        [postData appendData: [[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
495
-        [request setHTTPBody:postData];
496
-        // set content-length
497
-        [mheaders setValue:[NSString stringWithFormat:@"%d",[postData length]] forKey:@"Content-Length"];
498
-        [mheaders setValue:[NSString stringWithFormat:@"100-continue",[postData length]] forKey:@"Expect"];
499
-        // appaned boundary to content-type
500
-        [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forKey:@"content-type"];
501 521
         
502
-    }
503
-    
504
-    [request setHTTPMethod: method];
505
-    [request setAllHTTPHeaderFields:mheaders];
506
-    
507
-    
508
-    // send HTTP request
509
-    FetchBlobUtils * utils = [[FetchBlobUtils alloc] init];
510
-    [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
511
-    
522
+        [request setHTTPMethod: method];
523
+        [request setAllHTTPHeaderFields:mheaders];
524
+        
525
+        
526
+        // send HTTP request
527
+        FetchBlobUtils * utils = [[FetchBlobUtils alloc] init];
528
+        [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
529
+    });
512 530
 }
513 531
 
514 532
 // Fetch blob data request
@@ -525,27 +543,35 @@ RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
525 543
                                                  URLWithString: url]];
526 544
     
527 545
     NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[FetchBlobUtils normalizeHeaders:headers]];
528
-
529
-    // if method is POST or PUT, convert data string format
530
-    if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
531
-        
532
-        if(body != nil) {
546
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
547
+        // if method is POST or PUT, convert data string format
548
+        if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
533 549
             // generate octet-stream body
534
-            NSData* blobData = [[NSData alloc] initWithBase64EncodedString:body options:0];
535
-            NSMutableData* postBody = [[NSMutableData alloc] init];
536
-            [postBody appendData:[NSData dataWithData:blobData]];
537
-            [request setHTTPBody:postBody];
538
-            [mheaders setValue:@"application/octet-stream" forKey:@"content-type"];
550
+            if(body != nil) {
551
+                NSMutableData * blobData = [NSData alloc];
552
+                // move heavy task to another thread
553
+                
554
+                // when body is a string contains file path prefix, try load file from the path
555
+                if([body hasPrefix:self.filePathPrefix]) {
556
+                    NSString * orgPath = [body substringFromIndex:[self.filePathPrefix length]];
557
+                    [blobData initWithContentsOfFile: orgPath];
558
+                }
559
+                // otherwise convert it as BASE64 data string
560
+                else
561
+                    blobData = [[NSData alloc] initWithBase64EncodedString:body options:0];
562
+                [request setHTTPBody:blobData];
563
+                [mheaders setValue:@"application/octet-stream" forKey:@"content-type"];
564
+                
565
+            }
539 566
         }
540
-    }
541
-    
542
-    [request setHTTPMethod: method];
543
-    [request setAllHTTPHeaderFields:mheaders];
544
-    
545
-    // send HTTP request
546
-    FetchBlobUtils * utils = [[FetchBlobUtils alloc] init];
547
-    [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
548
-    
567
+        
568
+        [request setHTTPMethod: method];
569
+        [request setAllHTTPHeaderFields:mheaders];
570
+        
571
+        // send HTTP request
572
+        FetchBlobUtils * utils = [[FetchBlobUtils alloc] init];
573
+        [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
574
+    });
549 575
 }
550 576
 
551 577
 RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding) {
@@ -569,4 +595,7 @@ RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
569 595
             ]);
570 596
 }
571 597
 
598
+#pragma mark RNFetchBlob private methods
599
+
600
+
572 601
 @end