Browse Source

#2 ios download to file API complete

Ben Hsieh 8 years ago
parent
commit
7356e6e116
2 changed files with 131 additions and 32 deletions
  1. 65
    10
      src/index.js
  2. 66
    22
      src/ios/RNFetchBlob/RNFetchBlob.m

+ 65
- 10
src/index.js View File

11
   Platform,
11
   Platform,
12
 } from 'react-native'
12
 } from 'react-native'
13
 
13
 
14
+type RNFetchBlobNative = {
15
+  fetchBlob : (
16
+    options:fetchConfig,
17
+    taskId:string,
18
+    method:string,
19
+    url:string,
20
+    headers:any,
21
+    body:any,
22
+    callback:(err:any, ...data:any) => void
23
+  ) => void,
24
+  fetchBlobForm : (
25
+    options:fetchConfig,
26
+    taskId:string,
27
+    method:string,
28
+    url:string,
29
+    headers:any,
30
+    form:Array<any>,
31
+    callback:(err:any, ...data:any) => void
32
+  ) => void,
33
+  readStream : (
34
+    taskId:string,
35
+    path:string,
36
+    encode: 'utf8' | 'ascii' | 'base64'
37
+  ) => void,
38
+  getEnvironmentDirs : (dirs:any) => void,
39
+  flush : () => void
40
+};
41
+
14
 import base64 from 'base-64'
42
 import base64 from 'base-64'
15
 const emitter = (Platform.OS === 'android' ? DeviceEventEmitter : NativeAppEventEmitter)
43
 const emitter = (Platform.OS === 'android' ? DeviceEventEmitter : NativeAppEventEmitter)
16
-const RNFetchBlob = NativeModules.RNFetchBlob
44
+const RNFetchBlob:RNFetchBlobNative = NativeModules.RNFetchBlob
17
 
45
 
