expo-tiddlywiki-filesystem-android-external-storage 2.0.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.
- package/README.md +123 -0
- package/android/build.gradle +19 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/externalstorage/ExternalStorageModule.kt +823 -0
- package/app.plugin.js +25 -0
- package/build/index.d.ts +130 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +45 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +6 -0
- package/package.json +50 -0
- package/plugin.js +25 -0
- package/src/index.ts +196 -0
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# expo-tiddlywiki-filesystem-android-external-storage
|
|
2
|
+
|
|
3
|
+
An Expo Config Plugin and Native Module for accessing Android's External Storage (e.g. `/sdcard/Documents/`) directly using `java.io.File`, bypassing Expo FileSystem's scoped storage restrictions.
|
|
4
|
+
|
|
5
|
+
## Why this package?
|
|
6
|
+
|
|
7
|
+
We built this because we faced significant limitations with standard approaches when developing **TidGi-Mobile** (a TiddlyWiki app that needs to sync with desktop):
|
|
8
|
+
|
|
9
|
+
1. **SAF (Storage Access Framework) is too slow**: We need to sync thousands of small `.tid` files. Using `DocumentFile` and SAF APIs for batch operations was incredibly slow compared to direct file access.
|
|
10
|
+
2. **`expo-file-system` is restricted**: Even if you add `MANAGE_EXTERNAL_STORAGE` permission to your `app.json`, the standard `expo-file-system` APIs are scoped to the app's internal directory (or specific cache dirs). They generally cannot access arbitrary paths like `/sdcard/Documents/TidGi/` directly.
|
|
11
|
+
3. **Permissions alone are insufficient**: Simply adding the permissions below to `app.json` does **not** grant `expo-file-system` access to external storage due to its internal "scoped" design.
|
|
12
|
+
```json
|
|
13
|
+
"permissions": [
|
|
14
|
+
"android.permission.READ_EXTERNAL_STORAGE",
|
|
15
|
+
"android.permission.WRITE_EXTERNAL_STORAGE",
|
|
16
|
+
"android.permission.MANAGE_EXTERNAL_STORAGE"
|
|
17
|
+
]
|
|
18
|
+
```
|
|
19
|
+
4. **Legacy API failures**: We tried using `expo-file-system`'s legacy storage flags, but they often failed or were inconsistent across Android versions.
|
|
20
|
+
|
|
21
|
+
Therefore, we implemented this **Native Module** which uses standard `java.io.File` APIs in Kotlin. This requires:
|
|
22
|
+
- **Expo Development Client**: You cannot use Expo Go because this package contains custom native code. You must build a custom dev client or a production build (prebuild).
|
|
23
|
+
- **`MANAGE_EXTERNAL_STORAGE` Permission**: The user must grant "All files access" in system settings.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Direct File Access**: Read and write to any path the app has permission for.
|
|
28
|
+
- **Bypass Scoped Storage**: Works with absolute paths (e.g. `/storage/emulated/0/...`).
|
|
29
|
+
- **Standard Operations**: `exists`, `read`, `write`, `mkdir`, `list` (recursive), `delete`.
|
|
30
|
+
- **Permission Helper**: Check for `MANAGE_EXTERNAL_STORAGE` status.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install expo-tiddlywiki-filesystem-android-external-storage
|
|
36
|
+
# or
|
|
37
|
+
pnpm add expo-tiddlywiki-filesystem-android-external-storage
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
### Android Manifest
|
|
43
|
+
|
|
44
|
+
This module requires the `MANAGE_EXTERNAL_STORAGE` permission to be effective for broad access.
|
|
45
|
+
|
|
46
|
+
Add this to your `app.json` / `app.config.ts` if you want Expo to add the permission to `AndroidManifest.xml` (though you might need a custom config plugin to add `R.attr.requestLegacyExternalStorage` or similar attributes if targeting Android 10).
|
|
47
|
+
|
|
48
|
+
Actually, this package is primarily the *native implementation*. You should ensure your app requests the permission at runtime (e.g. using `Intent` to open Settings).
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { ExternalStorage } from 'expo-tiddlywiki-filesystem-android-external-storage';
|
|
54
|
+
|
|
55
|
+
async function example() {
|
|
56
|
+
const path = '/sdcard/Documents/myfile.txt';
|
|
57
|
+
|
|
58
|
+
// Check existence
|
|
59
|
+
if (await ExternalStorage.exists(path)) {
|
|
60
|
+
console.log('File exists');
|
|
61
|
+
const content = await ExternalStorage.readFileUtf8(path);
|
|
62
|
+
} else {
|
|
63
|
+
// Write file
|
|
64
|
+
await ExternalStorage.writeFileUtf8(path, 'Hello World');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// List directory
|
|
68
|
+
const files = await ExternalStorage.readDir('/sdcard/Documents');
|
|
69
|
+
console.log('Files:', files);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Expo Config Plugin
|
|
74
|
+
|
|
75
|
+
This package includes a config plugin to automatically add the `MANAGE_EXTERNAL_STORAGE` permission to your `AndroidManifest.xml`.
|
|
76
|
+
|
|
77
|
+
In `app.json` or `app.config.ts`:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"expo": {
|
|
82
|
+
"plugins": [
|
|
83
|
+
"expo-filesystem-android-external-storage"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## API
|
|
90
|
+
|
|
91
|
+
### `exists(path: string): Promise<boolean>`
|
|
92
|
+
Checks if a file or directory exists.
|
|
93
|
+
|
|
94
|
+
### `getInfo(path: string): Promise<FileInfo>`
|
|
95
|
+
Gets metadata (size, modification time, isDirectory).
|
|
96
|
+
|
|
97
|
+
### `readFileUtf8(path: string): Promise<string>`
|
|
98
|
+
Reads a file as a UTF-8 string.
|
|
99
|
+
|
|
100
|
+
### `writeFileUtf8(path: string, content: string): Promise<void>`
|
|
101
|
+
Writes a UTF-8 string to a file. Creates parent directories if needed.
|
|
102
|
+
|
|
103
|
+
### `readDir(path: string): Promise<string[]>`
|
|
104
|
+
Lists files in a directory (non-recursive).
|
|
105
|
+
|
|
106
|
+
### `readDirRecursive(path: string): Promise<string[]>`
|
|
107
|
+
Recursively lists all files, returning paths relative to the root. Skips `.git`, `node_modules`, etc.
|
|
108
|
+
|
|
109
|
+
### `mkdir(path: string): Promise<void>`
|
|
110
|
+
Creates a directory and necessary parent directories.
|
|
111
|
+
|
|
112
|
+
### `deleteFile(path: string): Promise<void>`
|
|
113
|
+
Deletes a file.
|
|
114
|
+
|
|
115
|
+
### `rmdir(path: string): Promise<void>`
|
|
116
|
+
Deletes a directory recursively.
|
|
117
|
+
|
|
118
|
+
### `isExternalStorageManager(): Promise<boolean>`
|
|
119
|
+
Checks if the `MANAGE_EXTERNAL_STORAGE` permission is granted (Android 11+).
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id 'com.android.library'
|
|
3
|
+
id 'expo-module-gradle-plugin'
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
group = 'expo.modules.externalstorage'
|
|
7
|
+
version = '0.1.0'
|
|
8
|
+
|
|
9
|
+
android {
|
|
10
|
+
namespace "expo.modules.externalstorage"
|
|
11
|
+
defaultConfig {
|
|
12
|
+
versionCode 1
|
|
13
|
+
versionName '0.1.0'
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
dependencies {
|
|
18
|
+
implementation "com.squareup.okhttp3:okhttp:4.12.0"
|
|
19
|
+
}
|