Browse Source

#3 Add ios from-file upload support

Ben Hsieh 8 years ago
parent
commit
b2e9e6202c
2 changed files with 102 additions and 64 deletions
  1. 10
    1
      src/ios/RNFetchBlob/RNFetchBlob.h
  2. 92
    63
      src/ios/RNFetchBlob/RNFetchBlob.m

+ 10
- 1
src/ios/RNFetchBlob/RNFetchBlob.h View File

14
 extern NSString *const MSG_EVENT_LOG;
14
 extern NSString *const MSG_EVENT_LOG;
15
 extern NSString *const MSG_EVENT_WARN;
15
 extern NSString *const MSG_EVENT_WARN;
16
 extern NSString *const MSG_EVENT_ERROR;
16
 extern NSString *const MSG_EVENT_ERROR;
17
+extern NSString *const FILE_PREFIX;
17
 
18
 
18
 // config
19
 // config
19
 extern NSString *const CONFIG_USE_TEMP;
20
 extern NSString *const CONFIG_USE_TEMP;
87
 @end
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
 @end
101
 @end
93
 
102
 

+ 92
- 63
src/ios/RNFetchBlob/RNFetchBlob.m View File

11
 #import "RCTBridge.h"
11
 #import "RCTBridge.h"
12
 #import "RCTEventDispatcher.h"
12
 #import "RCTEventDispatcher.h"
13
 
13
 
14
+NSString *const FILE_PREFIX = @"RNFetchBlob-file://";
15
+
14
 // fetch configs
16
 // fetch configs
15
 NSString *const CONFIG_USE_TEMP = @"fileCache";
17
 NSString *const CONFIG_USE_TEMP = @"fileCache";
16
 NSString *const CONFIG_FILE_PATH = @"path";
18
 NSString *const CONFIG_FILE_PATH = @"path";
241
              sendDeviceEventWithName:streamEventCode
243
              sendDeviceEventWithName:streamEventCode
242
              body:@{
244
              body:@{
243
                     @"event": FS_EVENT_ERROR,
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
             break;
249
             break;
330
 
332
 
331
 
333
 
332
 - (void) connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
334
 - (void) connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
333
-    receivedBytes += data.length;
335
+    receivedBytes += [data length];
334
     
336
     
335
     Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
337
     Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
336
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
338
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
435
 
437
 
436
 @implementation RNFetchBlob
438
 @implementation RNFetchBlob
437
 
439
 
440
+@synthesize filePathPrefix;
438
 @synthesize bridge = _bridge;
441
 @synthesize bridge = _bridge;
439
 
442
 
440
 RCT_EXPORT_MODULE();
443
 RCT_EXPORT_MODULE();
441
 
444
 
445
+- (id) init {
446
+    self = [super init];
447
+    self.filePathPrefix = FILE_PREFIX;
448
+    return self;
449
+}
450
+
442
 // Fetch blob data request
451
 // Fetch blob data request
443
 RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
452
 RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
444
                   taskId:(NSString *)taskId
453
                   taskId:(NSString *)taskId
462
     
471
     
463
     // generate boundary
472
     // generate boundary
464
     NSString * boundary = [NSString stringWithFormat:@"RNFetchBlob%d", timeStampObj];
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
         NSMutableData * postData = [[NSMutableData alloc] init];
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
 // Fetch blob data request
532
 // Fetch blob data request
525
                                                  URLWithString: url]];
543
                                                  URLWithString: url]];
526
     
544
     
527
     NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[FetchBlobUtils normalizeHeaders:headers]];
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
             // generate octet-stream body
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
 RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding) {
577
 RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding) {
569
             ]);
595
             ]);
570
 }
596
 }
571
 
597
 
598
+#pragma mark RNFetchBlob private methods
599
+
600
+
572
 @end
601
 @end