18
 emitter.addListener("RNFetchBlobMessage", (e) => {
46
 emitter.addListener("RNFetchBlobMessage", (e) => {
19
 
47
 
41
 type fetchConfig = {
69
 type fetchConfig = {
42
   fileCache : bool,
70
   fileCache : bool,
43
   path : string,
71
   path : string,
72
+};
73
+
74
+function getSystemDirs() {
75
+  return new Promise((resolve, reject) => {
76
+    try {
77
+      RNFetchBlob.getEnvironmentDirs((...dirs) => {
78
+        console.log('##',...dirs)
79
+        let [PictureDir, MovieDir, DocumentDir, CacheDir] = [...dirs]
80
+        resolve({PictureDir, MovieDir, DocumentDir, CacheDir})
81
+      })
82
+    } catch(err) {
83
+      reject(err)
84
+    }
85
+  })
86
+
44
 }
87
 }
45
 
88
 
46
-const config = function(options) {
89
+function config (options:fetchConfig) {
47
   return { fetch : fetch.bind(options) }
90
   return { fetch : fetch.bind(options) }
48
 }
91
 }
49
 
92
 
50
 // Promise wrapper function
93
 // Promise wrapper function
51
-const fetch = function(...args:any) {
94
+function fetch(...args:any) {
52
 
95
 
53
   let options = this || {}
96
   let options = this || {}
54
 
97
 
76
         reject(new Error(err, ...data))
119
         reject(new Error(err, ...data))
77
       else {
120
       else {
78
         let respType = 'base64'
121
         let respType = 'base64'
79
-        if(options.fileCache || options.path)
122
+        if(options.path || options.fileCache)
80
           respType = 'path'
123
           respType = 'path'
81
-        resolve(new FetchBlobResponse(taskId, options.path, respType,...data))
124
+        resolve(new FetchBlobResponse(taskId, respType, ...data))
82
       }
125
       }
83
 
126
 
84
     })
127
     })
100
 class FetchBlobResponse {
143
 class FetchBlobResponse {
101
 
144
 
102
   taskId : string;
145
   taskId : string;
103
-  path : string;
146
+  path : () => string | null;
104
   type : 'base64' | 'path';
147
   type : 'base64' | 'path';
105
   data : any;
148
   data : any;
106
   blob : (contentType:string, sliceSize:number) => null;
149
   blob : (contentType:string, sliceSize:number) => null;
113
     fn:(event : 'data' | 'end', chunk:any) => void
156
     fn:(event : 'data' | 'end', chunk:any) => void
114
   ) => void;
157
   ) => void;
115
 
158
 
116
-  constructor(taskId:string, path:string, type:'base64' | 'path',data:any) {
159
+  constructor(taskId:string, type:'base64' | 'path', data:any) {
117
     this.data = data
160
     this.data = data
118
-    this.path = path
119
     this.taskId = taskId
161
     this.taskId = taskId
162
+    this.type = type
120
     /**
163
     /**
121
      * Convert result to javascript Blob object.
164
      * Convert result to javascript Blob object.
122
      * @param  {string} contentType MIME type of the blob object.
165
      * @param  {string} contentType MIME type of the blob object.
156
       RNFetchBlob.flush(this.taskId, this.path)
199
       RNFetchBlob.flush(this.taskId, this.path)
157
     }
200
     }
158
 
201
 
202
+    this.path = () => {
203
+      if(this.type === 'path')
204
+        return this.data
205
+      return null
206
+    }
207
+
159
     /**
208
     /**
160
      * Start read stream from cached file
209
      * Start read stream from cached file
161
      * @param  {String} encoding Encode type, should be one of `base64`, `ascrii`, `utf8`.
210
      * @param  {String} encoding Encode type, should be one of `base64`, `ascrii`, `utf8`.
172
           subscription()
221
           subscription()
173
       })
222
       })
174
 
223
 
175
-      RNFetchBlob.readStream(this.taskId, this.path, encode)
224
+      if(this.type === 'path') {
225
+        RNFetchBlob.readStream(this.taskId, this.data, encode)
226
+      }
227
+      else {
228
+        console.warn('RNFetchblob', 'this response data does not contains any available stream')
229
+      }
230
+
176
     }
231
     }
177
 
232
 
178
   }
233
   }
187
 }
242
 }
188
 
243
 
189
 export default {
244
 export default {
190
-  fetch, FetchBlobResponse, base64
245
+  fetch, base64, config, getSystemDirs
191
 }
246
 }

+ 66
- 22
src/ios/RNFetchBlob/RNFetchBlob.m View File

47
 
47
 
48
 + (NSString *) getDocumentDir {
48
 + (NSString *) getDocumentDir {
49
 
49
 
50
-    return NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
50
+    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
51
 }
51
 }
52
 
52
 
53
 + (NSString *) getMusicDir {
53
 + (NSString *) getMusicDir {
54
-    return NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES);
54
+    return [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) firstObject];
55
 }
55
 }
56
 
56
 
57
 + (NSString *) getMovieDir {
57
 + (NSString *) getMovieDir {
58
-    return NSSearchPathForDirectoriesInDomains(NSMoviesDirectory, NSUserDomainMask, YES);
58
+    return [NSSearchPathForDirectoriesInDomains(NSMoviesDirectory, NSUserDomainMask, YES) firstObject];
59
 }
59
 }
60
 
60
 
61
 + (NSString *) getPictureDir {
61
 + (NSString *) getPictureDir {
62
-    return NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES);
62
+    return [NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES) firstObject];
63
 }
63
 }
64
 
64
 
65
 + (NSString *) getTempPath:(NSString*)taskId {
65
 + (NSString *) getTempPath:(NSString*)taskId {
66
 
66
 
67
-    NSString * documentDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
68
-    NSString * filename = [NSString stringWithFormat:@"RNFetchBlobTmp_%s", taskId];
67
+    NSString * documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
68
+    NSString * filename = [NSString stringWithFormat:@"/RNFetchBlobTmp_%@", taskId];
69
     NSString * tempPath = [documentDir stringByAppendingString: filename];
69
     NSString * tempPath = [documentDir stringByAppendingString: filename];
70
     return tempPath;
70
     return tempPath;
71
 }
71
 }
83
 }
83
 }
84
 
84
 
85
 - (void)openWithPath:(NSString *)destPath {
85
 - (void)openWithPath:(NSString *)destPath {
86
-    self.outStream = [[NSOutputStream alloc]init];
87
-    [self.outStream initToFileAtPath:destPath append:NO];
86
+    self.outStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:YES];
87
+    [self.outStream open];
88
 }
88
 }
89
 
89
 
90
 
90
 
97
 }
97
 }
98
 
98
 
99
 // Write file chunk into an opened stream
99
 // Write file chunk into an opened stream
100
-- (void)write:(NSString *) chunk {
101
-    [self.outStream write:[chunk cStringUsingEncoding:NSASCIIStringEncoding] maxLength:chunk.length];
100
+- (void)write:(NSData *) chunk toPath:(NSString *) path{
101
+    NSUInteger left = [chunk length];
102
+    NSUInteger nwr = 0;
103
+    do {
104
+        nwr = [self.outStream write:[chunk bytes] maxLength:left];
105
+        if (-1 == nwr) break;
106
+        left -= nwr;
107
+    } while (left > 0);
108
+    if (left) {
109
+        NSLog(@"stream error: %@", [self.outStream streamError]);
110
+    }
102
 }
111
 }
103
 
112
 
104
 - (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding {
113
 - (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding {
117
         [self readWithPath:path useEncoding:encoding];
126
         [self readWithPath:path useEncoding:encoding];
118
 }
127
 }
119
 
128
 
120
-// close file stream
129
+// close file write stream
121
 - (void)closeOutStream {
130
 - (void)closeOutStream {
122
     if(self.outStream != nil) {
131
     if(self.outStream != nil) {
123
         [self.outStream close];
132
         [self.outStream close];
126
 
135
 
127
 }
136
 }
128
 
137
 
138
+// close file read stream
129
 - (void)closeInStream {
139
 - (void)closeInStream {
130
     if(self.inStream != nil) {
140
     if(self.inStream != nil) {
131
         [self.inStream close];
141
         [self.inStream close];
139
 - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
149
 - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
140
 
150
 
141
     switch(eventCode) {
151
     switch(eventCode) {
142
-    
152
+            
153
+        // write stream event
154
+        case NSStreamEventHasSpaceAvailable:
155
+        {
156
+            
157
+        
158
+        }
159
+        
160
+        // read stream incoming chunk
143
         case NSStreamEventHasBytesAvailable:
161
         case NSStreamEventHasBytesAvailable:
144
         {
162
         {
145
             
163
             
196
             }
214
             }
197
             break;
215
             break;
198
         }
216
         }
217
+            
218
+        // stream error
199
         case NSStreamEventErrorOccurred:
219
         case NSStreamEventErrorOccurred:
200
         {
220
         {
201
             [self.bridge.eventDispatcher
221
             [self.bridge.eventDispatcher
265
         self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
285
         self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
266
         [self.fileStream openWithPath:path];
286
         [self.fileStream openWithPath:path];
267
     }
287
     }
268
-    else if ( [self.options valueForKey:CONFIG_USE_TEMP] == YES ) {
288
+    else if ( [self.options valueForKey:CONFIG_USE_TEMP]!= nil ) {
269
         self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
289
         self.fileStream = [[FetchBlobFS alloc]initWithCallback:self.callback];
270
         [self.fileStream openWithId:taskId];
290
         [self.fileStream openWithId:taskId];
271
     }
291
     }
284
 
304
 
285
 
305
 
286
 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
306
 - (void) connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
287
-    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
307
+//    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
288
     expectedBytes = [response expectedContentLength];
308
     expectedBytes = [response expectedContentLength];
289
 }
309
 }
290
 
310
 
294
     
314
     
295
     Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
315
     Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
296
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
316
     NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
297
-    
317
+    if(path != nil) {
318
+        [self.fileStream write:data toPath:path];
319
+    }
298
     // write to tmp file
320
     // write to tmp file
299
-    if( fileCache == YES || path != nil ) {
300
-        [self.fileStream write:data];
321
+    else if( fileCache != nil) {
322
+        [self.fileStream write:data toPath:[FetchBlobFS getTempPath:self.taskId ]];
301
     }
323
     }
302
     // cache data in memory
324
     // cache data in memory
303
     else {
325
     else {
331
 
353
 
332
 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
354
 - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
333
     
355
     
334
-    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
356
+//    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
335
     
357
     
336
     [self.fileStream closeInStream];
358
     [self.fileStream closeInStream];
337
     [self.fileStream closeOutStream];
359
     [self.fileStream closeOutStream];
358
     else
380
     else
359
         data = [[NSData alloc] init];
381
         data = [[NSData alloc] init];
360
     
382
     
361
-    NSString * path = [NSString stringWithString:[self.options valueForKey:CONFIG_FILE_PATH]];
383
+    NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
384
+    Boolean useCache = [self.options valueForKey:CONFIG_USE_TEMP];
362
     
385
     
363
     [self.fileStream closeInStream];
386
     [self.fileStream closeInStream];
364
     
387
     
367
         callback(@[[NSNull null], path]);
390
         callback(@[[NSNull null], path]);
368
     }
391
     }
369
     // when fileCache option is set but no path specified, save to tmp path
392
     // when fileCache option is set but no path specified, save to tmp path
370
-    else if( [self.options valueForKey:CONFIG_USE_TEMP] == YES || path != nil ) {
393
+    else if( [self.options valueForKey:CONFIG_USE_TEMP] != nil) {
371
         NSString * tmpPath = [FetchBlobFS getTempPath:taskId];
394
         NSString * tmpPath = [FetchBlobFS getTempPath:taskId];
372
         callback(@[[NSNull null], tmpPath]);
395
         callback(@[[NSNull null], tmpPath]);
373
     }
396
     }
395
 RCT_EXPORT_MODULE();
418
 RCT_EXPORT_MODULE();
396
 
419
 
397
 // Fetch blob data request
420
 // Fetch blob data request
398
-RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options taskId:(NSString *)taskId method:(NSString *)method url:(NSString *)url headers:(NSDictionary *)headers form:(NSArray *)form callback:(RCTResponseSenderBlock)callback)
421
+RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
422
+                  taskId:(NSString *)taskId
423
+                  method:(NSString *)method
424
+                  url:(NSString *)url
425
+                  headers:(NSDictionary *)headers
426
+                  form:(NSArray *)form
427
+                  callback:(RCTResponseSenderBlock)callback)
399
 {
428
 {
400
     
429
     
401
     // send request
430
     // send request
461
 }
490
 }
462
 
491
 
463
 // Fetch blob data request
492
 // Fetch blob data request
464
-RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options taskId:(NSString *)taskId method:(NSString *)method url:(NSString *)url headers:(NSDictionary *)headers body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
493
+RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
494
+                  taskId:(NSString *)taskId
495
+                  method:(NSString *)method
496
+                  url:(NSString *)url
497
+                  headers:(NSDictionary *)headers
498
+                  body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
465
 {
499
 {
466
     // send request
500
     // send request
467
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
501
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
507
     [[NSFileManager defaultManager] removeItemAtPath:path error:&error];
541
     [[NSFileManager defaultManager] removeItemAtPath:path error:&error];
508
 }
542
 }
509
 
543
 
544
+RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
545
+    
546
+    callback(@[
547
+               [FetchBlobFS getPictureDir],
548
+               [FetchBlobFS getMovieDir],
549
+               [FetchBlobFS getDocumentDir],
550
+               [FetchBlobFS getCacheDir],
551
+            ]);
552
+}
553
+
510
 @end
554
 @end