|
@@ -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
|
}
|