Browse Source

Fix IOS ALAsset upload issue #45

Ben Hsieh 8 years ago
parent
commit
23eee765d6

+ 6
- 0
src/ios/RNFetchBlob.xcodeproj/project.pbxproj View File

12
 		A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */; };
12
 		A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */; };
13
 		A15C30141CD25C330074CB35 /* RNFetchBlob.m in Sources */ = {isa = PBXBuildFile; fileRef = A15C30131CD25C330074CB35 /* RNFetchBlob.m */; };
13
 		A15C30141CD25C330074CB35 /* RNFetchBlob.m in Sources */ = {isa = PBXBuildFile; fileRef = A15C30131CD25C330074CB35 /* RNFetchBlob.m */; };
14
 		A166D1AA1CE0647A00273590 /* RNFetchBlob.h in Sources */ = {isa = PBXBuildFile; fileRef = A15C30111CD25C330074CB35 /* RNFetchBlob.h */; };
14
 		A166D1AA1CE0647A00273590 /* RNFetchBlob.h in Sources */ = {isa = PBXBuildFile; fileRef = A15C30111CD25C330074CB35 /* RNFetchBlob.h */; };
15
+		A1AAE2991D300E4D0051D11C /* RNFetchBlobReqBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = A1AAE2981D300E4D0051D11C /* RNFetchBlobReqBuilder.m */; };
15
 /* End PBXBuildFile section */
16
 /* End PBXBuildFile section */
16
 
17
 
17
 /* Begin PBXCopyFilesBuildPhase section */
18
 /* Begin PBXCopyFilesBuildPhase section */
36
 		A15C300E1CD25C330074CB35 /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFetchBlob.a; sourceTree = BUILT_PRODUCTS_DIR; };
37
 		A15C300E1CD25C330074CB35 /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFetchBlob.a; sourceTree = BUILT_PRODUCTS_DIR; };
37
 		A15C30111CD25C330074CB35 /* RNFetchBlob.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFetchBlob.h; path = RNFetchBlob/RNFetchBlob.h; sourceTree = "<group>"; };
38
 		A15C30111CD25C330074CB35 /* RNFetchBlob.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFetchBlob.h; path = RNFetchBlob/RNFetchBlob.h; sourceTree = "<group>"; };
38
 		A15C30131CD25C330074CB35 /* RNFetchBlob.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFetchBlob.m; path = RNFetchBlob/RNFetchBlob.m; sourceTree = "<group>"; };
39
 		A15C30131CD25C330074CB35 /* RNFetchBlob.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFetchBlob.m; path = RNFetchBlob/RNFetchBlob.m; sourceTree = "<group>"; };
40
+		A1AAE2971D300E3E0051D11C /* RNFetchBlobReqBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobReqBuilder.h; sourceTree = "<group>"; };
41
+		A1AAE2981D300E4D0051D11C /* RNFetchBlobReqBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobReqBuilder.m; sourceTree = "<group>"; };
39
 /* End PBXFileReference section */
42
 /* End PBXFileReference section */
40
 
43
 
41
 /* Begin PBXFrameworksBuildPhase section */
44
 /* Begin PBXFrameworksBuildPhase section */
59
 		A15C30051CD25C330074CB35 = {
62
 		A15C30051CD25C330074CB35 = {
60
 			isa = PBXGroup;
63
 			isa = PBXGroup;
61
 			children = (
64
 			children = (
65
+				A1AAE2981D300E4D0051D11C /* RNFetchBlobReqBuilder.m */,
66
+				A1AAE2971D300E3E0051D11C /* RNFetchBlobReqBuilder.h */,
62
 				A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */,
67
 				A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */,
63
 				A158F42E1D0539CE006FFD38 /* RNFetchBlobNetwork.h */,
68
 				A158F42E1D0539CE006FFD38 /* RNFetchBlobNetwork.h */,
64
 				A158F42C1D0535BB006FFD38 /* RNFetchBlobConst.m */,
69
 				A158F42C1D0535BB006FFD38 /* RNFetchBlobConst.m */,
140
 				A158F42D1D0535BB006FFD38 /* RNFetchBlobConst.m in Sources */,
145
 				A158F42D1D0535BB006FFD38 /* RNFetchBlobConst.m in Sources */,
141
 				A158F4271D052E49006FFD38 /* RNFetchBlobFS.m in Sources */,
146
 				A158F4271D052E49006FFD38 /* RNFetchBlobFS.m in Sources */,
142
 				A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */,
147
 				A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */,
148
+				A1AAE2991D300E4D0051D11C /* RNFetchBlobReqBuilder.m in Sources */,
143
 				A15C30141CD25C330074CB35 /* RNFetchBlob.m in Sources */,
149
 				A15C30141CD25C330074CB35 /* RNFetchBlob.m in Sources */,
144
 			);
150
 			);
145
 			runOnlyForDeploymentPostprocessing = 0;
151
 			runOnlyForDeploymentPostprocessing = 0;

+ 11
- 114
src/ios/RNFetchBlob/RNFetchBlob.m View File

12
 #import "RNFetchBlobFS.h"
12
 #import "RNFetchBlobFS.h"
13
 #import "RNFetchBlobNetwork.h"
13
 #import "RNFetchBlobNetwork.h"
14
 #import "RNFetchBlobConst.h"
14
 #import "RNFetchBlobConst.h"
15
+#import "RNFetchBlobReqBuilder.h"
15
 
16
 
16
 
17
 
17
 ////////////////////////////////////////
18
 ////////////////////////////////////////
61
                   form:(NSArray *)form
62
                   form:(NSArray *)form
62
                   callback:(RCTResponseSenderBlock)callback)
63
                   callback:(RCTResponseSenderBlock)callback)
