@capacitor/filesystem 7.0.2-nightly-20250526T150552.0 → 7.1.0-dev.2

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.
Files changed (39) hide show
  1. package/CapacitorFilesystem.podspec +4 -3
  2. package/LICENSE +17 -19
  3. package/Package.swift +10 -4
  4. package/README.md +149 -78
  5. package/android/build.gradle +12 -22
  6. package/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemErrors.kt +101 -0
  7. package/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodOptions.kt +129 -0
  8. package/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemMethodResults.kt +65 -0
  9. package/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/FilesystemPlugin.kt +412 -0
  10. package/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/LegacyFilesystemImplementation.kt +169 -0
  11. package/android/src/main/kotlin/com/capacitorjs/plugins/filesystem/PluginResultExtensions.kt +25 -0
  12. package/dist/docs.json +227 -145
  13. package/dist/esm/definitions.d.ts +102 -64
  14. package/dist/esm/definitions.js +25 -3
  15. package/dist/esm/definitions.js.map +1 -1
  16. package/dist/esm/index.js +3 -1
  17. package/dist/esm/index.js.map +1 -1
  18. package/dist/esm/web.d.ts +3 -1
  19. package/dist/esm/web.js +10 -10
  20. package/dist/esm/web.js.map +1 -1
  21. package/dist/plugin.cjs.js +40 -14
  22. package/dist/plugin.cjs.js.map +1 -1
  23. package/dist/plugin.js +41 -16
  24. package/dist/plugin.js.map +1 -1
  25. package/ios/Sources/FilesystemPlugin/CAPPluginCall+Accelerators.swift +73 -0
  26. package/ios/Sources/FilesystemPlugin/FilesystemConstants.swift +61 -0
  27. package/ios/Sources/FilesystemPlugin/FilesystemError.swift +57 -0
  28. package/ios/Sources/FilesystemPlugin/FilesystemLocationResolver.swift +39 -0
  29. package/ios/Sources/FilesystemPlugin/FilesystemOperation.swift +24 -0
  30. package/ios/Sources/FilesystemPlugin/FilesystemOperationExecutor.swift +116 -0
  31. package/ios/Sources/FilesystemPlugin/FilesystemPlugin.swift +103 -264
  32. package/ios/Sources/FilesystemPlugin/IONFileStructures+Converters.swift +60 -0
  33. package/ios/Sources/FilesystemPlugin/{Filesystem.swift → LegacyFilesystemImplementation.swift} +18 -179
  34. package/package.json +28 -24
  35. package/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java +0 -414
  36. package/android/src/main/java/com/capacitorjs/plugins/filesystem/FilesystemPlugin.java +0 -551
  37. package/android/src/main/java/com/capacitorjs/plugins/filesystem/exceptions/CopyFailedException.java +0 -16
  38. package/android/src/main/java/com/capacitorjs/plugins/filesystem/exceptions/DirectoryExistsException.java +0 -16
  39. package/android/src/main/java/com/capacitorjs/plugins/filesystem/exceptions/DirectoryNotFoundException.java +0 -16
