Преглед на файлове

Add #45 Android implementation

Ben Hsieh преди 8 години
родител
ревизия
e267dc5246

+ 3
- 0
src/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java Целия файл

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

+ 157
- 36
src/android/src/main/java/com/RNFetchBlob/RNFetchBlobFS.java Целия файл

@@ -1,10 +1,16 @@
1 1
 package com.RNFetchBlob;
2 2
 
3
+import android.app.Application;
4
+import android.content.CursorLoader;
3 5
 import android.content.Intent;
6
+import android.content.res.AssetFileDescriptor;
7
+import android.content.res.AssetManager;
8
+import android.database.Cursor;
4 9
 import android.media.MediaScannerConnection;
5 10
 import android.net.Uri;
6 11
 import android.os.AsyncTask;
7 12
 import android.os.Environment;
13
+import android.provider.MediaStore;
8 14
 
9 15
 import com.facebook.react.bridge.Arguments;
10 16
 import com.facebook.react.bridge.Callback;
@@ -43,6 +49,7 @@ public class RNFetchBlobFS {
43 49
     ReactApplicationContext mCtx;
44 50
     DeviceEventManagerModule.RCTDeviceEventEmitter emitter;
45 51
     String encoding = "base64";
52
+    static final String assetPrefix = "bundle-assets://";
46 53
     boolean append = false;
47 54
     OutputStream writeStreamInstance = null;
48 55
     static HashMap<String, RNFetchBlobFS> fileStreams = new HashMap<>();
@@ -134,6 +141,7 @@ public class RNFetchBlobFS {
134 141
      * @param promise
135 142
      */
136 143
     static public void readFile(String path, String encoding, final Promise promise ) {
144
+        path = normalizePath(path);
137 145
         AsyncTask<String, Integer, Integer> task = new AsyncTask<String, Integer, Integer>() {
138 146
             @Override
139 147
             protected Integer doInBackground(String... strings) {
@@ -141,12 +149,25 @@ public class RNFetchBlobFS {
141 149
                 try {
142 150
                     String path = strings[0];
143 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 171
                     switch (encoding.toLowerCase()) {
151 172
                         case "base64" :
152 173
                             promise.resolve(Base64.encodeToString(bytes, 0));
@@ -209,6 +230,7 @@ public class RNFetchBlobFS {
209 230
      * @param bufferSize    Buffer size of read stream, default to 4096 (4095 when encode is `base64`)
210 231
      */
211 232
     public void readStream( String path, String encoding, int bufferSize) {
233
+        path = normalizePath(path);
212 234
         AsyncTask<String, Integer, Integer> task = new AsyncTask<String, Integer, Integer>() {
213 235
             @Override
214 236
             protected Integer doInBackground(String ... args) {
@@ -221,7 +243,15 @@ public class RNFetchBlobFS {
221 243
                     int chunkSize = encoding.equalsIgnoreCase("base64") ? 4095 : 4096;
222 244
                     if(bufferSize > 0)
223 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 255
                     byte[] buffer = new byte[chunkSize];
226 256
                     int cursor = 0;
227 257
                     boolean error = false;
@@ -344,7 +374,7 @@ public class RNFetchBlobFS {
344 374
     }
345 375
 
346 376
     /**
347
-     * Close file stream by ID
377
+     * Close file write stream by ID
348 378
      * @param streamId Stream ID
349 379
      * @param callback JS context callback
350 380
      */
@@ -395,6 +425,7 @@ public class RNFetchBlobFS {
395 425
      * @param callback  JS context callback
396 426
      */
397 427
     static void cp(String path, String dest, Callback callback) {
428
+        path = normalizePath(path);
398 429
         InputStream in = null;
399 430
         OutputStream out = null;
400 431
 
@@ -409,7 +440,7 @@ public class RNFetchBlobFS {
409 440
             if(!new File(dest).exists())
410 441
                 new File(dest).createNewFile();
411 442
 
412
-            in = new FileInputStream(path);
443
+            in = inputStreamFromPath(path);
413 444
             out = new FileOutputStream(dest);
414 445
 
415 446
             byte[] buf = new byte[1024];
@@ -454,9 +485,23 @@ public class RNFetchBlobFS {
454 485
      * @param callback  JS context callback
455 486
      */
456 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,7 +510,9 @@ public class RNFetchBlobFS {
465 510
      * @param callback  JS context callback
466 511
      */
467 512
     static void ls(String path, Callback callback) {
513
+        path = normalizePath(path);
468 514
         File src = new File(path);
515
+        // TODO : handle asset folder
469 516
         if(!src.exists() || !src.isDirectory()) {
470 517
             callback.invoke("ls error: failed to list path `" + path + "` for it is not exist or it is not a folder");
471 518
             return;
@@ -479,6 +526,7 @@ public class RNFetchBlobFS {
479 526
     }
480 527
 
481 528
     static void lstat(String path, final Callback callback) {
529
+        path = normalizePath(path);
482 530
         File src = new File(path);
483 531
         new AsyncTask<String, Integer, Integer>() {
484 532
             @Override
@@ -511,24 +559,55 @@ public class RNFetchBlobFS {
511 559
      */
512 560
     static void stat(String path, Callback callback) {
513 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 563
         } catch(Exception err) {
528 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 611
     void scanFile(String [] path, String[] mimes, final Callback callback) {
533 612
         try {
534 613
             MediaScannerConnection.scanFile(mCtx, path, mimes, new MediaScannerConnection.OnScanCompletedListener() {
@@ -669,18 +748,60 @@ public class RNFetchBlobFS {
669 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,6 +8,7 @@
8 8
 import {
9 9
   NativeModules,
10 10
   DeviceEventEmitter,
11
+  Platform,
11 12
   NativeAppEventEmitter,
12 13
 } from 'react-native'
13 14
 import RNFetchBlobSession from './class/RNFetchBlobSession'
@@ -47,6 +48,15 @@ function session(name:string):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 60
 function createFile(path:string, data:string, encoding: 'base64' | 'ascii' | 'utf8'):Promise {
51 61
   encoding = encoding || 'utf8'
52 62
   return new Promise((resolve, reject) => {
@@ -324,5 +334,6 @@ export default {
324 334
   stat,
325 335
   lstat,
326 336
   scanFile,
327
-  dirs
337
+  dirs,
338
+  addAssetPrefix
328 339
 }

+ 1
- 1
src/index.js Целия файл

@@ -272,5 +272,5 @@ export default {
272 272
   config,
273 273
   session,
274 274
   fs,
275
-  wrap,
275
+  wrap
276 276
 }

+ 2
- 0
src/ios/RNFetchBlob/RNFetchBlob.m Целия файл

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

+ 1
- 0
src/ios/RNFetchBlobFS.m Целия файл

@@ -15,6 +15,7 @@
15 15
 #import "RNFetchBlobFS.h"
16 16
 #import "RNFetchBlobConst.h"
17 17
 @import AssetsLibrary;
18
+@import Photos;
18 19
 
19 20
 NSMutableDictionary *fileStreams = nil;
20 21