63
 {
64
 {
64
-    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
65
-    // send request
66
-    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
67
-                                    initWithURL:[NSURL
68
-                                                 URLWithString: encodedUrl]];
69
     
65
     
70
-    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ RNFetchBlobNetwork normalizeHeaders:headers]];
71
-    
72
-    
73
-    NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
74
-    NSNumber * timeStampObj = [NSNumber numberWithDouble: timeStamp];
75
-    
76
-    // generate boundary
77
-    NSString * boundary = [NSString stringWithFormat:@"RNFetchBlob%d", timeStampObj];
78
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
79
-        NSMutableData * postData = [[NSMutableData alloc] init];
80
-        // if method is POST or PUT, convert data string format
81
-        if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
82
-            
83
-            // combine multipart/form-data body
84
-            for(id field in form) {
85
-                NSString * name = [field valueForKey:@"name"];
86
-                NSString * content = [field valueForKey:@"data"];
87
-                // field is a text field
88
-                if([field valueForKey:@"filename"] == nil || content == [NSNull null]) {
89
-                    [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
90
-                    [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
91
-                    [postData appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
92
-                    [postData appendData:[[NSString stringWithFormat:@"%@\r\n", content] dataUsingEncoding:NSUTF8StringEncoding]];
93
-                }
94
-                // field contains a file
95
-                else {
96
-                    NSMutableData * blobData;
97
-                    if(content != nil) {
98
-                        if([content hasPrefix:self.filePathPrefix]) {
99
-                            NSString * orgPath = [content substringFromIndex:[self.filePathPrefix length]];
100
-                            orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
101
-                            blobData = [[NSData alloc] initWithContentsOfFile:orgPath];
102
-                        }
103
-                        else
104
-                            blobData = [[NSData alloc] initWithBase64EncodedString:content options:0];
105
-                    }
106
-                    NSString * filename = [field valueForKey:@"filename"];
107
-                    [postData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
108
-                    [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
109
-                    [postData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
110
-                    [postData appendData:blobData];
111
-                    [postData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
112
-                }
113
-                
114
-            }
115
-            
116
-            // close form data
117
-            [postData appendData: [[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
118
-            [request setHTTPBody:postData];
119
-            // set content-length
120
-            [mheaders setValue:[NSString stringWithFormat:@"%d",[postData length]] forKey:@"Content-Length"];
121
-            [mheaders setValue:[NSString stringWithFormat:@"100-continue",[postData length]] forKey:@"Expect"];
122
-            // appaned boundary to content-type
123
-            [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forKey:@"content-type"];
124
-            
125
-        }
126
-        
127
-        [request setHTTPMethod: method];
128
-        [request setAllHTTPHeaderFields:mheaders];
129
-        
130
-        
66
+    [RNFetchBlobReqBuilder buildMultipartRequest:options taskId:taskId method:method url:url headers:headers form:form onComplete:^(NSURLRequest *req) {
131
         // send HTTP request
67
         // send HTTP request
132
         RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
68
         RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
133
-        [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
69
+        [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:req callback:callback];
134
         utils = nil;
70
         utils = nil;
135
-    });
71
+    }];
72
+    
136
 }
73
 }
137
 
74
 
138
 // Fetch blob data request
75
 // Fetch blob data request
143
                   headers:(NSDictionary *)headers
80
                   headers:(NSDictionary *)headers
144
                   body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
81
                   body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
145
 {
82
 {
146
-    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
147
-    // send request
148
-    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
149
-                                    initWithURL:[NSURL
150
-                                                 URLWithString: encodedUrl]];
151
-    
152
-    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
153
-    // move heavy task to another thread
154
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
155
-        NSMutableData * blobData;
156
-        // if method is POST or PUT, convert data string format
157
-        if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
158
-            // generate octet-stream body
159
-            if(body != nil) {
160
-                
161
-                // when body is a string contains file path prefix, try load file from the path
162
-                if([body hasPrefix:self.filePathPrefix]) {
163
-                    NSString * orgPath = [body substringFromIndex:[self.filePathPrefix length]];
164
-                    orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
165
-                    [request setHTTPBodyStream: [NSInputStream inputStreamWithFileAtPath:orgPath ]];
166
-                }
167
-                // otherwise convert it as BASE64 data string
168
-                else {
169
-                    blobData = [[NSData alloc] initWithBase64EncodedString:body options:0];
170
-                    [request setHTTPBody:blobData];
171
-                }
172
-                
173
-                [mheaders setValue:@"application/octet-stream" forKey:@"content-type"];
174
-                
175
-            }
176
-        }
177
-        
178
-        [request setHTTPMethod: method];
179
-        [request setAllHTTPHeaderFields:mheaders];
180
-        
83
+    [RNFetchBlobReqBuilder buildOctetRequest:options taskId:taskId method:method url:url headers:headers body:body onComplete:^(NSURLRequest *req) {
181
         // send HTTP request
84
         // send HTTP request
182
         RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
85
         RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
183
-        [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
86
+        [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:req callback:callback];
184
         utils = nil;
87
         utils = nil;
185
-    });
88
+    }];
89
+    
186
 }
90
 }
187
 
91
 
188
 RCT_EXPORT_METHOD(createFile:(NSString *)path data:(NSString *)data encoding:(NSString *)encoding callback:(RCTResponseSenderBlock)callback) {
92
 RCT_EXPORT_METHOD(createFile:(NSString *)path data:(NSString *)data encoding:(NSString *)encoding callback:(RCTResponseSenderBlock)callback) {
419
 
323
 
420
 RCT_EXPORT_METHOD(readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
324
 RCT_EXPORT_METHOD(readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
421
     
325
     
422
-    [RNFetchBlobFS readFile:path encoding:encoding resolver:resolve rejecter:reject];
326
+    [RNFetchBlobFS readFile:path encoding:encoding resolver:resolve rejecter:reject onComplete:nil];
423
 })
327
 })
424
 
328
 
425
 RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
329
 RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
432
             bufferSize = 4096;
336
             bufferSize = 4096;
433
     }
337
     }
434
     // read asset stream
338
     // read asset stream
435
-    if([path hasPrefix:@"assets-library://"])
436
-    {
437
-        
438
-    }
439
-    else
440
-    {
441
-        [fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
442
-    }
339
+    [fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
443
 }
340
 }
444
 
341
 
445
 RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
342
 RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {

+ 3
- 0
src/ios/RNFetchBlobConst.h View File

16
 extern NSString *const MSG_EVENT_LOG;
16
 extern NSString *const MSG_EVENT_LOG;
17
 extern NSString *const MSG_EVENT_WARN;
17
 extern NSString *const MSG_EVENT_WARN;
18
 extern NSString *const MSG_EVENT_ERROR;
18
 extern NSString *const MSG_EVENT_ERROR;
19
+
19
 extern NSString *const FILE_PREFIX;
20
 extern NSString *const FILE_PREFIX;
21
+extern NSString *const ASSET_PREFIX;
22
+extern NSString *const AL_PREFIX;
20
 
23
 
21
 // config
24
 // config
22
 extern NSString *const CONFIG_USE_TEMP;
25
 extern NSString *const CONFIG_USE_TEMP;

+ 4
- 0
src/ios/RNFetchBlobConst.m View File

8
 #import "RNFetchBlobConst.h"
8
 #import "RNFetchBlobConst.h"
9
 
9
 
10
 extern NSString *const FILE_PREFIX = @"RNFetchBlob-file://";
10
 extern NSString *const FILE_PREFIX = @"RNFetchBlob-file://";
11
+extern NSString *const ASSET_PREFIX = @"bundle-assets://";
12
+extern NSString *const AL_PREFIX = @"assets-library://";
13
+
14
+
11
 
15
 
12
 // fetch configs
16
 // fetch configs
13
 extern NSString *const CONFIG_USE_TEMP = @"fileCache";
17
 extern NSString *const CONFIG_USE_TEMP = @"fileCache";

+ 4
- 2
src/ios/RNFetchBlobFS.h View File

11
 
11
 
12
 #import <Foundation/Foundation.h>
12
 #import <Foundation/Foundation.h>
13
 #import "RCTBridgeModule.h"
13
 #import "RCTBridgeModule.h"
14
+@import AssetsLibrary;
14
 
15
 
15
 @interface RNFetchBlobFS : NSObject <NSStreamDelegate>  {
16
 @interface RNFetchBlobFS : NSObject <NSStreamDelegate>  {
16
     NSOutputStream * outStream;
17
     NSOutputStream * outStream;
42
 + (NSString *) getCacheDir;
43
 + (NSString *) getCacheDir;
43
 + (NSString *) getDocumentDir;
44
 + (NSString *) getDocumentDir;
44
 + (NSString *) getTempPath:(NSString*)taskId withExtension:(NSString *)ext;
45
 + (NSString *) getTempPath:(NSString*)taskId withExtension:(NSString *)ext;
46
++ (NSString *) getPathOfAsset:(NSString *)assetURI;
47
++ (void) getPathFromUri:(NSString *)uri completionHandler:(void(^)(NSString * path, ALAssetRepresentation *asset)) onComplete;
45
 
48
 
46
 // fs methods
49
 // fs methods
47
 + (RNFetchBlobFS *) getFileStreams;
50
 + (RNFetchBlobFS *) getFileStreams;
50
 + (BOOL) exists:(NSString *) path;
53
 + (BOOL) exists:(NSString *) path;
51
 + (void) writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
54
 + (void) writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
52
 + (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
55
 + (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
53
-+ (void) readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
56
++ (void) readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject onComplete:(void (^)(NSData * content))onComplete;
54
 + (void) readAssetFile:(NSData *)assetUrl completionBlock:(void(^)(NSData * content))completionBlock failBlock:(void(^)(NSError * err))failBlock;
57
 + (void) readAssetFile:(NSData *)assetUrl completionBlock:(void(^)(NSData * content))completionBlock failBlock:(void(^)(NSError * err))failBlock;
55
-+ (NSString *) getPathOfAsset:(NSString *)assetURI;
56
 
58
 
57
 // constructor
59
 // constructor
58
 - (id) init;
60
 - (id) init;

+ 72
- 86
src/ios/RNFetchBlobFS.m View File

15
 #import "RNFetchBlobFS.h"
15
 #import "RNFetchBlobFS.h"
16
 #import "RNFetchBlobConst.h"
16
 #import "RNFetchBlobConst.h"
17
 @import AssetsLibrary;
17
 @import AssetsLibrary;
18
-@import Photos;
18
+
19
 
19
 
20
 NSMutableDictionary *fileStreams = nil;
20
 NSMutableDictionary *fileStreams = nil;
21
 
21
 
54
 +(NSString *) getPathOfAsset:(NSString *)assetURI
54
 +(NSString *) getPathOfAsset:(NSString *)assetURI
55
 {
55
 {
56
     // get file path of an app asset
56
     // get file path of an app asset
57
-    if([assetURI hasPrefix:@"bundle-assets://"])
57
+    if([assetURI hasPrefix:ASSET_PREFIX])
58
     {
58
     {
59
-        assetURI = [assetURI stringByReplacingOccurrencesOfString:@"bundle-assets://" withString:@""];
59
+        assetURI = [assetURI stringByReplacingOccurrencesOfString:ASSET_PREFIX withString:@""];
60
         assetURI = [[NSBundle mainBundle] pathForResource: [assetURI stringByDeletingPathExtension]
60
         assetURI = [[NSBundle mainBundle] pathForResource: [assetURI stringByDeletingPathExtension]
61
                                                ofType: [assetURI pathExtension]];
61
                                                ofType: [assetURI pathExtension]];
62
     }
62
     }
98
     return tempPath;
98
     return tempPath;
99
 }
99
 }
100
 
100
 
101
-- (void) startAssetReadStream:(NSData *)assetUrl
101
+- (void) startAssetReadStream:(NSString *)assetUrl
102
 {
102
 {
103
     ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
103
     ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
104
     {
104
     {
185
     }
185
     }
186
 }
186
 }
187
 
187
 
188
-// read system asset file
189
-+ (void) readAssetFile:(NSData *)assetUrl completionBlock:(void(^)(NSData * content))completionBlock failBlock:(void(^)(NSError * err))failBlock
190
-{
191
-    
192
-    ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
193
-    {
194
-        ALAssetRepresentation *rep = [myasset defaultRepresentation];
195
-        Byte *buffer = (Byte*)malloc(rep.size);
196
-        NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
197
-        NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
198
-        completionBlock(data);
199
-    };
200
-    
201
-    ALAssetsLibraryAccessFailureBlock failureblock  = ^(NSError *error)
202
-    {
203
-        failBlock(error);
204
-    };
205
-    
206
-    if(assetUrl && [assetUrl length])
207
-    {
208
-        NSURL *asseturl = [NSURL URLWithString:assetUrl];
209
-        ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
210
-        [assetslibrary assetForURL:asseturl
211
-                       resultBlock:resultblock
212
-                      failureBlock:failureblock];
213
-    }
214
-}
215
-
216
 + (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
188
 + (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
217
     @try {
189
     @try {
218
         NSFileManager * fm = [NSFileManager defaultManager];
190
         NSFileManager * fm = [NSFileManager defaultManager];
301
     }
273
     }
302
 }
274
 }
303
 
275
 
304
-+ (void) readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
276
++ (void) readFile:(NSString *)path encoding:(NSString *)encoding
277
+         resolver:(RCTPromiseResolveBlock)resolve
278
+         rejecter:(RCTPromiseRejectBlock)reject
279
+       onComplete:(void (^)(NSData * content))onComplete
280
+{
305
     @try
281
     @try
306
     {
282
     {
307
-        // before start reading file, we have to check if the `path` contains any special prefix
308
-        // if the `path` begins with the following prefix then it will need special handling.
309
-        //      "assets-library://" this kind of path usually comes from camera roll, should use it's own readFile implementation
310
-        //      "bundle-assets://" this means an asset inside app bundle, usually we only have to convert it into normal file path
311
-        if([path hasPrefix:@"assets-library://"])
312
-        {
313
-            [[self class] readAssetFile:path completionBlock:^(NSData * content)
283
+        [[self class] getPathFromUri:path completionHandler:^(NSString *path, ALAssetRepresentation *asset) {
284
+            NSData * fileContent;
285
+            NSError * err;
286
+            if(asset != nil)
287
+            {
288
+                Byte * buffer = malloc(asset.size);
289
+                [asset getBytes:buffer fromOffset:0 length:asset.size error:&err];
290
+                if(err != nil)
291
+                {
292
+                    reject(@"RNFetchBlobFS readFile error", @"failed to read asset", [err localizedDescription]);
293
+                    return;
294
+                }
295
+                fileContent = [NSData dataWithBytes:buffer length:asset.size];
296
+                if(onComplete != nil)
297
+                    onComplete(fileContent);
298
+                free(buffer);
299
+            }
300
+            else
314
             {
301
             {
315
-                if([[encoding lowercaseString] isEqualToString:@"utf8"]) {
316
-                    resolve([[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding]);
302
+                BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path];
303
+                if(!exists) {
304
+                    reject(@"RNFetchBlobFS readFile error", @"file not exists", path);
305
+                    return;
317
                 }
306
                 }
318
-                else if ([[encoding lowercaseString] isEqualToString:@"base64"]) {
319
-                    resolve([content base64EncodedStringWithOptions:0]);
307
+                fileContent = [NSData dataWithContentsOfFile:path];
308
+            }
309
+            
310
+            if([[encoding lowercaseString] isEqualToString:@"utf8"]) {
311
+                if(resolve != nil)
312
+                    resolve([[NSString alloc] initWithData:fileContent encoding:NSUTF8StringEncoding]);
313
+            }
314
+            else if ([[encoding lowercaseString] isEqualToString:@"base64"]) {
315
+                if(resolve != nil)
316
+                    resolve([fileContent base64EncodedStringWithOptions:0]);
317
+            }
318
+            else if ([[encoding lowercaseString] isEqualToString:@"ascii"]) {
319
+                NSMutableArray * resultArray = [NSMutableArray array];
320
+                char * bytes = [fileContent bytes];
321
+                for(int i=0;i<[fileContent length];i++) {
322
+                    [resultArray addObject:[NSNumber numberWithChar:bytes[i]]];
320
                 }
323
                 }
321
-                else if ([[encoding lowercaseString] isEqualToString:@"ascii"]) {
322
-                    NSMutableArray * resultArray = [NSMutableArray array];
323
-                    char * bytes = [content bytes];
324
-                    for(int i=0;i<[content length];i++) {
325
-                        [resultArray addObject:[NSNumber numberWithChar:bytes[i]]];
326
-                    }
324
+                if(resolve != nil)
327
                     resolve(resultArray);
325
                     resolve(resultArray);
328
-                }
329
-            } failBlock:^(NSError *err) {
330
-                @throw @"RNFetchBlobFS readFile error", @"failed to read asset", path;
331
-            }];
332
-            return ;
333
-        }
334
-        
335
-        // normalize the file path
336
-        path = [[self class]getPathOfAsset:path];
337
-        
338
-        NSFileManager * fm = [NSFileManager defaultManager];
339
-        NSError *err = nil;
340
-        BOOL exists = [fm fileExistsAtPath:path];
341
-        if(!exists) {
342
-            @throw @"RNFetchBlobFS readFile error", @"file not exists", path;
343
-            return;
344
-        }
345
-        if([[encoding lowercaseString] isEqualToString:@"utf8"]) {
346
-            NSString * utf8Result = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&err];
347
-            resolve(utf8Result);
348
-        }
349
-        else if ([[encoding lowercaseString] isEqualToString:@"base64"]) {
350
-            NSData * fileData = [NSData dataWithContentsOfFile:path];
351
-            resolve([fileData base64EncodedStringWithOptions:0]);
352
-        }
353
-        else if ([[encoding lowercaseString] isEqualToString:@"ascii"]) {
354
-            NSData * resultData = [NSData dataWithContentsOfFile:path];
355
-            NSMutableArray * resultArray = [NSMutableArray array];
356
-            char * bytes = [resultData bytes];
357
-            for(int i=0;i<[resultData length];i++) {
358
-                [resultArray addObject:[NSNumber numberWithChar:bytes[i]]];
359
             }
326
             }
360
-            resolve(resultArray);
361
-        }
362
-
327
+        }];
363
     }
328
     }
364
     @catch(NSException * e)
329
     @catch(NSException * e)
365
     {
330
     {
331
+        if(reject != nil)
366
         reject(@"RNFetchBlobFS readFile error", @"error", [e description]);
332
         reject(@"RNFetchBlobFS readFile error", @"error", [e description]);
367
     }
333
     }
368
 }
334
 }
486
     self.path = path;
452
     self.path = path;
487
     self.bufferSize = bufferSize;
453
     self.bufferSize = bufferSize;
488
     
454
     
489
-    if([path hasPrefix:@"assets-library://"])
455
+    if([path hasPrefix:AL_PREFIX])
490
     {
456
     {
491
-     
457
+        [self startAssetReadStream:path];
492
         return;
458
         return;
493
     }
459
     }
494
     
460
     
631
 
597
 
632
 }
598
 }
633
 
599
 
600
++ (void) getPathFromUri:(NSString *)uri completionHandler:(void(^)(NSString * path, ALAssetRepresentation *asset)) onComplete
601
+{
602
+    if([uri hasPrefix:AL_PREFIX])
603
+    {
604
+        NSURL *asseturl = [NSURL URLWithString:uri];
605
+        ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
606
+        [assetslibrary assetForURL:asseturl
607
+                       resultBlock:^(ALAsset *asset) {
608
+                           onComplete(nil, [asset defaultRepresentation]);
609
+                       }
610
+                      failureBlock:^(NSError *error) {
611
+                          onComplete(nil, nil);
612
+                      }];
613
+    }
614
+    else
615
+    {
616
+        onComplete([[self class] getPathOfAsset:uri], nil);
617
+    }
618
+}
619
+
634
 @end
620
 @end

+ 1
- 0
src/ios/RNFetchBlobNetwork.h View File

11
 
11
 
12
 #import <Foundation/Foundation.h>
12
 #import <Foundation/Foundation.h>
13
 #import "RCTBridgeModule.h"
13
 #import "RCTBridgeModule.h"
14
+#import "RNFetchBlobFS.h"
14
 
15
 
15
 typedef void(^CompletionHander)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error);
16
 typedef void(^CompletionHander)(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error);
16
 typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error);
