浏览代码

Add #45 Android implementation

Ben Hsieh 8 年前
父节点
当前提交
e267dc5246

+ 3
- 0
src/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java 查看文件

13
 public class RNFetchBlob extends ReactContextBaseJavaModule {
13
 public class RNFetchBlob extends ReactContextBaseJavaModule {
14
 
14
 
15
     String filePathPrefix = "RNFetchBlob-file://";
15
     String filePathPrefix = "RNFetchBlob-file://";
16
+    static ReactApplicationContext RCTContext;
16
 
17
 
17
     public RNFetchBlob(ReactApplicationContext reactContext) {
18
     public RNFetchBlob(ReactApplicationContext reactContext) {
19
+
18
         super(reactContext);
20
         super(reactContext);
21
+        RCTContext = reactContext;
19
     }
22
     }
20
 
23
 
21
     @Override
24
     @Override

+ 157
- 36
src/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java 查看文件

1
 package com.RNFetchBlob;
1
 package com.RNFetchBlob;
2
 
2
 
3
+import android.app.Application;
4
+import android.content.CursorLoader;
3
 import android.content.Intent;
5
 import android.content.Intent;
6
+import android.content.res.AssetFileDescriptor;
7
+import android.content.res.AssetManager;
8
+import android.database.Cursor;
4
 import android.media.MediaScannerConnection;
9
 import android.media.MediaScannerConnection;
5
 import android.net.Uri;
10
 import android.net.Uri;
6
 import android.os.AsyncTask;
11
 import android.os.AsyncTask;
7
 import android.os.Environment;
12
 import android.os.Environment;
13
+import android.provider.MediaStore;
8
 
14
 
9
 import com.facebook.react.bridge.Arguments;
15
 import com.facebook.react.bridge.Arguments;
10
 import com.facebook.react.bridge.Callback;
16
 import com.facebook.react.bridge.Callback;
43
     ReactApplicationContext mCtx;
49
     ReactApplicationContext mCtx;
44
     DeviceEventManagerModule.RCTDeviceEventEmitter emitter;
50
     DeviceEventManagerModule.RCTDeviceEventEmitter emitter;
45
     String encoding = "base64";
51
     String encoding = "base64";
52
+    static final String assetPrefix = "bundle-assets://";
46
     boolean append = false;
53
     boolean append = false;
47
     OutputStream writeStreamInstance = null;
54
     OutputStream writeStreamInstance = null;
48
     static HashMap<String, RNFetchBlobFS> fileStreams = new HashMap<>();
55
     static HashMap<String, RNFetchBlobFS> fileStreams = new HashMap<>();
134
      * @param promise
141
      * @param promise
135
      */
142
      */
136
     static public void readFile(String path, String encoding, final Promise promise ) {
143
     static public void readFile(String path, String encoding, final Promise promise ) {
144
+        path = normalizePath(path);
137
         AsyncTask<String, Integer, Integer> task = new AsyncTask<String, Integer, Integer>() {
145
         AsyncTask<String, Integer, Integer> task = new AsyncTask<String, Integer, Integer>() {
138
             @Override
146
             @Override
139
             protected Integer doInBackground(String... strings) {
147
             protected Integer doInBackground(String... strings) {
141
                 try {
149
                 try {
142
                     String path = strings[0];
150
                     String path = strings[0];
143
                     String encoding = strings[1];
151
                     String encoding = strings[1];
144
-                    File f = new File(path);
145
-                    int length = (int) f.length();
146
-                    byte[] bytes = new byte[length];
147
-                    FileInputStream in = new FileInputStream(f);
148
-                    in.read(bytes);
149
-                    in.close();
152
+                    byte[] bytes;
153
+
154
+                    if(path.startsWith(assetPrefix)) {
155
+                        String assetName = path.replace(assetPrefix, "");
156
+                        long length = RNFetchBlob.RCTContext.getAssets().openFd(assetName).getLength();
157
+                        bytes = new byte[(int) length];
158
+                        InputStream in = RNFetchBlob.RCTContext.getAssets().open(assetName);
159
+                        in.read(bytes, 0, (int) length);
160
+                        in.close();
161
+                    }
162
+                    else {
163
+                        File f = new File(path);
164
+                        int length = (int) f.length();
165
+                        bytes = new byte[length];
166
+                        FileInputStream in = new FileInputStream(f);
167
+                        in.read(bytes);
168
+                        in.close();
169
+                    }
170
+
150
                     switch (encoding.toLowerCase()) {
171
                     switch (encoding.toLowerCase()) {
151
                         case "base64" :
172
                         case "base64" :
152
                             promise.resolve(Base64.encodeToString(bytes, 0));
173
                             promise.resolve(Base64.encodeToString(bytes, 0));
209
      * @param bufferSize    Buffer size of read stream, default to 4096 (4095 when encode is `base64`)
230
      * @param bufferSize    Buffer size of read stream, default to 4096 (4095 when encode is `base64`)
210
      */
231
      */
211
     public void readStream( String path, String encoding, int bufferSize) {
232
     public void readStream( String path, String encoding, int bufferSize) {
233
+        path = normalizePath(path);
212
         AsyncTask<String, Integer, Integer> task = new AsyncTask<String, Integer, Integer>() {
234
         AsyncTask<String, Integer, Integer> task = new AsyncTask<String, Integer, Integer>() {
213
             @Override
235
             @Override
214
             protected Integer doInBackground(String ... args) {
236
             protected Integer doInBackground(String ... args) {
221
                     int chunkSize = encoding.equalsIgnoreCase("base64") ? 4095 : 4096;
243
                     int chunkSize = encoding.equalsIgnoreCase("base64") ? 4095 : 4096;
222
                     if(bufferSize > 0)
244
                     if(bufferSize > 0)
223
                         chunkSize = bufferSize;
245
                         chunkSize = bufferSize;
224
-                    FileInputStream fs = new FileInputStream(new File(path));
246
+
247
+                    InputStream fs;
248
+                    if(path.startsWith(assetPrefix)) {
249
+                        fs = RNFetchBlob.RCTContext.getAssets().open(path.replace(assetPrefix, ""));
250
+                    }
251
+                    else {
252
+                        fs = new FileInputStream(new File(path));
253
+                    }
254
+
225
                     byte[] buffer = new byte[chunkSize];
255
                     byte[] buffer = new byte[chunkSize];
226
                     int cursor = 0;
256
                     int cursor = 0;
227
                     boolean error = false;
257
                     boolean error = false;
344
     }
374
     }
345
 
375
 
346
     /**
376
     /**
347
-     * Close file stream by ID
377
+     * Close file write stream by ID
348
      * @param streamId Stream ID
378
      * @param streamId Stream ID
349
      * @param callback JS context callback
379
      * @param callback JS context callback
350
      */
380
      */
395
      * @param callback  JS context callback
425
      * @param callback  JS context callback
396
      */
426
      */
397
     static void cp(String path, String dest, Callback callback) {
427
     static void cp(String path, String dest, Callback callback) {
428
+        path = normalizePath(path);
398
         InputStream in = null;
429
         InputStream in = null;
399
         OutputStream out = null;
430
         OutputStream out = null;
400
 
431
 
409
             if(!new File(dest).exists())
440
             if(!new File(dest).exists())
410
                 new File(dest).createNewFile();
441
                 new File(dest).createNewFile();
411
 
442
 
412
-            in = new FileInputStream(path);
443
+            in = inputStreamFromPath(path);
413
             out = new FileOutputStream(dest);
444
             out = new FileOutputStream(dest);
414
 
445
 
415
             byte[] buf = new byte[1024];
446
             byte[] buf = new byte[1024];
454
      * @param callback  JS context callback
485
      * @param callback  JS context callback
455
      */
486
      */
456
     static void exists(String path, Callback callback) {
487
     static void exists(String path, Callback callback) {
457
-        boolean exist = new File(path).exists();
458
-        boolean isDir = new File(path).isDirectory();;
459
-        callback.invoke(exist, isDir);
488
+        path = normalizePath(path);
489
+        if(isAsset(path)) {
490
+            try {
491
+                String filename = path.replace(assetPrefix, "");
492
+                AssetFileDescriptor fd = RNFetchBlob.RCTContext.getAssets().openFd(filename);
493
+                // TODO : handle asset folder
494
+                callback.invoke(true, false);
495
+            } catch (IOException e) {
496
+                callback.invoke(false, false);
497
+            }
498
+        }
499
+        else {
500
+            boolean exist = new File(path).exists();
501
+            boolean isDir = new File(path).isDirectory();
502
+            callback.invoke(exist, isDir);
503
+        }
504
+
460
     }
505
     }
461
 
506
 
462
     /**
507
     /**
465
      * @param callback  JS context callback
510
      * @param callback  JS context callback
466
      */
511
      */
467
     static void ls(String path, Callback callback) {
512
     static void ls(String path, Callback callback) {
513
+        path = normalizePath(path);
468
         File src = new File(path);
514
         File src = new File(path);
515
+        // TODO : handle asset folder
469
         if(!src.exists() || !src.isDirectory()) {
516
         if(!src.exists() || !src.isDirectory()) {
470
             callback.invoke("ls error: failed to list path `" + path + "` for it is not exist or it is not a folder");
517
             callback.invoke("ls error: failed to list path `" + path + "` for it is not exist or it is not a folder");
471
             return;
518
             return;
479
     }
526
     }
480
 
527
 
481
     static void lstat(String path, final Callback callback) {
528
     static void lstat(String path, final Callback callback) {
529
+        path = normalizePath(path);
482
         File src = new File(path);
530
         File src = new File(path);
483
         new AsyncTask<String, Integer, Integer>() {
531
         new AsyncTask<String, Integer, Integer>() {
484
             @Override
532
             @Override
511
      */
559
      */
512
     static void stat(String path, Callback callback) {
560
     static void stat(String path, Callback callback) {
513
         try {
561
         try {
514
-            File target = new File(path);
515
-            if (!target.exists()) {
516
-                callback.invoke("stat error: file " + path + " does not exists");
517
-                return;
518
-            }
519
-            WritableMap stat = Arguments.createMap();
520
-            stat.putString("filename", target.getName());
521
-            stat.putString("path", target.getPath());
522
-            stat.putString("type", target.isDirectory() ? "directory" : "file");
523
-            stat.putString("size", String.valueOf(target.length()));
524
-            String lastModified = String.valueOf(target.lastModified());
525
-            stat.putString("lastModified", lastModified);
526
-            callback.invoke(null, stat);
562
+            callback.invoke(null, statFile(path));
527
         } catch(Exception err) {
563
         } catch(Exception err) {
528
             callback.invoke(err.getLocalizedMessage());
564
             callback.invoke(err.getLocalizedMessage());
529
         }
565
         }
530
     }
566
     }
531
 
567
 
568
+    /**
569
+     * Basic stat method
570
+     * @param path
571
+     * @return Stat result of a file or path
572
+     */
573
+    static WritableMap statFile(String path) {
574
+        try {
575
+            path = normalizePath(path);
576
+            WritableMap stat = Arguments.createMap();
577
+            if(isAsset(path)) {
578
+                String name = path.replace(assetPrefix, "");
579
+                AssetFileDescriptor fd = RNFetchBlob.RCTContext.getAssets().openFd(name);
580
+                stat.putString("filename", name);
581
+                stat.putString("path", path);
582
+                stat.putString("type", "asset");
583
+                stat.putString("size", String.valueOf(fd.getLength()));
584
+                stat.putString("lastModified", "0");
585
+            }
586
+            else {
587
+                File target = new File(path);
588
+                if (!target.exists()) {
589
+                    return null;
590
+                }
591
+                stat.putString("filename", target.getName());
592
+                stat.putString("path", target.getPath());
593
+                stat.putString("type", target.isDirectory() ? "directory" : "file");
594
+                stat.putString("size", String.valueOf(target.length()));
595
+                String lastModified = String.valueOf(target.lastModified());
596
+                stat.putString("lastModified", lastModified);
597
+
598
+            }
599
+            return stat;
600
+        } catch(Exception err) {
601
+            return null;
602
+        }
603
+    }
604
+
605
+    /**
606
+     * Media scanner scan file
607
+     * @param path
608
+     * @param mimes
609
+     * @param callback
610
+     */
532
     void scanFile(String [] path, String[] mimes, final Callback callback) {
611
     void scanFile(String [] path, String[] mimes, final Callback callback) {
533
         try {
612
         try {
534
             MediaScannerConnection.scanFile(mCtx, path, mimes, new MediaScannerConnection.OnScanCompletedListener() {
613
             MediaScannerConnection.scanFile(mCtx, path, mimes, new MediaScannerConnection.OnScanCompletedListener() {
669
         this.emitter.emit("RNFetchBlobStream" + taskId, eventData);
748
         this.emitter.emit("RNFetchBlobStream" + taskId, eventData);
670
     }
749
     }
671
 
750
 
672
-    static WritableMap statFile(String path) {
673
-        File target = new File(path);
674
-        if(!target.exists()) {
675
-            return null;
751
+    /**
752
+     * Get input stream of the given path, when the path is a string starts with bundle-assets://
753
+     * the stream is created by Assets Manager, otherwise use FileInputStream.
754
+     * @param path
755
+     * @return
756
+     * @throws IOException
757
+     */
758
+    static InputStream inputStreamFromPath(String path) throws IOException {
759
+        if (path.startsWith(assetPrefix)) {
760
+            return RNFetchBlob.RCTContext.getAssets().open(path.replace(assetPrefix, ""));
761
+        }
762
+        return new FileInputStream(new File(path));
763
+    }
764
+
765
+    /**
766
+     * Check if the asset or the file exists
767
+     * @param path
768
+     * @return
769
+     */
770
+    static boolean isPathExists(String path) {
771
+        if(path.startsWith(assetPrefix)) {
772
+            try {
773
+                RNFetchBlob.RCTContext.getAssets().open(path.replace(assetPrefix, ""));
774
+            } catch (IOException e) {
775
+                return false;
776
+            }
777
+            return true;
778
+        }
779
+        else {
780
+            return new File(path).exists();
781
+        }
782
+
783
+    }
784
+
785
+    static boolean isAsset(String path) {
786
+        return path.startsWith(assetPrefix);
787
+    }
788
+
789
+    static String normalizePath(String path) {
790
+        if(path.startsWith("bundle-assets://")) {
791
+            return path;
792
+        }
793
+        else if (path.startsWith("content://")) {
794
+            String[] proj = { MediaStore.Images.Media.DATA };
795
+            Uri contentUri = Uri.parse(path);
796
+            CursorLoader loader = new CursorLoader(RNFetchBlob.RCTContext, contentUri, proj, null, null, null);
797
+            Cursor cursor = loader.loadInBackground();
798
+            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
799
+            cursor.moveToFirst();
800
+            String result = cursor.getString(column_index);
801
+            cursor.close();
802
+            return result;
676
         }
803
         }
677
-        WritableMap stat = Arguments.createMap();
678
-        stat.putString("filename", target.getName());
679
-        stat.putString("path", target.getPath());
680
-        stat.putString("type", target.isDirectory() ? "directory" : "file");
681
-        stat.putInt("size", (int)target.length());
682
-        stat.putInt("lastModified", (int)target.lastModified());
683
-        return stat;
804
+        return path;
684
     }
805
     }
685
 
806
 
686
 }
807
 }

+ 12
- 1
src/fs.js 查看文件

8
 import {
8
 import {
9
   NativeModules,
9
   NativeModules,
10
   DeviceEventEmitter,
10
   DeviceEventEmitter,
11
+  Platform,
11
   NativeAppEventEmitter,
12
   NativeAppEventEmitter,
12
 } from 'react-native'
13
 } from 'react-native'
13
 import RNFetchBlobSession from './class/RNFetchBlobSession'
14
 import RNFetchBlobSession from './class/RNFetchBlobSession'
47
   }
48
   }
48
 }
49
 }
49
 
50
 
51
+function addAssetPrefix(path:string):string {
52
+  if(Platform.OS === 'ios') {
53
+    // path from camera roll
54
+    if(/^assets-library\:\/\//.test(path))
55
+      return path
56
+  }
57
+  return 'bundle-assets://' + path
58
+}
59
+
50
 function createFile(path:string, data:string, encoding: 'base64' | 'ascii' | 'utf8'):Promise {
60
 function createFile(path:string, data:string, encoding: 'base64' | 'ascii' | 'utf8'):Promise {
51
   encoding = encoding || 'utf8'
61
   encoding = encoding || 'utf8'
52
   return new Promise((resolve, reject) => {
62
   return new Promise((resolve, reject) => {
324
   stat,
334
   stat,
325
   lstat,
335
   lstat,
326
   scanFile,
336
   scanFile,
327
-  dirs
337
+  dirs,
338
+  addAssetPrefix
328
 }
339
 }

+ 1
- 1
src/index.js 查看文件

272
   config,
272
   config,
273
   session,
273
   session,
274
   fs,
274
   fs,
275
-  wrap,
275
+  wrap
276
 }
276
 }

+ 2
- 0
src/ios/RNFetchBlob/RNFetchBlob.m 查看文件

97
                     if(content != nil) {
97
                     if(content != nil) {
98
                         if([content hasPrefix:self.filePathPrefix]) {
98
                         if([content hasPrefix:self.filePathPrefix]) {
99
                             NSString * orgPath = [content substringFromIndex:[self.filePathPrefix length]];
99
                             NSString * orgPath = [content substringFromIndex:[self.filePathPrefix length]];
100
+                            orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
100
                             blobData = [[NSData alloc] initWithContentsOfFile:orgPath];
101
                             blobData = [[NSData alloc] initWithContentsOfFile:orgPath];
101
                         }
102
                         }
102
                         else
103
                         else
160
                 // when body is a string contains file path prefix, try load file from the path
161
                 // when body is a string contains file path prefix, try load file from the path
161
                 if([body hasPrefix:self.filePathPrefix]) {
162
                 if([body hasPrefix:self.filePathPrefix]) {
162
                     NSString * orgPath = [body substringFromIndex:[self.filePathPrefix length]];
163
                     NSString * orgPath = [body substringFromIndex:[self.filePathPrefix length]];
164
+                    orgPath = [RNFetchBlobFS getPathOfAsset:orgPath];
163
                     [request setHTTPBodyStream: [NSInputStream inputStreamWithFileAtPath:orgPath ]];
165
                     [request setHTTPBodyStream: [NSInputStream inputStreamWithFileAtPath:orgPath ]];
164
                 }
166
                 }
165
                 // otherwise convert it as BASE64 data string
167
                 // otherwise convert it as BASE64 data string

+ 1
- 0
src/ios/RNFetchBlobFS.m 查看文件

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
 NSMutableDictionary *fileStreams = nil;
20
 NSMutableDictionary *fileStreams = nil;
20
 
21