|
2 | 2 |
|
3 | 3 | An abstraction to allow working with files across multiple platforms. |
4 | 4 |
|
| 5 | +<?code-excerpt path-base="example/lib"?> |
| 6 | + |
| 7 | +[](https://pub.dartlang.org/packages/cross_file) |
| 8 | + |
| 9 | +| | Android | iOS | Linux | macOS | Web | Windows | |
| 10 | +|-------------|---------|---------|-------|--------|-----|-------------| |
| 11 | +| **Support** | SDK 24+ | iOS 13+ | Any | 10.15+ | Any | Windows 10+ | |
| 12 | + |
| 13 | +## Overview |
| 14 | + |
| 15 | +This package provides a unified API for interacting with resources across platforms through two |
| 16 | +primary implementation types: |
| 17 | + |
| 18 | +### FileSystem |
| 19 | + |
| 20 | +The `FileSystem` implementation represents resources on a traditional file system. It is used when |
| 21 | +resources are identified by standard file paths or `file://` URIs. |
| 22 | + |
| 23 | +* **Classes**: `FileSystemXFile`, `FileSystemXDirectory`. |
| 24 | +* **Use Cases**: Desktop applications, app-private storage on mobile, or any environment where |
| 25 | + direct file system access is available. |
| 26 | + |
| 27 | +### ScopedStorage |
| 28 | + |
| 29 | +The `ScopedStorage` implementation represents resources that are managed or restricted by the |
| 30 | +platform. These resources are typically identified by platform-specific URIs rather than direct |
| 31 | +paths. |
| 32 | + |
| 33 | +* **Classes**: `ScopedStorageXFile`, `ScopedStorageXDirectory`. |
| 34 | +* **Use Cases**: Android Content URIs, iOS Security-Scoped bookmarks, Web Object URLs, or Photo |
| 35 | + Library assets. |
| 36 | +* **Key Characteristic**: Access to these resources may be ephemeral or requires explicit lifecycle |
| 37 | + management (e.g., using `dispose()` or specific platform extensions). |
| 38 | + |
5 | 39 | ## Usage |
6 | 40 |
|
7 | | -Import `package:cross_file/cross_file.dart`, instantiate a `XFile` |
8 | | -using a path or byte array and use its methods and properties to |
9 | | -access the file and its metadata. |
| 41 | +Instantiate a `XFile` using a uri or path and use its methods and properties to access the file and |
| 42 | +its metadata. |
10 | 43 |
|
11 | 44 | Example: |
12 | 45 |
|
13 | | -<?code-excerpt "example/lib/main.dart (Instantiate)"?> |
| 46 | +<?code-excerpt "readme_excerpts.dart (Instantiate)"?> |
14 | 47 | ```dart |
15 | | -final file = XFile('assets/hello.txt'); |
| 48 | +final file = XFile.fileSystem(path: 'assets/hello.txt'); |
16 | 49 |
|
17 | | -print('XFile from disk:'); |
18 | | -print('- Path: ${file.path}'); |
19 | | -print('- Name: ${file.name}'); |
20 | | -print('- Length: ${await file.length()} bytes'); |
21 | | -print('- Content: ${await file.readAsString()}'); |
22 | | -``` |
| 50 | +debugPrint('File information:'); |
| 51 | +debugPrint('- URI: ${file.uri}'); |
| 52 | +debugPrint('- Name: ${await file.name()}'); |
23 | 53 |
|
24 | | -You will find links to the API docs on the [pub page](https://pub.dev/packages/cross_file). |
25 | | - |
26 | | -## MIME types |
| 54 | +if (await file.exists()) { |
| 55 | + final String fileContent = await file.readAsString(); |
| 56 | + debugPrint('Content of the file: $fileContent'); |
| 57 | +} |
| 58 | +``` |
27 | 59 |
|
28 | | -On web, `mimeType` reflects browser-provided file metadata when available. |
29 | | -Native implementations do not infer MIME types from file paths or contents. |
30 | | -On native platforms, `mimeType` returns the value explicitly passed to the |
31 | | -`XFile` constructor or `XFile.fromData`, if any. |
| 60 | +You can find links to the API docs on the [pub page](https://pub.dev/documentation/cross_file/latest/). |
32 | 61 |
|
33 | | -## Web Limitations |
| 62 | +### Implementation-Specific Features |
34 | 63 |
|
35 | | -`XFile` on the web platform is backed by [Blob](https://api.dart.dev/be/180361/dart-html/Blob-class.html) |
36 | | -objects and their URLs. |
| 64 | +Classes in this package contain an underlying platform implementation that provides features that |
| 65 | +are specific to an implementation. |
37 | 66 |
|
38 | | -It seems that Safari hangs when reading Blobs larger than 4GB (your app will stop |
39 | | -without returning any data, or throwing an exception). |
| 67 | +To access implementation-specific features, start by adding the platform implementation packages to |
| 68 | +your app or package: |
40 | 69 |
|
41 | | -This package will attempt to throw an `Exception` before a large file is accessed |
42 | | -from Safari (if its size is known beforehand), so that case can be handled |
43 | | -programmatically. |
| 70 | +* **dart:io** [cross_file_io](https://pub.dev/packages/cross_file_io/install) |
| 71 | +* **Android Scoped Storage**: [cross_file_android](https://pub.dev/packages/cross_file_android/install) |
| 72 | +* **iOS/macOS App Sandbox**: [cross_file_darwin](https://pub.dev/packages/cross_file_darwin/install) |
| 73 | +* **Web**: [cross_file_web](https://pub.dev/packages/cross_file_web/install) |
44 | 74 |
|
45 | | -### Browser compatibility |
| 75 | +Next, add the imports of the implementation packages to your app or package: |
46 | 76 |
|
47 | | -[](https://caniuse.com/blobbuilder) |
| 77 | +<?code-excerpt "readme_excerpts.dart (platform_imports)"?> |
| 78 | +```dart |
| 79 | +// Import for Darwin App Sandbox features. |
| 80 | +import 'package:cross_file_darwin/cross_file_darwin.dart'; |
| 81 | +// Import for Web features. |
| 82 | +import 'package:cross_file_web/cross_file_web.dart'; |
| 83 | +``` |
48 | 84 |
|
49 | | -[](https://caniuse.com/bloburls) |
| 85 | +Now, additional features can be accessed through the platform implementations. Classes |
| 86 | +`FileSystemXFile`, `FileSystemXDirectory`, `ScopedStorageXFile`, and `ScopedStorageXDirectory` pass |
| 87 | +their functionality to a class provided by the current platform. Below are a couple of ways to |
| 88 | +access additional functionality provided by the platform and is followed by an example. |
50 | 89 |
|
51 | | -## Testing |
| 90 | +1. Pass a creation params class provided by a platform implementation to a `fromCreationParams` |
| 91 | + constructor (e.g. `FileSystemXFile.fromCreationParams`, `ScopedStorageXFile.fromCreationParams`, |
| 92 | + etc.). |
| 93 | +2. Call methods on an implementation of a class by using `getExtension` method (e.g. |
| 94 | + `XFile.getExtension`, `XDirectory.getExtension`, etc.). |
52 | 95 |
|
53 | | -This package supports both web and native platforms. Unit tests need to be split |
54 | | -in two separate suites (because native code cannot use `package:web`, and web code |
55 | | -cannot use `dart:io`). |
| 96 | +Below is an example of using additional iOS/macOS and Web features for a `XFile`. |
56 | 97 |
|
57 | | -When adding new features, it is likely that tests need to be added for both the |
58 | | -native and web platforms. |
| 98 | +<?code-excerpt "readme_excerpts.dart (platform_features)"?> |
| 99 | +```dart |
| 100 | +late final XFile file; |
| 101 | +
|
| 102 | +switch (CrossFile.implementation) { |
| 103 | + case CrossFileWeb(): |
| 104 | + final params = WebScopedStorageXFileCreationParams.fromObjectUrl( |
| 105 | + objectUrl: 'blob:https://some/url:for/file', |
| 106 | + ); |
| 107 | + file = ScopedStorageXFile.fromCreationParams(params); |
| 108 | + case CrossFileDarwin(): |
| 109 | + file = ScopedStorageXFile.fromUri(Uri.file('/my/file.txt')); |
| 110 | + default: |
| 111 | + file = XFile.fileSystem(path: '/my/file.txt'); |
| 112 | +} |
| 113 | +
|
| 114 | +await file |
| 115 | + .getExtension<SecurityScopedDarwinScopedStorageXFileExtension>() |
| 116 | + ?.startAccessingSecurityScopedResource(); |
| 117 | +
|
| 118 | +debugPrint(await file.readAsString()); |
| 119 | +
|
| 120 | +if (file is ScopedStorageXFile) { |
| 121 | + await file.dispose(); |
| 122 | +} |
| 123 | +``` |
59 | 124 |
|
60 | | -### Native tests |
| 125 | +See https://pub.dev/documentation/cross_file_darwin/latest/cross_file_darwin/cross_file_darwin-library.html |
| 126 | +for more details on iOS/macOS App Sandbox features. |
61 | 127 |
|
62 | | -Tests for native platforms are located in the `x_file_io_test.dart`. Tests can |
63 | | -be run with `dart test`. |
| 128 | +See https://pub.dev/documentation/cross_file_android/latest/cross_file_android/cross_file_android-library.html |
| 129 | +for more details on Android Scoped Storage features. |
64 | 130 |
|
65 | | -### Web tests |
| 131 | +See https://pub.dev/documentation/cross_file_io/latest/cross_file_io/cross_file_io-library.html |
| 132 | +for more details on `dart:io` features. |
66 | 133 |
|
67 | | -Tests for the web platform live in the `x_file_html_test.dart`. They can be run |
68 | | -with `dart test -p chrome`. |
| 134 | +See https://pub.dev/documentation/cross_file_web/latest/cross_file_web/cross_file_web-library.html |
| 135 | +for more details on Web features. |
0 commit comments