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,19 +141,33 @@ protected Void doInBackground(Object... args) {
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 ) {
140
148
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 @@ static public String getTmpPath(ReactApplicationContext ctx, String taskId) {
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 @@ protected Integer doInBackground(String ... args) {
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 ;
@@ -314,7 +344,6 @@ static void writeChunk(String streamId, String data, Callback callback) {
314
344
try {
315
345
stream .write (chunk );
316
346
callback .invoke ();
317
- chunk = null ;
318
347
} catch (Exception e ) {
319
348
callback .invoke (e .getLocalizedMessage ());
320
349
}
@@ -344,7 +373,7 @@ static void writeArrayChunk(String streamId, ReadableArray data, Callback callba
344
373
}
345
374
346
375
/**
347
- * Close file stream by ID
376
+ * Close file write stream by ID
348
377
* @param streamId Stream ID
349
378
* @param callback JS context callback
350
379
*/
@@ -395,21 +424,21 @@ static void mkdir(String path, Callback callback) {
395
424
* @param callback JS context callback
396
425
*/
397
426
static void cp (String path , String dest , Callback callback ) {
427
+ path = normalizePath (path );
398
428
InputStream in = null ;
399
429
OutputStream out = null ;
400
430
401
431
try {
402
432
403
- String destFolder = new File (dest ).getPath ();
404
- if (!new File (path ).exists ()) {
433
+ if (!isPathExists (path )) {
405
434
callback .invoke ("cp error: source file at path`" + path + "` not exists" );
406
435
return ;
407
436
}
408
437
409
438
if (!new File (dest ).exists ())
410
439
new File (dest ).createNewFile ();
411
440
412
- in = new FileInputStream (path );
441
+ in = inputStreamFromPath (path );
413
442
out = new FileOutputStream (dest );
414
443
415
444
byte [] buf = new byte [1024 ];
@@ -454,9 +483,22 @@ static void mv(String path, String dest, Callback callback) {
454
483
* @param callback JS context callback
455
484
*/
456
485
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 );
486
+ path = normalizePath (path );
487
+ if (isAsset (path )) {
488
+ try {
489
+ String filename = path .replace (assetPrefix , "" );
490
+ AssetFileDescriptor fd = RNFetchBlob .RCTContext .getAssets ().openFd (filename );
491
+ callback .invoke (true , false );
492
+ } catch (IOException e ) {
493
+ callback .invoke (false , false );
494
+ }
495
+ }
496
+ else {
497
+ boolean exist = new File (path ).exists ();
498
+ boolean isDir = new File (path ).isDirectory ();
499
+ callback .invoke (exist , isDir );
500
+ }
501
+
460
502
}
461
503
462
504
/**
@@ -465,21 +507,23 @@ static void exists(String path, Callback callback) {
465
507
* @param callback JS context callback
466
508
*/
467
509
static void ls (String path , Callback callback ) {
510
+ path = normalizePath (path );
468
511
File src = new File (path );
469
- if (!src .exists () || !src .isDirectory ()) {
512
+ if (!src .exists () || !src .isDirectory ()) {
470
513
callback .invoke ("ls error: failed to list path `" + path + "` for it is not exist or it is not a folder" );
471
514
return ;
472
515
}
473
- String [] files = new File (path ).list ();
516
+ String [] files = new File (path ).list ();
474
517
WritableArray arg = Arguments .createArray ();
475
- for (String i : files ) {
518
+ for (String i : files ) {
476
519
arg .pushString (i );
477
520
}
478
521
callback .invoke (null , arg );
479
522
}
480
523
481
524
static void lstat (String path , final Callback callback ) {
482
- File src = new File (path );
525
+ path = normalizePath (path );
526
+
483
527
new AsyncTask <String , Integer , Integer >() {
484
528
@ Override
485
529
protected Integer doInBackground (String ...args ) {
@@ -511,24 +555,55 @@ protected Integer doInBackground(String ...args) {
511
555
*/
512
556
static void stat (String path , Callback callback ) {
513
557
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 );
558
+ callback .invoke (null , statFile (path ));
527
559
} catch (Exception err ) {
528
560
callback .invoke (err .getLocalizedMessage ());
529
561
}
530
562
}
531
563
564
+ /**
565
+ * Basic stat method
566
+ * @param path
567
+ * @return Stat result of a file or path
568
+ */
569
+ static WritableMap statFile (String path ) {
570
+ try {
571
+ path = normalizePath (path );
572
+ WritableMap stat = Arguments .createMap ();
573
+ if (isAsset (path )) {
574
+ String name = path .replace (assetPrefix , "" );
575
+ AssetFileDescriptor fd = RNFetchBlob .RCTContext .getAssets ().openFd (name );
576
+ stat .putString ("filename" , name );
577
+ stat .putString ("path" , path );
578
+ stat .putString ("type" , "asset" );
579
+ stat .putString ("size" , String .valueOf (fd .getLength ()));
580
+ stat .putString ("lastModified" , "0" );
581
+ }
582
+ else {
583
+ File target = new File (path );
584
+ if (!target .exists ()) {
585
+ return null ;
586
+ }
587
+ stat .putString ("filename" , target .getName ());
588
+ stat .putString ("path" , target .getPath ());
589
+ stat .putString ("type" , target .isDirectory () ? "directory" : "file" );
590
+ stat .putString ("size" , String .valueOf (target .length ()));
591
+ String lastModified = String .valueOf (target .lastModified ());
592
+ stat .putString ("lastModified" , lastModified );
593
+
594
+ }
595
+ return stat ;
596
+ } catch (Exception err ) {
597
+ return null ;
598
+ }
599
+ }
600
+
601
+ /**
602
+ * Media scanner scan file
603
+ * @param path
604
+ * @param mimes
605
+ * @param callback
606
+ */
532
607
void scanFile (String [] path , String [] mimes , final Callback callback ) {
533
608
try {
534
609
MediaScannerConnection .scanFile (mCtx , path , mimes , new MediaScannerConnection .OnScanCompletedListener () {
@@ -669,18 +744,60 @@ void emitFSData(String taskId, String event, String data) {
669
744
this .emitter .emit ("RNFetchBlobStream" + taskId , eventData );
670
745
}
671
746
672
- static WritableMap statFile (String path ) {
673
- File target = new File (path );
674
- if (!target .exists ()) {
675
- return null ;
747
+ /**
748
+ * Get input stream of the given path, when the path is a string starts with bundle-assets://
749
+ * the stream is created by Assets Manager, otherwise use FileInputStream.
750
+ * @param path
751
+ * @return
752
+ * @throws IOException
753
+ */
754
+ static InputStream inputStreamFromPath (String path ) throws IOException {
755
+ if (path .startsWith (assetPrefix )) {
756
+ return RNFetchBlob .RCTContext .getAssets ().open (path .replace (assetPrefix , "" ));
757
+ }
758
+ return new FileInputStream (new File (path ));
759
+ }
760
+
761
+ /**
762
+ * Check if the asset or the file exists
763
+ * @param path
764
+ * @return
765
+ */
766
+ static boolean isPathExists (String path ) {
767
+ if (path .startsWith (assetPrefix )) {
768
+ try {
769
+ RNFetchBlob .RCTContext .getAssets ().open (path .replace (assetPrefix , "" ));
770
+ } catch (IOException e ) {
771
+ return false ;
772
+ }
773
+ return true ;
774
+ }
775
+ else {
776
+ return new File (path ).exists ();
777
+ }
778
+
779
+ }
780
+
781
+ static boolean isAsset (String path ) {
782
+ return path .startsWith (assetPrefix );
783
+ }
784
+
785
+ static String normalizePath (String path ) {
786
+ if (path .startsWith ("bundle-assets://" )) {
787
+ return path ;
788
+ }
789
+ else if (path .startsWith ("content://" )) {
790
+ String [] proj = { MediaStore .Images .Media .DATA };
791
+ Uri contentUri = Uri .parse (path );
792
+ CursorLoader loader = new CursorLoader (RNFetchBlob .RCTContext , contentUri , proj , null , null , null );
793
+ Cursor cursor = loader .loadInBackground ();
794
+ int column_index = cursor .getColumnIndexOrThrow (MediaStore .Images .Media .DATA );
795
+ cursor .moveToFirst ();
796
+ String result = cursor .getString (column_index );
797
+ cursor .close ();
798
+ return result ;
676
799
}
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 ;
800
+ return path ;
684
801
}
685
802
686
803
}
0 commit comments