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 ;
@@ -344,7 +374,7 @@ static void writeArrayChunk(String streamId, ReadableArray data, Callback callba
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 @@ static void mkdir(String path, Callback callback) {
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 @@ static void cp(String path, String dest, Callback callback) {
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 @@ static void mv(String path, String dest, Callback callback) {
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 @@ static void exists(String path, Callback callback) {
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 @@ static void ls(String path, Callback callback) {
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 @@ protected Integer doInBackground(String ...args) {
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 @@ void emitFSData(String taskId, String event, String data) {
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
}
0 commit comments