react-native-blob-util 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -0
- package/android/src/main/AndroidManifest.xml +0 -3
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtil.java +11 -12
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilBody.java +30 -6
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +2 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java +94 -3
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +10 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilMediaCollection.java +123 -87
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +99 -1
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilUtils.java +5 -17
- package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +4 -0
- package/class/ReactNativeBlobUtilBlobResponse.js +1 -1
- package/fs.js +42 -3
- package/index.d.ts +30 -1
- package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.m +4 -3
- package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +6 -2
- package/ios/ReactNativeBlobUtilConst.h +1 -0
- package/ios/ReactNativeBlobUtilConst.m +1 -0
- package/ios/ReactNativeBlobUtilFS.h +2 -1
- package/ios/ReactNativeBlobUtilFS.m +30 -2
- package/ios/ReactNativeBlobUtilFileTransformer.h +24 -0
- package/ios/ReactNativeBlobUtilFileTransformer.m +21 -0
- package/ios/ReactNativeBlobUtilReqBuilder.m +3 -4
- package/ios/ReactNativeBlobUtilRequest.m +35 -7
- package/mediacollection.js +6 -1
- package/package.json +1 -1
- package/polyfill/Fetch.js +4 -2
- package/types.js +1 -0
- package/ios/IOS7Polyfill.h +0 -27
package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilMediaCollection.java
CHANGED
|
@@ -10,11 +10,10 @@ import android.os.ParcelFileDescriptor;
|
|
|
10
10
|
import android.provider.MediaStore;
|
|
11
11
|
import android.util.Base64;
|
|
12
12
|
|
|
13
|
-
import androidx.annotation.RequiresApi;
|
|
14
|
-
|
|
15
13
|
import com.ReactNativeBlobUtil.Utils.FileDescription;
|
|
16
14
|
import com.facebook.react.bridge.Arguments;
|
|
17
15
|
import com.facebook.react.bridge.Promise;
|
|
16
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
18
17
|
import com.facebook.react.bridge.WritableArray;
|
|
19
18
|
|
|
20
19
|
import java.io.File;
|
|
@@ -62,21 +61,29 @@ public class ReactNativeBlobUtilMediaCollection {
|
|
|
62
61
|
return res;
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
private static String getRelativePath(MediaType mt) {
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
private static String getRelativePath(MediaType mt, ReactApplicationContext ctx) {
|
|
65
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
66
|
+
if (mt == MediaType.Audio) return Environment.DIRECTORY_MUSIC;
|
|
67
|
+
if (mt == MediaType.Video) return Environment.DIRECTORY_MOVIES;
|
|
68
|
+
if (mt == MediaType.Image) return Environment.DIRECTORY_PICTURES;
|
|
69
|
+
if (mt == MediaType.Download) return Environment.DIRECTORY_DOWNLOADS;
|
|
70
|
+
return Environment.DIRECTORY_DOWNLOADS;
|
|
71
|
+
} else {
|
|
72
|
+
if (mt == MediaType.Audio) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_MUSIC);
|
|
73
|
+
if (mt == MediaType.Video) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_MOVIES);
|
|
74
|
+
if (mt == MediaType.Image) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_PICTURES);
|
|
75
|
+
if (mt == MediaType.Download) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_DOWNLOADS);
|
|
76
|
+
return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_DOWNLOADS);
|
|
77
|
+
}
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
public static Uri createNewMediaFile(FileDescription file, MediaType mt) {
|
|
80
|
+
public static Uri createNewMediaFile(FileDescription file, MediaType mt, ReactApplicationContext ctx) {
|
|
74
81
|
// Add a specific media item.
|
|
75
82
|
Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
|
|
76
83
|
ContentResolver resolver = appCtx.getContentResolver();
|
|
77
84
|
|
|
78
85
|
ContentValues fileDetails = new ContentValues();
|
|
79
|
-
String relativePath = getRelativePath(mt);
|
|
86
|
+
String relativePath = getRelativePath(mt, ctx);
|
|
80
87
|
String mimeType = file.mimeType;
|
|
81
88
|
|
|
82
89
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
@@ -91,12 +98,24 @@ public class ReactNativeBlobUtilMediaCollection {
|
|
|
91
98
|
// Keeps a handle to the new file's URI in case we need to modify it later.
|
|
92
99
|
return resolver.insert(mediauri, fileDetails);
|
|
93
100
|
} else {
|
|
94
|
-
File
|
|
95
|
-
if (
|
|
96
|
-
File f = new File(relativePath + '/' + file.getFullPath());
|
|
101
|
+
File f = new File(relativePath + file.getFullPath());
|
|
102
|
+
if (true) {
|
|
97
103
|
if (!f.exists()) {
|
|
98
|
-
|
|
99
|
-
if (
|
|
104
|
+
File parent = f.getParentFile();
|
|
105
|
+
if (parent != null && !parent.exists() && !parent.mkdirs()) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
if (f.createNewFile()) ;
|
|
110
|
+
{
|
|
111
|
+
return Uri.fromFile(f);
|
|
112
|
+
}
|
|
113
|
+
} catch (IOException ioException) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
} else {
|
|
118
|
+
return Uri.fromFile(f);
|
|
100
119
|
}
|
|
101
120
|
|
|
102
121
|
}
|
|
@@ -105,83 +124,99 @@ public class ReactNativeBlobUtilMediaCollection {
|
|
|
105
124
|
return null;
|
|
106
125
|
}
|
|
107
126
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
public static boolean writeToMediaFile(Uri fileUri, String data, boolean transformFile, Promise promise) {
|
|
128
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
129
|
+
try {
|
|
130
|
+
Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
|
|
131
|
+
ContentResolver resolver = appCtx.getContentResolver();
|
|
113
132
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
133
|
+
// set pending doesn't work right now. We would have to requery for the item
|
|
134
|
+
//ContentValues contentValues = new ContentValues();
|
|
135
|
+
//contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
|
|
136
|
+
//resolver.update(fileUri, contentValues, null, null);
|
|
118
137
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
138
|
+
// write data
|
|
139
|
+
OutputStream stream = null;
|
|
140
|
+
Uri uri = null;
|
|
122
141
|
|
|
123
|
-
try {
|
|
124
|
-
ParcelFileDescriptor descr;
|
|
125
142
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
143
|
+
ParcelFileDescriptor descr;
|
|
144
|
+
try {
|
|
145
|
+
assert fileUri != null;
|
|
146
|
+
descr = appCtx.getContentResolver().openFileDescriptor(fileUri, "w");
|
|
147
|
+
assert descr != null;
|
|
148
|
+
String normalizedData = ReactNativeBlobUtilUtils.normalizePath(data);
|
|
149
|
+
File src = new File(normalizedData);
|
|
150
|
+
if (!src.exists()) {
|
|
151
|
+
promise.reject("ENOENT", "No such file ('" + normalizedData + "')");
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
FileInputStream fin = new FileInputStream(src);
|
|
157
|
+
FileOutputStream out = new FileOutputStream(descr.getFileDescriptor());
|
|
158
|
+
|
|
159
|
+
if (transformFile) {
|
|
160
|
+
// in order to transform file, we must load the entire file onto memory
|
|
161
|
+
int length = (int) src.length();
|
|
162
|
+
byte[] bytes = new byte[length];
|
|
163
|
+
fin.read(bytes);
|
|
164
|
+
if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
|
|
165
|
+
throw new IllegalStateException("Write to media file with transform was specified but the shared file transformer is not set");
|
|
166
|
+
}
|
|
167
|
+
byte[] transformedBytes = ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(bytes);
|
|
168
|
+
out.write(transformedBytes);
|
|
169
|
+
} else {
|
|
170
|
+
byte[] buf = new byte[10240];
|
|
171
|
+
int read;
|
|
172
|
+
|
|
173
|
+
while ((read = fin.read(buf)) > 0) {
|
|
174
|
+
out.write(buf, 0, read);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
fin.close();
|
|
180
|
+
out.close();
|
|
181
|
+
descr.close();
|
|
182
|
+
} catch (Exception e) {
|
|
183
|
+
e.printStackTrace();
|
|
184
|
+
promise.reject(new IOException("Failed to get output stream."));
|
|
133
185
|
return false;
|
|
134
186
|
}
|
|
135
|
-
byte[] buf = new byte[10240];
|
|
136
|
-
int read;
|
|
137
|
-
int written = 0;
|
|
138
|
-
|
|
139
|
-
FileInputStream fin = new FileInputStream(src);
|
|
140
|
-
FileOutputStream out = new FileOutputStream(descr.getFileDescriptor());
|
|
141
187
|
|
|
142
|
-
|
|
143
|
-
|
|
188
|
+
//contentValues.clear();
|
|
189
|
+
//contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
|
|
190
|
+
//appCtx.getContentResolver().update(fileUri, contentValues, null, null);
|
|
191
|
+
stream = resolver.openOutputStream(fileUri);
|
|
192
|
+
if (stream == null) {
|
|
193
|
+
promise.reject(new IOException("Failed to get output stream."));
|
|
194
|
+
return false;
|
|
144
195
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
} catch (Exception e) {
|
|
150
|
-
e.printStackTrace();
|
|
151
|
-
promise.reject(new IOException("Failed to get output stream."));
|
|
196
|
+
} catch (IOException e) {
|
|
197
|
+
// Don't leave an orphan entry in the MediaStore
|
|
198
|
+
resolver.delete(uri, null, null);
|
|
199
|
+
promise.reject(e);
|
|
152
200
|
return false;
|
|
201
|
+
} finally {
|
|
202
|
+
if (stream != null) {
|
|
203
|
+
stream.close();
|
|
204
|
+
}
|
|
153
205
|
}
|
|
154
206
|
|
|
155
|
-
|
|
156
|
-
contentValues
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
promise.reject(new IOException("Failed to get output stream."));
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
207
|
+
// remove pending
|
|
208
|
+
//contentValues = new ContentValues();
|
|
209
|
+
//contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
|
|
210
|
+
//resolver.update(fileUri, contentValues, null, null);
|
|
211
|
+
|
|
163
212
|
} catch (IOException e) {
|
|
164
|
-
|
|
165
|
-
resolver.delete(uri, null, null);
|
|
166
|
-
promise.reject(e);
|
|
213
|
+
promise.reject("ReactNativeBlobUtil.createMediaFile", "Cannot write to file, file might not exist");
|
|
167
214
|
return false;
|
|
168
|
-
} finally {
|
|
169
|
-
if (stream != null) {
|
|
170
|
-
stream.close();
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
215
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
|
|
178
|
-
resolver.update(fileUri, contentValues, null, null);
|
|
179
|
-
|
|
180
|
-
} catch (IOException e) {
|
|
181
|
-
promise.reject("ReactNativeBlobUtil.createMediaFile", "Cannot write to file, file might not exist");
|
|
182
|
-
return false;
|
|
216
|
+
return true;
|
|
217
|
+
} else {
|
|
218
|
+
return ReactNativeBlobUtilFS.writeFile(ReactNativeBlobUtilUtils.normalizePath(fileUri.toString()), ReactNativeBlobUtilConst.DATA_ENCODE_URI, data, false);
|
|
183
219
|
}
|
|
184
|
-
return true;
|
|
185
220
|
}
|
|
186
221
|
|
|
187
222
|
public static void copyToInternal(Uri contenturi, String destpath, Promise promise) {
|
|
@@ -190,10 +225,16 @@ public class ReactNativeBlobUtilMediaCollection {
|
|
|
190
225
|
|
|
191
226
|
InputStream in = null;
|
|
192
227
|
OutputStream out = null;
|
|
228
|
+
File f = new File((destpath));
|
|
193
229
|
|
|
194
|
-
if (!
|
|
230
|
+
if (!f.exists()) {
|
|
195
231
|
try {
|
|
196
|
-
|
|
232
|
+
File parent = f.getParentFile();
|
|
233
|
+
if (parent != null && !parent.exists() && !parent.mkdirs()) {
|
|
234
|
+
promise.reject("ReactNativeBlobUtil.copyToInternal: Cannot create parent folders<'" + destpath);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
boolean result = f.createNewFile();
|
|
197
238
|
if (!result) {
|
|
198
239
|
promise.reject("ReactNativeBlobUtil.copyToInternal: Destination file at '" + destpath + "' already exists");
|
|
199
240
|
return;
|
|
@@ -240,9 +281,7 @@ public class ReactNativeBlobUtilMediaCollection {
|
|
|
240
281
|
ContentResolver resolver = appCtx.getContentResolver();
|
|
241
282
|
try {
|
|
242
283
|
InputStream in = resolver.openInputStream(contentUri);
|
|
243
|
-
int length =
|
|
244
|
-
|
|
245
|
-
length = in.available();
|
|
284
|
+
int length = in.available();
|
|
246
285
|
|
|
247
286
|
byte[] bytes = new byte[length];
|
|
248
287
|
int bytesRead = in.read(bytes);
|
|
@@ -260,14 +299,11 @@ public class ReactNativeBlobUtilMediaCollection {
|
|
|
260
299
|
case "ascii":
|
|
261
300
|
WritableArray asciiResult = Arguments.createArray();
|
|
262
301
|
for (byte b : bytes) {
|
|
263
|
-
asciiResult.pushInt(
|
|
302
|
+
asciiResult.pushInt(b);
|
|
264
303
|
}
|
|
265
304
|
promise.resolve(asciiResult);
|
|
266
305
|
break;
|
|
267
|
-
|
|
268
|
-
promise.resolve(new String(bytes));
|
|
269
|
-
break;
|
|
270
|
-
default:
|
|
306
|
+
default: // covers utf-8
|
|
271
307
|
promise.resolve(new String(bytes));
|
|
272
308
|
break;
|
|
273
309
|
}
|
|
@@ -12,6 +12,9 @@ import android.net.NetworkCapabilities;
|
|
|
12
12
|
import android.net.NetworkInfo;
|
|
13
13
|
import android.net.Uri;
|
|
14
14
|
import android.os.Build;
|
|
15
|
+
import android.os.Bundle;
|
|
16
|
+
import android.os.Handler;
|
|
17
|
+
import android.os.Message;
|
|
15
18
|
import android.util.Base64;
|
|
16
19
|
import android.webkit.CookieManager;
|
|
17
20
|
|
|
@@ -48,6 +51,9 @@ import java.util.HashMap;
|
|
|
48
51
|
|
|
49
52
|
import java.util.List;
|
|
50
53
|
import java.util.Locale;
|
|
54
|
+
import java.util.concurrent.Executors;
|
|
55
|
+
import java.util.concurrent.Future;
|
|
56
|
+
import java.util.concurrent.ScheduledExecutorService;
|
|
51
57
|
import java.util.concurrent.TimeUnit;
|
|
52
58
|
|
|
53
59
|
import javax.net.ssl.SSLContext;
|
|
@@ -87,6 +93,12 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
87
93
|
BASE64
|
|
88
94
|
}
|
|
89
95
|
|
|
96
|
+
private boolean shouldTransformFile() {
|
|
97
|
+
return this.options.transformFile &&
|
|
98
|
+
// Can only process if it's written to a file
|
|
99
|
+
(this.options.fileCache || this.options.path != null);
|
|
100
|
+
}
|
|
101
|
+
|
|
90
102
|
public static HashMap<String, Call> taskTable = new HashMap<>();
|
|
91
103
|
public static HashMap<String, Long> androidDownloadManagerTaskTable = new HashMap<>();
|
|
92
104
|
static HashMap<String, ReactNativeBlobUtilProgressConfig> progressReport = new HashMap<>();
|
|
@@ -124,7 +136,9 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
124
136
|
this.rawRequestBodyArray = arrayBody;
|
|
125
137
|
this.client = client;
|
|
126
138
|
|
|
127
|
-
|
|
139
|
+
// If transformFile is specified, we first want to get the response back in memory so we can
|
|
140
|
+
// encrypt it wholesale and at that point, write it into the file storage.
|
|
141
|
+
if((this.options.fileCache || this.options.path != null) && !this.shouldTransformFile())
|
|
128
142
|
responseType = ResponseType.FileStorage;
|
|
129
143
|
else
|
|
130
144
|
responseType = ResponseType.KeepInMemory;
|
|
@@ -153,6 +167,59 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
153
167
|
}
|
|
154
168
|
}
|
|
155
169
|
|
|
170
|
+
private final int QUERY = 1314;
|
|
171
|
+
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
|
|
172
|
+
private Future<?> future;
|
|
173
|
+
private Handler mHandler = new Handler(new Handler.Callback() {
|
|
174
|
+
public boolean handleMessage(Message msg) {
|
|
175
|
+
switch (msg.what) {
|
|
176
|
+
|
|
177
|
+
case QUERY:
|
|
178
|
+
|
|
179
|
+
Bundle data = msg.getData();
|
|
180
|
+
long id = data.getLong("downloadManagerId");
|
|
181
|
+
if (id == downloadManagerId) {
|
|
182
|
+
|
|
183
|
+
Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
|
|
184
|
+
|
|
185
|
+
DownloadManager downloadManager = (DownloadManager) appCtx.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
186
|
+
|
|
187
|
+
DownloadManager.Query query = new DownloadManager.Query();
|
|
188
|
+
|
|
189
|
+
Cursor cursor = downloadManager.query(query);
|
|
190
|
+
|
|
191
|
+
if (cursor != null && cursor.moveToFirst()) {
|
|
192
|
+
|
|
193
|
+
long written = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
|
|
194
|
+
|
|
195
|
+
long total = cursor.getLong(cursor.getColumnIndex(
|
|
196
|
+
DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
|
|
197
|
+
cursor.close();
|
|
198
|
+
|
|
199
|
+
ReactNativeBlobUtilProgressConfig reportConfig = getReportProgress(taskId);
|
|
200
|
+
float progress = (total != -1) ? written / total : 0;
|
|
201
|
+
|
|
202
|
+
if (reportConfig != null && reportConfig.shouldReport(progress /* progress */)) {
|
|
203
|
+
WritableMap args = Arguments.createMap();
|
|
204
|
+
args.putString("taskId", String.valueOf(taskId));
|
|
205
|
+
args.putString("written", String.valueOf(written));
|
|
206
|
+
args.putString("total", String.valueOf(total));
|
|
207
|
+
args.putString("chunk", "");
|
|
208
|
+
ReactNativeBlobUtil.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
209
|
+
.emit(ReactNativeBlobUtilConst.EVENT_PROGRESS, args);
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (total == written) {
|
|
214
|
+
future.cancel(true);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
156
223
|
@Override
|
|
157
224
|
public void run() {
|
|
158
225
|
|
|
@@ -204,6 +271,17 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
204
271
|
downloadManagerId = dm.enqueue(req);
|
|
205
272
|
androidDownloadManagerTaskTable.put(taskId, Long.valueOf(downloadManagerId));
|
|
206
273
|
appCtx.registerReceiver(this, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
|
274
|
+
future = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
|
|
275
|
+
@Override
|
|
276
|
+
public void run() {
|
|
277
|
+
Message msg = mHandler.obtainMessage();
|
|
278
|
+
Bundle data = new Bundle();
|
|
279
|
+
data.putLong("downloadManagerId", downloadManagerId);
|
|
280
|
+
msg.setData(data);
|
|
281
|
+
msg.what = QUERY;
|
|
282
|
+
mHandler.sendMessage(msg);
|
|
283
|
+
}
|
|
284
|
+
}, 0, 100, TimeUnit.MILLISECONDS);
|
|
207
285
|
return;
|
|
208
286
|
}
|
|
209
287
|
|
|
@@ -557,6 +635,26 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
557
635
|
// response data directly pass to JS context as string.
|
|
558
636
|
else {
|
|
559
637
|
byte[] b = resp.body().bytes();
|
|
638
|
+
// If process file option is turned on, we first keep response in memory and then stream that content
|
|
639
|
+
// after processing
|
|
640
|
+
if (this.shouldTransformFile()) {
|
|
641
|
+
if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
|
|
642
|
+
throw new IllegalStateException("Write file with transform was specified but the shared file transformer is not set");
|
|
643
|
+
}
|
|
644
|
+
this.destPath = this.destPath.replace("?append=true", "");
|
|
645
|
+
File file = new File(this.destPath);
|
|
646
|
+
if (!file.exists()) {
|
|
647
|
+
file.createNewFile();
|
|
648
|
+
}
|
|
649
|
+
try (FileOutputStream fos = new FileOutputStream(file)) {
|
|
650
|
+
fos.write(ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(b));
|
|
651
|
+
} catch(Exception e) {
|
|
652
|
+
callback.invoke("Error from file transformer:" + e.getLocalizedMessage(), null);
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
560
658
|
if (responseFormat == ResponseFormat.BASE64) {
|
|
561
659
|
callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP));
|
|
562
660
|
return;
|
|
@@ -10,7 +10,6 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
|
10
10
|
|
|
11
11
|
import java.nio.charset.Charset;
|
|
12
12
|
import java.security.MessageDigest;
|
|
13
|
-
import java.security.cert.CertificateException;
|
|
14
13
|
import java.util.Locale;
|
|
15
14
|
|
|
16
15
|
import javax.net.ssl.HostnameVerifier;
|
|
@@ -22,9 +21,10 @@ import javax.net.ssl.X509TrustManager;
|
|
|
22
21
|
|
|
23
22
|
import okhttp3.OkHttpClient;
|
|
24
23
|
|
|
25
|
-
|
|
26
24
|
public class ReactNativeBlobUtilUtils {
|
|
27
25
|
|
|
26
|
+
public static X509TrustManager sharedTrustManager;
|
|
27
|
+
|
|
28
28
|
public static String getMD5(String input) {
|
|
29
29
|
String result = null;
|
|
30
30
|
|
|
@@ -61,22 +61,10 @@ public class ReactNativeBlobUtilUtils {
|
|
|
61
61
|
|
|
62
62
|
public static OkHttpClient.Builder getUnsafeOkHttpClient(OkHttpClient client) {
|
|
63
63
|
try {
|
|
64
|
-
// Create a trust manager that does not validate certificate chains
|
|
65
|
-
final X509TrustManager x509TrustManager = new X509TrustManager() {
|
|
66
|
-
@Override
|
|
67
|
-
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
|
|
68
|
-
}
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
|
|
72
|
-
}
|
|
65
|
+
if (sharedTrustManager == null) throw new IllegalStateException("Use of own trust manager but none defined");
|
|
73
66
|
|
|
74
|
-
|
|
75
|
-
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
|
|
76
|
-
return new java.security.cert.X509Certificate[]{};
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
final TrustManager[] trustAllCerts = new TrustManager[]{x509TrustManager};
|
|
67
|
+
final TrustManager[] trustAllCerts = new TrustManager[]{sharedTrustManager};
|
|
80
68
|
|
|
81
69
|
// Install the all-trusting trust manager
|
|
82
70
|
final SSLContext sslContext = SSLContext.getInstance("SSL");
|
|
@@ -85,7 +73,7 @@ public class ReactNativeBlobUtilUtils {
|
|
|
85
73
|
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
|
86
74
|
|
|
87
75
|
OkHttpClient.Builder builder = client.newBuilder();
|
|
88
|
-
builder.sslSocketFactory(sslSocketFactory,
|
|
76
|
+
builder.sslSocketFactory(sslSocketFactory, sharedTrustManager);
|
|
89
77
|
builder.hostnameVerifier(new HostnameVerifier() {
|
|
90
78
|
@Override
|
|
91
79
|
public boolean verify(String hostname, SSLSession session) {
|
package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java
CHANGED
|
@@ -72,6 +72,10 @@ public class ReactNativeBlobUtilFileResp extends ResponseBody {
|
|
|
72
72
|
|
|
73
73
|
@Override
|
|
74
74
|
public long contentLength() {
|
|
75
|
+
if (originalBody.contentLength() > Integer.MAX_VALUE) {
|
|
76
|
+
// This is a workaround for a bug Okio buffer where it can't handle larger than int.
|
|
77
|
+
return Integer.MAX_VALUE;
|
|
78
|
+
}
|
|
75
79
|
return originalBody.contentLength();
|
|
76
80
|
}
|
|
77
81
|
|
package/fs.js
CHANGED
|
@@ -160,7 +160,20 @@ function readFile(path: string, encoding: string = 'utf8'): Promise<any> {
|
|
|
160
160
|
if (typeof path !== 'string') {
|
|
161
161
|
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')));
|
|
162
162
|
}
|
|
163
|
-
return ReactNativeBlobUtil.readFile(path, encoding);
|
|
163
|
+
return ReactNativeBlobUtil.readFile(path, encoding, false);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Reads the file, then transforms it before returning the content
|
|
168
|
+
* @param {string} path Path of the file.
|
|
169
|
+
* @param {'base64' | 'utf8' | 'ascii'} encoding Encoding of read stream.
|
|
170
|
+
* @return {Promise<Array<number> | string>}
|
|
171
|
+
*/
|
|
172
|
+
function readFileWithTransform(path: string, encoding: string = 'utf8'): Promise<any> {
|
|
173
|
+
if (typeof path !== 'string') {
|
|
174
|
+
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
|
|
175
|
+
}
|
|
176
|
+
return ReactNativeBlobUtil.readFile(path, encoding, true);
|
|
164
177
|
}
|
|
165
178
|
|
|
166
179
|
/**
|
|
@@ -186,7 +199,31 @@ function writeFile(path: string, data: string | Array<number>, encoding: ?string
|
|
|
186
199
|
return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)));
|
|
187
200
|
}
|
|
188
201
|
else
|
|
189
|
-
return ReactNativeBlobUtil.writeFile(path, encoding, data, false);
|
|
202
|
+
return ReactNativeBlobUtil.writeFile(path, encoding, data, false, false);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Transforms the data and then writes to the file.
|
|
208
|
+
* @param {string} path Path of the file.
|
|
209
|
+
* @param {string | number[]} data Data to write to the file.
|
|
210
|
+
* @param {string} encoding Encoding of data (Optional).
|
|
211
|
+
* @return {Promise}
|
|
212
|
+
*/
|
|
213
|
+
function writeFileWithTransform(path: string, data: string | Array<number>, encoding: ?string = 'utf8'): Promise {
|
|
214
|
+
if (typeof path !== 'string') {
|
|
215
|
+
return Promise.reject(addCode('EINVAL', new TypeError('Missing argument "path" ')))
|
|
216
|
+
}
|
|
217
|
+
if (encoding.toLocaleLowerCase() === 'ascii') {
|
|
218
|
+
return Promise.reject(addCode('EINVAL', new TypeError('ascii is not supported for converted files')))
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
if (typeof data !== 'string') {
|
|
222
|
+
return Promise.reject(addCode('EINVAL', new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`)))
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
else
|
|
226
|
+
return ReactNativeBlobUtil.writeFile(path, encoding, data, true, false)
|
|
190
227
|
}
|
|
191
228
|
}
|
|
192
229
|
|
|
@@ -206,7 +243,7 @@ function appendFile(path: string, data: string | Array<number>, encoding?: strin
|
|
|
206
243
|
return Promise.reject(addCode('EINVAL'), new TypeError(`"data" must be a String when encoding is "utf8" or "base64", but it is "${typeof data}"`));
|
|
207
244
|
}
|
|
208
245
|
else
|
|
209
|
-
return ReactNativeBlobUtil.writeFile(path, encoding, data, true);
|
|
246
|
+
return ReactNativeBlobUtil.writeFile(path, encoding, data, false, true);
|
|
210
247
|
}
|
|
211
248
|
}
|
|
212
249
|
|
|
@@ -415,6 +452,8 @@ export default {
|
|
|
415
452
|
cp,
|
|
416
453
|
writeStream,
|
|
417
454
|
writeFile,
|
|
455
|
+
writeFileWithTransform,
|
|
456
|
+
readFileWithTransform,
|
|
418
457
|
appendFile,
|
|
419
458
|
pathForAppGroup,
|
|
420
459
|
syncPathAppGroup,
|
package/index.d.ts
CHANGED
|
@@ -399,6 +399,14 @@ export interface FS {
|
|
|
399
399
|
*/
|
|
400
400
|
writeFile(path: string, data: string | number[], encoding?: Encoding): Promise<void>;
|
|
401
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Processes the data and then writes to the file.
|
|
404
|
+
* @param path Path of the file.
|
|
405
|
+
* @param data Data to write to the file.
|
|
406
|
+
* @param encoding Encoding of data (Optional).
|
|
407
|
+
*/
|
|
408
|
+
writeFileWithTransform(path: string, data: string | number[], encoding?: Encoding): Promise<void>;
|
|
409
|
+
|
|
402
410
|
appendFile(path: string, data: string | number[], encoding?: Encoding | "uri"): Promise<number>;
|
|
403
411
|
|
|
404
412
|
/**
|
|
@@ -408,6 +416,13 @@ export interface FS {
|
|
|
408
416
|
*/
|
|
409
417
|
readFile(path: string, encoding: Encoding, bufferSize?: number): Promise<any>;
|
|
410
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Reads from a file and then processes the data before returning
|
|
421
|
+
* @param path Path of the file.
|
|
422
|
+
* @param encoding Encoding of read stream.
|
|
423
|
+
*/
|
|
424
|
+
readFileWithTransform(path: string, encoding: Encoding, bufferSize?: number): Promise<any>;
|
|
425
|
+
|
|
411
426
|
/**
|
|
412
427
|
* Check if file exists and if it is a folder.
|
|
413
428
|
* @param path Path to check
|
|
@@ -475,7 +490,7 @@ export interface ReactNativeBlobUtilWriteStream {
|
|
|
475
490
|
|
|
476
491
|
write(data: string): Promise<void>;
|
|
477
492
|
|
|
478
|
-
close(): void
|
|
493
|
+
close(): Promise<void>;
|
|
479
494
|
}
|
|
480
495
|
|
|
481
496
|
export interface ReactNativeBlobUtilReadStream {
|
|
@@ -698,6 +713,13 @@ export interface ReactNativeBlobUtilConfig {
|
|
|
698
713
|
*/
|
|
699
714
|
fileCache?: boolean;
|
|
700
715
|
|
|
716
|
+
/**
|
|
717
|
+
* Set this property to true if you want the data to be processed before it gets written onto disk.
|
|
718
|
+
* This only has effect if the FileTransformer has been registered and the library is configured to write
|
|
719
|
+
* response onto disk.
|
|
720
|
+
*/
|
|
721
|
+
transformFile?: boolean;
|
|
722
|
+
|
|
701
723
|
/**
|
|
702
724
|
* Set this property to change temp file extension that created by fetch response data.
|
|
703
725
|
*/
|
|
@@ -808,6 +830,13 @@ export interface MediaCollection {
|
|
|
808
830
|
*/
|
|
809
831
|
writeToMediafile(uri: string, path: string): Promise<string>
|
|
810
832
|
|
|
833
|
+
/**
|
|
834
|
+
* Copies and transforms an existing file to a mediastore file. Make sure FileTransformer is set
|
|
835
|
+
* @param uri URI of the destination mediastore file
|
|
836
|
+
* @param path Path to the existing file which should be copied
|
|
837
|
+
*/
|
|
838
|
+
writeToMediafileWithTransform(uri: string, path: string): Promise<string>
|
|
839
|
+
|
|
811
840
|
/**
|
|
812
841
|
* Copies a file from the mediastore to the apps internal storage
|
|
813
842
|
* @param contenturi URI of the mediastore file
|