17
 typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error);

+ 34
- 0
src/ios/RNFetchBlobReqBuilder.h View File

1
+//
2
+//  RNFetchBlobReqBuilder.h
3
+//  RNFetchBlob
4
+//
5
+//  Created by Ben Hsieh on 2016/7/9.
6
+//  Copyright © 2016年 wkh237. All rights reserved.
7
+//
8
+
9
+#ifndef RNFetchBlobReqBuilder_h
10
+#define RNFetchBlobReqBuilder_h
11
+
12
+#import <Foundation/Foundation.h>
13
+
14
+@interface RNFetchBlobReqBuilder : NSObject;
15
+
16
++(void) buildMultipartRequest:(NSDictionary *)options
17
+                       taskId:(NSString *)taskId
18
+                       method:(NSString *)method
19
+                          url:(NSString *)url
20
+                      headers:(NSDictionary *)headers
21
+                         form:(NSArray *)form
22
+                   onComplete:(void(^)(NSURLRequest * req))onComplete;
23
+
24
++(void) buildOctetRequest:(NSDictionary *)options
25
+                   taskId:(NSString *)taskId
26
+                   method:(NSString *)method
27
+                      url:(NSString *)url
28
+                  headers:(NSDictionary *)headers
29
+                     body:(NSString *)body
30
+               onComplete:(void(^)(NSURLRequest * req))onComplete;
31
+
32
+@end
33
+
34
+#endif /* RNFetchBlobReqBuilder_h */