@@ -1,551 +0,0 @@
1
- package com.capacitorjs.plugins.filesystem;
2
-
3
- import android.Manifest;
4
- import android.media.MediaScannerConnection;
5
- import android.net.Uri;
6
- import android.os.Build;
7
- import android.os.Environment;
8
- import com.capacitorjs.plugins.filesystem.exceptions.CopyFailedException;
9
- import com.capacitorjs.plugins.filesystem.exceptions.DirectoryExistsException;
10
- import com.capacitorjs.plugins.filesystem.exceptions.DirectoryNotFoundException;
11
- import com.getcapacitor.JSArray;
12
- import com.getcapacitor.JSObject;
13
- import com.getcapacitor.Logger;
14
- import com.getcapacitor.PermissionState;
15
- import com.getcapacitor.Plugin;
16
- import com.getcapacitor.PluginCall;
17
- import com.getcapacitor.PluginMethod;
18
- import com.getcapacitor.annotation.CapacitorPlugin;
19
- import com.getcapacitor.annotation.Permission;
20
- import com.getcapacitor.annotation.PermissionCallback;
21
- import com.getcapacitor.plugin.util.HttpRequestHandler;
22
- import java.io.File;
23
- import java.io.FileNotFoundException;
24
- import java.io.IOException;
25
- import java.nio.charset.Charset;
26
- import java.nio.file.Files;
27
- import java.nio.file.attribute.BasicFileAttributes;
28
- import org.json.JSONException;
29
-
30
- @CapacitorPlugin(
31
- name = "Filesystem",
32
- permissions = {
33
- @Permission(
34
- strings = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE },
35
- alias = "publicStorage"
36
- )
37
- }
38
- )
39
- public class FilesystemPlugin extends Plugin {
40
-
41
- static final String PUBLIC_STORAGE = "publicStorage";
42
- private Filesystem implementation;
43
-
44
- @Override
45
- public void load() {
46
- implementation = new Filesystem(getContext());
47
- }
48
-
49
- private static final String PERMISSION_DENIED_ERROR = "Unable to do file operation, user denied permission request";
50
-
51
- @PluginMethod
52
- public void readFile(PluginCall call) {
53
- String path = call.getString("path");
54
- String directory = getDirectoryParameter(call);
55
- String encoding = call.getString("encoding");
56
-
57
- Charset charset = implementation.getEncoding(encoding);
58
- if (encoding != null && charset == null) {
59
- call.reject("Unsupported encoding provided: " + encoding);
60
- return;
61
- }
62
-
63
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
64
- requestAllPermissions(call, "permissionCallback");
65
- } else {
66
- try {
67
- String dataStr = implementation.readFile(path, directory, charset);
68
- JSObject ret = new JSObject();
69
- ret.putOpt("data", dataStr);
70
- call.resolve(ret);
71
- } catch (FileNotFoundException ex) {
72
- call.reject("File does not exist", ex);
73
- } catch (IOException ex) {
74
- call.reject("Unable to read file", ex);
75
- } catch (JSONException ex) {
76
- call.reject("Unable to return value for reading file", ex);
77
- }
78
- }
79
- }
80
-
81
- @PluginMethod
82
- public void writeFile(PluginCall call) {
83
- String path = call.getString("path");
84
- String data = call.getString("data");
85
- Boolean recursive = call.getBoolean("recursive", false);
86
-
87
- if (path == null) {
88
- Logger.error(getLogTag(), "No path or filename retrieved from call", null);
89
- call.reject("NO_PATH");
90
- return;
91
- }
92
-
93
- if (data == null) {
94
- Logger.error(getLogTag(), "No data retrieved from call", null);
95
- call.reject("NO_DATA");
96
- return;
97
- }
98
-
99
- String directory = getDirectoryParameter(call);
100
- if (directory != null) {
101
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
102
- requestAllPermissions(call, "permissionCallback");
103
- } else {
104
- // create directory because it might not exist
105
- File androidDir = implementation.getDirectory(directory);
106
- if (androidDir != null) {
107
- if (androidDir.exists() || androidDir.mkdirs()) {
108
- // path might include directories as well
109
- File fileObject = new File(androidDir, path);
110
- if (fileObject.getParentFile().exists() || (recursive && fileObject.getParentFile().mkdirs())) {
111
- saveFile(call, fileObject, data);
112
- } else {
113
- call.reject("Parent folder doesn't exist");
114
- }
115
- } else {
116
- Logger.error(getLogTag(), "Not able to create '" + directory + "'!", null);
117
- call.reject("NOT_CREATED_DIR");
118
- }
119
- } else {
120
- Logger.error(getLogTag(), "Directory ID '" + directory + "' is not supported by plugin", null);
121
- call.reject("INVALID_DIR");
122
- }
123
- }
124
- } else {
125
- // check file:// or no scheme uris
126
- Uri u = Uri.parse(path);
127
- if (u.getScheme() == null || u.getScheme().equals("file")) {
128
- File fileObject = new File(u.getPath());
129
- // do not know where the file is being store so checking the permission to be secure
130
- // TODO to prevent permission checking we need a property from the call
131
- if (!isStoragePermissionGranted()) {
132
- requestAllPermissions(call, "permissionCallback");
133
- } else {
134
- if (
135
- fileObject.getParentFile() == null ||
136
- fileObject.getParentFile().exists() ||
137
- (recursive && fileObject.getParentFile().mkdirs())
138
- ) {
139
- saveFile(call, fileObject, data);
140
- } else {
141
- call.reject("Parent folder doesn't exist");
142
- }
143
- }
144
- } else {
145
- call.reject(u.getScheme() + " scheme not supported");
146
- }
147
- }
148
- }
149
-
150
- private void saveFile(PluginCall call, File file, String data) {
151
- String encoding = call.getString("encoding");
152
- boolean append = call.getBoolean("append", false);
153
-
154
- Charset charset = implementation.getEncoding(encoding);
155
- if (encoding != null && charset == null) {
156
- call.reject("Unsupported encoding provided: " + encoding);
157
- return;
158
- }
159
-
160
- try {
161
- implementation.saveFile(file, data, charset, append);
162
- // update mediaStore index only if file was written to external storage
163
- if (isPublicDirectory(getDirectoryParameter(call))) {
164
- MediaScannerConnection.scanFile(getContext(), new String[] { file.getAbsolutePath() }, null, null);
165
- }
166
- Logger.debug(getLogTag(), "File '" + file.getAbsolutePath() + "' saved!");
167
- JSObject result = new JSObject();
168
- result.put("uri", Uri.fromFile(file).toString());
169
- call.resolve(result);
170
- } catch (IOException ex) {
171
- Logger.error(
172
- getLogTag(),
173
- "Creating file '" + file.getPath() + "' with charset '" + charset + "' failed. Error: " + ex.getMessage(),
174
- ex
175
- );
176
- call.reject("FILE_NOTCREATED");
177
- } catch (IllegalArgumentException ex) {
178
- call.reject("The supplied data is not valid base64 content.");
179
- }
180
- }
181
-
182
- @PluginMethod
183
- public void appendFile(PluginCall call) {
184
- try {
185
- call.getData().putOpt("append", true);
186
- } catch (JSONException ex) {}
187
-
188
- this.writeFile(call);
189
- }
190
-
191
- @PluginMethod
192
- public void deleteFile(PluginCall call) {
193
- String file = call.getString("path");
194
- String directory = getDirectoryParameter(call);
195
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
196
- requestAllPermissions(call, "permissionCallback");
197
- } else {
198
- try {
199
- boolean deleted = implementation.deleteFile(file, directory);
200
- if (!deleted) {
201
- call.reject("Unable to delete file");
202
- } else {
203
- call.resolve();
204
- }
205
- } catch (FileNotFoundException ex) {
206
- call.reject(ex.getMessage());
207
- }
208
- }
209
- }
210
-
211
- @PluginMethod
212
- public void mkdir(PluginCall call) {
213
- String path = call.getString("path");
214
- String directory = getDirectoryParameter(call);
215
- boolean recursive = call.getBoolean("recursive", false).booleanValue();
216
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
217
- requestAllPermissions(call, "permissionCallback");
218
- } else {
219
- try {
220
- boolean created = implementation.mkdir(path, directory, recursive);
221
- if (!created) {
222
- call.reject("Unable to create directory, unknown reason");
223
- } else {
224
- call.resolve();
225
- }
226
- } catch (DirectoryExistsException ex) {
227
- call.reject(ex.getMessage());
228
- }
229
- }
230
- }
231
-
232
- @PluginMethod
233
- public void rmdir(PluginCall call) {
234
- String path = call.getString("path");
235
- String directory = getDirectoryParameter(call);
236
- Boolean recursive = call.getBoolean("recursive", false);
237
-
238
- File fileObject = implementation.getFileObject(path, directory);
239
-
240
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
241
- requestAllPermissions(call, "permissionCallback");
242
- } else {
243
- if (!fileObject.exists()) {
244
- call.reject("Directory does not exist");
245
- return;
246
- }
247
-
248
- if (fileObject.isDirectory() && fileObject.listFiles().length != 0 && !recursive) {
249
- call.reject("Directory is not empty");
250
- return;
251
- }
252
-
253
- boolean deleted = false;
254
-
255
- try {
256
- implementation.deleteRecursively(fileObject);
257
- deleted = true;
258
- } catch (IOException ignored) {}
259
-
260
- if (!deleted) {
261
- call.reject("Unable to delete directory, unknown reason");
262
- } else {
263
- call.resolve();
264
- }
265
- }
266
- }
267
-
268
- @PluginMethod
269
- public void readdir(PluginCall call) {
270
- String path = call.getString("path");
271
- String directory = getDirectoryParameter(call);
272
-
273
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
274
- requestAllPermissions(call, "permissionCallback");
275
- } else {
276
- try {
277
- File[] files = implementation.readdir(path, directory);
278
- JSArray filesArray = new JSArray();
279
- if (files != null) {
280
- for (var i = 0; i < files.length; i++) {
281
- File fileObject = files[i];
282
- JSObject data = new JSObject();
283
- data.put("name", fileObject.getName());
284
- data.put("type", fileObject.isDirectory() ? "directory" : "file");
285
- data.put("size", fileObject.length());
286
- data.put("mtime", fileObject.lastModified());
287
- data.put("uri", Uri.fromFile(fileObject).toString());
288
-
289
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
290
- try {
291
- BasicFileAttributes attr = Files.readAttributes(fileObject.toPath(), BasicFileAttributes.class);
292
-
293
- // use whichever is the oldest between creationTime and lastAccessTime
294
- if (attr.creationTime().toMillis() < attr.lastAccessTime().toMillis()) {
295
- data.put("ctime", attr.creationTime().toMillis());
296
- } else {
297
- data.put("ctime", attr.lastAccessTime().toMillis());
298
- }
299
- } catch (Exception ex) {}
300
- } else {
301
- data.put("ctime", null);
302
- }
303
- filesArray.put(data);
304
- }
305
-
306
- JSObject ret = new JSObject();
307
- ret.put("files", filesArray);
308
- call.resolve(ret);
309
- } else {
310
- call.reject("Unable to read directory");
311
- }
312
- } catch (DirectoryNotFoundException ex) {
313
- call.reject(ex.getMessage());
314
- }
315
- }
316
- }
317
-
318
- @PluginMethod
319
- public void getUri(PluginCall call) {
320
- String path = call.getString("path");
321
- String directory = getDirectoryParameter(call);
322
-
323
- File fileObject = implementation.getFileObject(path, directory);
324
-
325
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
326
- requestAllPermissions(call, "permissionCallback");
327
- } else {
328
- JSObject data = new JSObject();
329
- data.put("uri", Uri.fromFile(fileObject).toString());
330
- call.resolve(data);
331
- }
332
- }
333
-
334
- @PluginMethod
335
- public void stat(PluginCall call) {
336
- String path = call.getString("path");
337
- String directory = getDirectoryParameter(call);
338
-
339
- File fileObject = implementation.getFileObject(path, directory);
340
-
341
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
342
- requestAllPermissions(call, "permissionCallback");
343
- } else {
344
- if (!fileObject.exists()) {
345
- call.reject("File does not exist");
346
- return;
347
- }
348
-
349
- JSObject data = new JSObject();
350
- data.put("type", fileObject.isDirectory() ? "directory" : "file");
351
- data.put("size", fileObject.length());
352
- data.put("mtime", fileObject.lastModified());
353
- data.put("uri", Uri.fromFile(fileObject).toString());
354
-
355
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
356
- try {
357
- BasicFileAttributes attr = Files.readAttributes(fileObject.toPath(), BasicFileAttributes.class);
358
-
359
- // use whichever is the oldest between creationTime and lastAccessTime
360
- if (attr.creationTime().toMillis() < attr.lastAccessTime().toMillis()) {
361
- data.put("ctime", attr.creationTime().toMillis());
362
- } else {
363
- data.put("ctime", attr.lastAccessTime().toMillis());
364
- }
365
- } catch (Exception ex) {}
366
- } else {
367
- data.put("ctime", null);
368
- }
369
-
370
- call.resolve(data);
371
- }
372
- }
373
-
374
- @PluginMethod
375
- public void rename(PluginCall call) {
376
- this._copy(call, true);
377
- }
378
-
379
- @PluginMethod
380
- public void copy(PluginCall call) {
381
- this._copy(call, false);
382
- }
383
-
384
- @PluginMethod
385
- public void downloadFile(PluginCall call) {
386
- try {
387
- String directory = call.getString("directory", Environment.DIRECTORY_DOWNLOADS);
388
-
389
- if (isPublicDirectory(directory) && !isStoragePermissionGranted()) {
390
- requestAllPermissions(call, "permissionCallback");
391
- return;
392
- }
393
-
394
- HttpRequestHandler.ProgressEmitter emitter = (bytes, contentLength) -> {
395
- JSObject ret = new JSObject();
396
- ret.put("url", call.getString("url"));
397
- ret.put("bytes", bytes);
398
- ret.put("contentLength", contentLength);
399
- notifyListeners("progress", ret);
400
- };
401
-
402
- implementation.downloadFile(
403
- call,
404
- bridge,
405
- emitter,
406
- new Filesystem.FilesystemDownloadCallback() {
407
- @Override
408
- public void onSuccess(JSObject response) {
409
- // update mediaStore index only if file was written to external storage
410
- if (isPublicDirectory(directory)) {
411
- MediaScannerConnection.scanFile(getContext(), new String[] { response.getString("path") }, null, null);
412
- }
413
- call.resolve(response);
414
- }
415
-
416
- @Override
417
- public void onError(Exception error) {
418
- call.reject("Error downloading file: " + error.getLocalizedMessage(), error);
419
- }
420
- }
421
- );
422
- } catch (Exception ex) {
423
- call.reject("Error downloading file: " + ex.getLocalizedMessage(), ex);
424
- }
425
- }
426
-
427
- private void _copy(PluginCall call, Boolean doRename) {
428
- String from = call.getString("from");
429
- String to = call.getString("to");
430
- String directory = call.getString("directory");
431
- String toDirectory = call.getString("toDirectory");
432
-
433
- if (from == null || from.isEmpty() || to == null || to.isEmpty()) {
434
- call.reject("Both to and from must be provided");
435
- return;
436
- }
437
- if (isPublicDirectory(directory) || isPublicDirectory(toDirectory)) {
438
- if (!isStoragePermissionGranted()) {
439
- requestAllPermissions(call, "permissionCallback");
440
- return;
441
- }
442
- }
443
- try {
444
- File file = implementation.copy(from, directory, to, toDirectory, doRename);
445
- if (!doRename) {
446
- JSObject result = new JSObject();
447
- result.put("uri", Uri.fromFile(file).toString());
448
- call.resolve(result);
449
- } else {
450
- call.resolve();
451
- }
452
- } catch (CopyFailedException ex) {
453
- call.reject(ex.getMessage());
454
- } catch (IOException ex) {
455
- call.reject("Unable to perform action: " + ex.getLocalizedMessage());
456
- }
457
- }
458
-
459
- @PluginMethod
460
- public void checkPermissions(PluginCall call) {
461
- if (isStoragePermissionGranted()) {
462
- JSObject permissionsResultJSON = new JSObject();
463
- permissionsResultJSON.put(PUBLIC_STORAGE, "granted");
464
- call.resolve(permissionsResultJSON);
465
- } else {
466
- super.checkPermissions(call);
467
- }
468
- }
469
-
470
- @PluginMethod
471
- public void requestPermissions(PluginCall call) {
472
- if (isStoragePermissionGranted()) {
473
- JSObject permissionsResultJSON = new JSObject();
474
- permissionsResultJSON.put(PUBLIC_STORAGE, "granted");
475
- call.resolve(permissionsResultJSON);
476
- } else {
477
- super.requestPermissions(call);
478
- }
479
- }
480
-
481
- @PermissionCallback
482
- private void permissionCallback(PluginCall call) {
483
- if (!isStoragePermissionGranted()) {
484
- Logger.debug(getLogTag(), "User denied storage permission");
485
- call.reject(PERMISSION_DENIED_ERROR);
486
- return;
487
- }
488
-
489
- switch (call.getMethodName()) {
490
- case "appendFile":
491
- case "writeFile":
492
- writeFile(call);
493
- break;
494
- case "deleteFile":
495
- deleteFile(call);
496
- break;
497
- case "mkdir":
498
- mkdir(call);
499
- break;
500
- case "rmdir":
501
- rmdir(call);
502
- break;
503
- case "rename":
504
- rename(call);
505
- break;
506
- case "copy":
507
- copy(call);
508
- break;
509
- case "readFile":
510
- readFile(call);
511
- break;
512
- case "readdir":
513
- readdir(call);
514
- break;
515
- case "getUri":
516
- getUri(call);
517
- break;
518
- case "stat":
519
- stat(call);
520
- break;
521
- case "downloadFile":
522
- downloadFile(call);
523
- break;
524
- }
525
- }
526
-
527
- /**
528
- * Checks the the given permission is granted or not
529
- * @return Returns true if the app is running on Android 30 or newer or if the permission is already granted
530
- * or false if it is denied.
531
- */
532
- private boolean isStoragePermissionGranted() {
533
- return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R || getPermissionState(PUBLIC_STORAGE) == PermissionState.GRANTED;
534
- }
535
-
536
- /**
537
- * Reads the directory parameter from the plugin call
538
- * @param call the plugin call
539
- */
540
- private String getDirectoryParameter(PluginCall call) {
541
- return call.getString("directory");
542
- }
543
-
544
- /**
545
- * True if the given directory string is a public storage directory, which is accessible by the user or other apps.
546
- * @param directory the directory string.
547
- */
548
- private boolean isPublicDirectory(String directory) {
549
- return "DOCUMENTS".equals(directory) || "EXTERNAL_STORAGE".equals(directory);
550
- }
551
- }
@@ -1,16 +0,0 @@
1
- package com.capacitorjs.plugins.filesystem.exceptions;
2
-
3
- public class CopyFailedException extends Exception {
4
-
5
- public CopyFailedException(String s) {
6
- super(s);
7
- }
8
-
9
- public CopyFailedException(Throwable t) {
10
- super(t);
11
- }
12
-
13
- public CopyFailedException(String s, Throwable t) {
14
- super(s, t);
15
- }
16
- }
@@ -1,16 +0,0 @@
1
- package com.capacitorjs.plugins.filesystem.exceptions;
2
-
3
- public class DirectoryExistsException extends Exception {
4
-
5
- public DirectoryExistsException(String s) {
6
- super(s);
7
- }
8
-
9
- public DirectoryExistsException(Throwable t) {
10
- super(t);
11
- }
12
-
13
- public DirectoryExistsException(String s, Throwable t) {
14
- super(s, t);
15
- }
16
- }
@@ -1,16 +0,0 @@
1
- package com.capacitorjs.plugins.filesystem.exceptions;
2
-
3
- public class DirectoryNotFoundException extends Exception {
4
-
5
- public DirectoryNotFoundException(String s) {
6
- super(s);
7
- }
8
-
9
- public DirectoryNotFoundException(Throwable t) {
10
- super(t);
11
- }
12
-
13
- public DirectoryNotFoundException(String s, Throwable t) {
14
- super(s, t);
15
- }
16
- }