+ 195
- 0
src/ios/RNFetchBlobReqBuilder.m View File

1
+//
2
+//  RNFetchBlobReqBuilder.m
3
+//  RNFetchBlob
4
+//
5
+//  Created by Ben Hsieh on 2016/7/9.
6
+//  Copyright © 2016年 wkh237. All rights reserved.
7
+//
8
+
9
+#import <Foundation/Foundation.h>
10
+#import "RNFetchBlobReqBuilder.h"
11
+#import "RNFetchBlobNetwork.h"
12
+#import "RNFetchBlobConst.h"
13
+#import "RNFetchBlobFS.h"
14
+
15
+@interface RNFetchBlobReqBuilder()
16
+{
17
+    
18
+}
19
+@end
20
+
21
+@implementation RNFetchBlobReqBuilder
22
+
23
+
24
+// Fetch blob data request
25
++(void) buildMultipartRequest:(NSDictionary *)options
26
+                       taskId:(NSString *)taskId
27
+                       method:(NSString *)method
28
+                          url:(NSString *)url
29
+                      headers:(NSDictionary *)headers
30
+                         form:(NSArray *)form
31
+                   onComplete:(void(^)(NSURLRequest * req))onComplete
32
+{
33
+    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
34
+    // send request
35
+    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString: encodedUrl]];
36
+    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
37
+    NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
38
+    NSNumber * timeStampObj = [NSNumber numberWithDouble: timeStamp];
39
+    
40
+    // generate boundary
41
+    NSString * boundary = [NSString stringWithFormat:@"RNFetchBlob%d", timeStampObj];
42
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
43
+        NSMutableData * postData = [[NSMutableData alloc] init];
44
+        // combine multipart/form-data body
45
+        [[self class] buildFormBody:form boundary:boundary onComplete:^(NSData *formData) {
46
+            if(formData != nil) {
47
+                [postData appendData:formData];
48
+                // close form data
49
+                [postData appendData: [[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
50
+                [request setHTTPBody:postData];
51
+            }
52
+            // set content-length
53
+            [mheaders setValue:[NSString stringWithFormat:@"%d",[postData length]] forKey:@"Content-Length"];
54
+            [mheaders setValue:[NSString stringWithFormat:@"100-continue",[postData length]] forKey:@"Expect"];
55
+            // appaned boundary to content-type
56
+            [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] forKey:@"content-type"];
57
+            [request setHTTPMethod: method];
58
+            [request setAllHTTPHeaderFields:mheaders];
59
+            onComplete(request);
60
+        }];
61
+        
62
+    });
63
+}
64
+
65
+// Fetch blob data request
66
++(void) buildOctetRequest:(NSDictionary *)options
67
+                   taskId:(NSString *)taskId
68
+                   method:(NSString *)method
69
+                      url:(NSString *)url
70
+                  headers:(NSDictionary *)headers
71
+                     body:(NSString *)body
72
+               onComplete:(void(^)(NSURLRequest * req))onComplete
73
+{
74
+    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
75
+    // send request
76
+    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
77
+                                    initWithURL:[NSURL
78
+                                                 URLWithString: encodedUrl]];
79
+    
80
+    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
81
+    // move heavy task to another thread
82
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
83
+        NSMutableData * blobData;
84
+        // if method is POST or PUT, convert data string format
85
+        if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
86
+            // generate octet-stream body
87
+            if(body != nil) {
88
+                
89
+                // when body is a string contains file path prefix, try load file from the path
90
+                if([body hasPrefix:FILE_PREFIX]) {
91
+                    NSString * orgPath = [body substringFromIndex:[FILE_PREFIX length]];
92
+                    orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
93
+                    if([orgPath hasPrefix:AL_PREFIX])
94
+                    {
95
+                        [RNFetchBlobFS readFile:orgPath encoding:@"utf8" resolver:nil rejecter:nil onComplete:^(NSData *content) {
96
+                            [request setHTTPBody:content];
97
+                            [mheaders setValue:@"application/octet-stream" forKey:@"content-type"];
98
+                            [request setHTTPMethod: method];
99
+                            [request setAllHTTPHeaderFields:mheaders];
100
+                            onComplete(request);
101
+                        }];
102
+                        return;
103
+                    }
104
+                    [request setHTTPBodyStream: [NSInputStream inputStreamWithFileAtPath:orgPath ]];
105
+                }
106
+                // otherwise convert it as BASE64 data string
107
+                else {
108
+                    blobData = [[NSData alloc] initWithBase64EncodedString:body options:0];
109
+                    [request setHTTPBody:blobData];
110
+                }
111
+                
112
+                [mheaders setValue:@"application/octet-stream" forKey:@"content-type"];
113
+                
114
+            }
115
+        }
116
+        
117
+        [request setHTTPMethod: method];
118
+        [request setAllHTTPHeaderFields:mheaders];
119
+        
120
+        onComplete(request);
121
+    });
122
+}
123
+
124
++(void) buildFormBody:(NSArray *)form boundary:(NSString *)boundary onComplete:(void(^)(NSData * formData))onComplete
125
+{
126
+    NSMutableData * formData = [[NSMutableData alloc] init];
127
+    if(form == nil)
128
+        onComplete(nil);
129
+    else
130
+    {
131
+        __block int i = 0;
132
+        __block int count = [form count];
133
+        void __block (^getFieldData)(id field) = ^(id field)
134
+        {
135
+            NSString * name = [field valueForKey:@"name"];
136
+            NSString * content = [field valueForKey:@"data"];
137
+            // field is a text field
138
+            if([field valueForKey:@"filename"] == nil || content == [NSNull null]) {
139
+                [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
140
+                [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
141
+                [formData appendData:[[NSString stringWithFormat:@"Content-Type: text/plain\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
142
+                [formData appendData:[[NSString stringWithFormat:@"%@\r\n", content] dataUsingEncoding:NSUTF8StringEncoding]];
143
+            }
144
+            // field contains a file
145
+            else {
146
+                NSMutableData * blobData;
147
+                if(content != nil)
148
+                {
149
+                    // append data from file asynchronously
150
+                    if([content hasPrefix:FILE_PREFIX])
151
+                    {
152
+                        NSString * orgPath = [content substringFromIndex:[FILE_PREFIX length]];
153
+                        orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
154
+                        [RNFetchBlobFS readFile:orgPath encoding:@"utf8" resolver:nil rejecter:nil onComplete:^(NSData *content) {
155
+                            NSString * filename = [field valueForKey:@"filename"];
156
+                            [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
157
+                            [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
158
+                            [formData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
159
+                            [formData appendData:content];
160
+                            [formData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
161
+                            i++;
162
+                            if(i < count)
163
+                            {
164
+                                getFieldData([form objectAtIndex:i]);
165
+                            }
166
+                            else
167
+                                onComplete(formData);
168
+                        }];
169
+                        return ;
170
+                    }
171
+                    else
172
+                        blobData = [[NSData alloc] initWithBase64EncodedString:content options:0];
173
+                }
174
+                NSString * filename = [field valueForKey:@"filename"];
175
+                [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
176
+                [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
177
+                [formData appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
178
+                [formData appendData:blobData];
179
+                [formData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
180
+            }
181
+            i++;
182
+            if(i < count)
183
+            {
184
+                getFieldData([form objectAtIndex:i]);
185
+            }
186
+            else
187
+                onComplete(formData);
188
+            
189
+        };
190
+        getFieldData([form objectAtIndex:i]);
191
+    }
192
+}
193
+
194
+
195
+@end