@simplysm/capacitor-plugin-file-system 13.0.100 → 14.0.4
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 +92 -56
- package/android/build.gradle +1 -0
- package/android/src/main/kotlin/kr/co/simplysm/capacitor/filesystem/FileSystemPlugin.kt +306 -0
- package/android/src/main/kotlin/kr/co/simplysm/capacitor/filesystem/FileSystemProvider.kt +5 -0
- package/dist/FileSystem.d.ts +24 -24
- package/dist/FileSystem.js +103 -97
- package/dist/FileSystem.js.map +1 -6
- package/dist/FileSystemPlugin.js +2 -1
- package/dist/FileSystemPlugin.js.map +1 -6
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -6
- package/dist/web/FileSystemWeb.d.ts +3 -3
- package/dist/web/FileSystemWeb.js +64 -64
- package/dist/web/FileSystemWeb.js.map +1 -6
- package/dist/web/VirtualFileSystem.d.ts +6 -6
- package/dist/web/VirtualFileSystem.js +33 -36
- package/dist/web/VirtualFileSystem.js.map +1 -6
- package/package.json +7 -7
- package/src/FileSystem.ts +25 -25
- package/src/index.ts +1 -1
- package/src/web/FileSystemWeb.ts +7 -7
- package/src/web/VirtualFileSystem.ts +6 -6
- package/android/src/main/java/kr/co/simplysm/capacitor/filesystem/FileSystemPlugin.java +0 -305
- package/android/src/main/java/kr/co/simplysm/capacitor/filesystem/FileSystemProvider.java +0 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @simplysm/capacitor-plugin-file-system
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Capacitor file system plugin with full storage access on Android 11+.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -14,85 +14,121 @@ npm install @simplysm/capacitor-plugin-file-system
|
|
|
14
14
|
|
|
15
15
|
| API | Type | Description |
|
|
16
16
|
|-----|------|-------------|
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
###
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
type StorageType =
|
|
28
|
-
| "external" // External storage root (Environment.getExternalStorageDirectory)
|
|
29
|
-
| "externalFiles" // App-specific external files directory
|
|
30
|
-
| "externalCache" // App-specific external cache directory
|
|
31
|
-
| "externalMedia" // App-specific external media directory
|
|
32
|
-
| "appData" // App data directory
|
|
33
|
-
| "appFiles" // App files directory
|
|
34
|
-
| "appCache"; // App cache directory
|
|
17
|
+
| `StorageType` | Type | Union of supported Android storage location identifiers |
|
|
18
|
+
| `FileInfo` | Interface | File entry metadata returned by directory listing |
|
|
19
|
+
| `FileSystemPlugin` | Interface | Native plugin interface for file system operations |
|
|
20
|
+
| `FileSystem` | Class | Static API for file system access with permission management |
|
|
21
|
+
|
|
22
|
+
## Types
|
|
23
|
+
|
|
24
|
+
### StorageType
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
type StorageType = "external" | "externalFiles" | "externalCache" | "externalMedia" | "appData" | "appFiles" | "appCache";
|
|
35
28
|
```
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
| Value | Description |
|
|
31
|
+
|-------|-------------|
|
|
32
|
+
| `"external"` | Shared external storage root |
|
|
33
|
+
| `"externalFiles"` | App-specific external files directory |
|
|
34
|
+
| `"externalCache"` | App-specific external cache directory |
|
|
35
|
+
| `"externalMedia"` | App-specific external media directory |
|
|
36
|
+
| `"appData"` | Internal app data directory |
|
|
37
|
+
| `"appFiles"` | Internal app files directory |
|
|
38
|
+
| `"appCache"` | Internal app cache directory |
|
|
39
|
+
|
|
40
|
+
## Interfaces
|
|
41
|
+
|
|
42
|
+
### FileInfo
|
|
43
|
+
|
|
44
|
+
Metadata for a single file or directory entry.
|
|
38
45
|
|
|
39
46
|
| Field | Type | Description |
|
|
40
47
|
|-------|------|-------------|
|
|
41
|
-
| `name` | `string` |
|
|
42
|
-
| `isDirectory` | `boolean` |
|
|
48
|
+
| `name` | `string` | Name of the file or directory |
|
|
49
|
+
| `isDirectory` | `boolean` | `true` if the entry is a directory |
|
|
43
50
|
|
|
44
|
-
###
|
|
51
|
+
### FileSystemPlugin
|
|
52
|
+
|
|
53
|
+
Native plugin interface for file system operations.
|
|
45
54
|
|
|
46
55
|
| Method | Signature | Description |
|
|
47
56
|
|--------|-----------|-------------|
|
|
48
|
-
| `checkPermissions` | `() => Promise<{ granted: boolean }>` | Check
|
|
49
|
-
| `requestPermissions` | `() => Promise<void>` | Request
|
|
50
|
-
| `readdir` | `(options: { path: string }) => Promise<{ files: FileInfo[] }>` |
|
|
51
|
-
| `getStoragePath` | `(options: { type: StorageType }) => Promise<{ path: string }>` | Get
|
|
52
|
-
| `getUri` | `(options: { path: string }) => Promise<{ uri: string }>` | Get FileProvider URI |
|
|
53
|
-
| `writeFile` | `(options: { path: string; data: string; encoding?: "utf8" \| "base64" }) => Promise<void>` | Write file |
|
|
54
|
-
| `readFile` | `(options: { path: string; encoding?: "utf8" \| "base64" }) => Promise<{ data: string }>` | Read file |
|
|
55
|
-
| `remove` | `(options: { path: string }) => Promise<void>` |
|
|
56
|
-
| `mkdir` | `(options: { path: string }) => Promise<void>` | Create directory |
|
|
57
|
-
| `exists` | `(options: { path: string }) => Promise<{ exists: boolean }>` | Check
|
|
57
|
+
| `checkPermissions` | `() => Promise<{ granted: boolean }>` | Check if storage permissions are granted |
|
|
58
|
+
| `requestPermissions` | `() => Promise<void>` | Request storage permissions |
|
|
59
|
+
| `readdir` | `(options: { path: string }) => Promise<{ files: FileInfo[] }>` | List files in a directory |
|
|
60
|
+
| `getStoragePath` | `(options: { type: StorageType }) => Promise<{ path: string }>` | Get the absolute path for a storage type |
|
|
61
|
+
| `getUri` | `(options: { path: string }) => Promise<{ uri: string }>` | Get a FileProvider content URI for a file path |
|
|
62
|
+
| `writeFile` | `(options: { path: string; data: string; encoding?: "utf8" \| "base64" }) => Promise<void>` | Write data to a file |
|
|
63
|
+
| `readFile` | `(options: { path: string; encoding?: "utf8" \| "base64" }) => Promise<{ data: string }>` | Read data from a file |
|
|
64
|
+
| `remove` | `(options: { path: string }) => Promise<void>` | Remove a file or directory |
|
|
65
|
+
| `mkdir` | `(options: { path: string }) => Promise<void>` | Create a directory |
|
|
66
|
+
| `exists` | `(options: { path: string }) => Promise<{ exists: boolean }>` | Check if a path exists |
|
|
67
|
+
|
|
68
|
+
## Classes
|
|
69
|
+
|
|
70
|
+
### FileSystem
|
|
58
71
|
|
|
59
|
-
|
|
72
|
+
File system access plugin. On Android 11+ it uses `MANAGE_EXTERNAL_STORAGE`. On Android 10 and below it uses `READ_EXTERNAL_STORAGE` / `WRITE_EXTERNAL_STORAGE`. On the browser it falls back to IndexedDB emulation.
|
|
60
73
|
|
|
61
|
-
|
|
74
|
+
All methods are static.
|
|
62
75
|
|
|
63
76
|
| Method | Signature | Description |
|
|
64
77
|
|--------|-----------|-------------|
|
|
65
|
-
| `checkPermissions` | `()
|
|
66
|
-
| `requestPermissions` | `()
|
|
67
|
-
| `readdir` | `(dirPath: string)
|
|
68
|
-
| `getStoragePath` | `(type: StorageType)
|
|
69
|
-
| `getUri` | `(filePath: string)
|
|
70
|
-
| `writeFile` | `(filePath: string, data: string \| Bytes)
|
|
71
|
-
| `readFile` | `(filePath: string)
|
|
72
|
-
| `readFile` | `(filePath: string, encoding: "utf8")
|
|
73
|
-
| `remove` | `(targetPath: string)
|
|
74
|
-
| `mkdir` | `(targetPath: string)
|
|
75
|
-
| `exists` | `(targetPath: string)
|
|
78
|
+
| `checkPermissions` | `static async checkPermissions(): Promise<boolean>` | Check whether storage permissions are granted |
|
|
79
|
+
| `requestPermissions` | `static async requestPermissions(): Promise<void>` | Request storage permissions from the user |
|
|
80
|
+
| `readdir` | `static async readdir(dirPath: string): Promise<FileInfo[]>` | List files and directories at the given path |
|
|
81
|
+
| `getStoragePath` | `static async getStoragePath(type: StorageType): Promise<string>` | Get the absolute path for a storage type (`external`, `externalFiles`, `externalCache`, `externalMedia`, `appData`, `appFiles`, `appCache`) |
|
|
82
|
+
| `getUri` | `static async getUri(filePath: string): Promise<string>` | Get a FileProvider content URI for the given file path |
|
|
83
|
+
| `writeFile` | `static async writeFile(filePath: string, data: string \| Bytes): Promise<void>` | Write string or binary data to a file. Binary data (`Bytes`) is automatically base64-encoded. |
|
|
84
|
+
| `readFile` | `static async readFile(filePath: string): Promise<Bytes>` | Read a file as binary data |
|
|
85
|
+
| `readFile` (overload) | `static async readFile(filePath: string, encoding: "utf8"): Promise<string>` | Read a file as a UTF-8 string |
|
|
86
|
+
| `remove` | `static async remove(targetPath: string): Promise<void>` | Recursively delete a file or directory |
|
|
87
|
+
| `mkdir` | `static async mkdir(targetPath: string): Promise<void>` | Recursively create a directory and all parent directories |
|
|
88
|
+
| `exists` | `static async exists(targetPath: string): Promise<boolean>` | Check whether a file or directory exists at the given path |
|
|
76
89
|
|
|
77
90
|
## Usage Examples
|
|
78
91
|
|
|
79
92
|
### Read and write files
|
|
80
93
|
|
|
81
|
-
```
|
|
94
|
+
```ts
|
|
82
95
|
import { FileSystem } from "@simplysm/capacitor-plugin-file-system";
|
|
83
96
|
|
|
84
|
-
//
|
|
85
|
-
|
|
97
|
+
// Ensure permissions
|
|
98
|
+
const granted = await FileSystem.checkPermissions();
|
|
99
|
+
if (!granted) {
|
|
86
100
|
await FileSystem.requestPermissions();
|
|
87
101
|
}
|
|
88
102
|
|
|
89
|
-
// Get
|
|
90
|
-
const
|
|
91
|
-
|
|
103
|
+
// Get external files directory
|
|
104
|
+
const basePath = await FileSystem.getStoragePath("externalFiles");
|
|
105
|
+
|
|
106
|
+
// Write a text file
|
|
107
|
+
await FileSystem.writeFile(`${basePath}/config.json`, '{"key": "value"}');
|
|
108
|
+
|
|
109
|
+
// Read it back as a string
|
|
110
|
+
const content = await FileSystem.readFile(`${basePath}/config.json`, "utf8");
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### List directory contents
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { FileSystem } from "@simplysm/capacitor-plugin-file-system";
|
|
117
|
+
|
|
118
|
+
const files = await FileSystem.readdir("/storage/emulated/0/Download");
|
|
119
|
+
for (const file of files) {
|
|
120
|
+
console.log(`${file.name} (${file.isDirectory ? "dir" : "file"})`);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Create directories and check existence
|
|
92
125
|
|
|
93
|
-
|
|
94
|
-
|
|
126
|
+
```ts
|
|
127
|
+
import { FileSystem } from "@simplysm/capacitor-plugin-file-system";
|
|
95
128
|
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
const dirPath = "/storage/emulated/0/MyApp/data/logs";
|
|
130
|
+
|
|
131
|
+
if (!(await FileSystem.exists(dirPath))) {
|
|
132
|
+
await FileSystem.mkdir(dirPath);
|
|
133
|
+
}
|
|
98
134
|
```
|
package/android/build.gradle
CHANGED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
package kr.co.simplysm.capacitor.filesystem
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.content.pm.PackageManager
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.os.Environment
|
|
9
|
+
import android.provider.Settings
|
|
10
|
+
import android.util.Base64
|
|
11
|
+
import android.util.Log
|
|
12
|
+
import androidx.core.app.ActivityCompat
|
|
13
|
+
import androidx.core.content.ContextCompat
|
|
14
|
+
import androidx.core.content.FileProvider
|
|
15
|
+
import com.getcapacitor.JSArray
|
|
16
|
+
import com.getcapacitor.JSObject
|
|
17
|
+
import com.getcapacitor.Plugin
|
|
18
|
+
import com.getcapacitor.PluginCall
|
|
19
|
+
import com.getcapacitor.PluginMethod
|
|
20
|
+
import com.getcapacitor.annotation.CapacitorPlugin
|
|
21
|
+
import java.io.BufferedInputStream
|
|
22
|
+
import java.io.BufferedOutputStream
|
|
23
|
+
import java.io.ByteArrayOutputStream
|
|
24
|
+
import java.io.File
|
|
25
|
+
import java.io.FileInputStream
|
|
26
|
+
import java.io.FileOutputStream
|
|
27
|
+
import java.nio.charset.StandardCharsets
|
|
28
|
+
|
|
29
|
+
@CapacitorPlugin(name = "FileSystem")
|
|
30
|
+
class FileSystemPlugin : Plugin() {
|
|
31
|
+
|
|
32
|
+
companion object {
|
|
33
|
+
private const val TAG = "FileSystemPlugin"
|
|
34
|
+
private const val PERMISSION_REQUEST_CODE = 1001
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@PluginMethod
|
|
38
|
+
fun checkPermissions(call: PluginCall) {
|
|
39
|
+
val granted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
40
|
+
Environment.isExternalStorageManager()
|
|
41
|
+
} else {
|
|
42
|
+
val ctx = context
|
|
43
|
+
ContextCompat.checkSelfPermission(ctx, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
|
|
44
|
+
&& ContextCompat.checkSelfPermission(ctx, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
|
|
45
|
+
}
|
|
46
|
+
val ret = JSObject()
|
|
47
|
+
ret.put("granted", granted)
|
|
48
|
+
call.resolve(ret)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@PluginMethod
|
|
52
|
+
fun requestPermissions(call: PluginCall) {
|
|
53
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
54
|
+
if (!Environment.isExternalStorageManager()) {
|
|
55
|
+
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
|
56
|
+
intent.data = Uri.parse("package:" + context.packageName)
|
|
57
|
+
activity.startActivity(intent)
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
val readGranted = ContextCompat.checkSelfPermission(
|
|
61
|
+
context,
|
|
62
|
+
Manifest.permission.READ_EXTERNAL_STORAGE
|
|
63
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
64
|
+
val writeGranted = ContextCompat.checkSelfPermission(
|
|
65
|
+
context,
|
|
66
|
+
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
67
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
68
|
+
|
|
69
|
+
if (!readGranted || !writeGranted) {
|
|
70
|
+
ActivityCompat.requestPermissions(
|
|
71
|
+
activity,
|
|
72
|
+
arrayOf(
|
|
73
|
+
Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
74
|
+
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
75
|
+
),
|
|
76
|
+
PERMISSION_REQUEST_CODE
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
call.resolve()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@PluginMethod
|
|
84
|
+
fun readdir(call: PluginCall) {
|
|
85
|
+
val path = call.getString("path")
|
|
86
|
+
if (path == null) {
|
|
87
|
+
call.reject("path is required")
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
val dir = File(path)
|
|
92
|
+
if (!dir.exists() || !dir.isDirectory) {
|
|
93
|
+
call.reject("Directory does not exist")
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
val files = dir.listFiles()
|
|
98
|
+
if (files == null) {
|
|
99
|
+
call.reject("Cannot read directory")
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
val result = JSArray()
|
|
104
|
+
for (f in files) {
|
|
105
|
+
val info = JSObject()
|
|
106
|
+
info.put("name", f.name)
|
|
107
|
+
info.put("isDirectory", f.isDirectory)
|
|
108
|
+
result.put(info)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
val ret = JSObject()
|
|
112
|
+
ret.put("files", result)
|
|
113
|
+
call.resolve(ret)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@PluginMethod
|
|
117
|
+
fun getStoragePath(call: PluginCall) {
|
|
118
|
+
val type = call.getString("type")
|
|
119
|
+
if (type == null) {
|
|
120
|
+
call.reject("type is required")
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
val ctx = context
|
|
125
|
+
val path: File? = when (type) {
|
|
126
|
+
"external" -> Environment.getExternalStorageDirectory()
|
|
127
|
+
"externalFiles" -> ctx.getExternalFilesDir(null)
|
|
128
|
+
"externalCache" -> ctx.externalCacheDir
|
|
129
|
+
"externalMedia" -> {
|
|
130
|
+
val dirs = ctx.externalMediaDirs
|
|
131
|
+
if (dirs.isNotEmpty()) dirs[0] else null
|
|
132
|
+
}
|
|
133
|
+
"appData" -> File(ctx.applicationInfo.dataDir)
|
|
134
|
+
"appFiles" -> ctx.filesDir
|
|
135
|
+
"appCache" -> ctx.cacheDir
|
|
136
|
+
else -> {
|
|
137
|
+
call.reject("Unknown type: $type")
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (path == null) {
|
|
143
|
+
call.reject("Path not available")
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
val ret = JSObject()
|
|
148
|
+
ret.put("path", path.absolutePath)
|
|
149
|
+
call.resolve(ret)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@PluginMethod
|
|
153
|
+
fun getUri(call: PluginCall) {
|
|
154
|
+
val path = call.getString("path")
|
|
155
|
+
if (path == null) {
|
|
156
|
+
call.reject("path is required")
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
val authority = context.packageName + ".filesystem.provider"
|
|
162
|
+
val uri = FileProvider.getUriForFile(context, authority, File(path))
|
|
163
|
+
val ret = JSObject()
|
|
164
|
+
ret.put("uri", uri.toString())
|
|
165
|
+
call.resolve(ret)
|
|
166
|
+
} catch (e: Exception) {
|
|
167
|
+
Log.e(TAG, "getUri failed", e)
|
|
168
|
+
call.reject("getUri failed: " + e.message)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@PluginMethod
|
|
173
|
+
fun writeFile(call: PluginCall) {
|
|
174
|
+
val path = call.getString("path")
|
|
175
|
+
val data = call.getString("data")
|
|
176
|
+
val encoding = call.getString("encoding", "utf8")
|
|
177
|
+
|
|
178
|
+
if (path == null || data == null) {
|
|
179
|
+
call.reject("path and data are required")
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
val file = File(path)
|
|
185
|
+
val parent = file.parentFile
|
|
186
|
+
if (parent != null && !parent.exists()) {
|
|
187
|
+
parent.mkdirs()
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
val bytes = if ("base64" == encoding) {
|
|
191
|
+
Base64.decode(data, Base64.DEFAULT)
|
|
192
|
+
} else {
|
|
193
|
+
data.toByteArray(StandardCharsets.UTF_8)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
BufferedOutputStream(FileOutputStream(file)).use { bos ->
|
|
197
|
+
bos.write(bytes)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
call.resolve()
|
|
201
|
+
} catch (e: Exception) {
|
|
202
|
+
Log.e(TAG, "writeFile failed", e)
|
|
203
|
+
call.reject("Write failed: " + e.message)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@PluginMethod
|
|
208
|
+
fun readFile(call: PluginCall) {
|
|
209
|
+
val path = call.getString("path")
|
|
210
|
+
val encoding = call.getString("encoding", "utf8")
|
|
211
|
+
|
|
212
|
+
if (path == null) {
|
|
213
|
+
call.reject("path is required")
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
val file = File(path)
|
|
218
|
+
if (!file.exists()) {
|
|
219
|
+
call.reject("File not found: $path")
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
BufferedInputStream(FileInputStream(file)).use { bis ->
|
|
225
|
+
ByteArrayOutputStream().use { baos ->
|
|
226
|
+
val buf = ByteArray(8192)
|
|
227
|
+
var len: Int
|
|
228
|
+
while (bis.read(buf).also { len = it } != -1) {
|
|
229
|
+
baos.write(buf, 0, len)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
val result = if ("base64" == encoding) {
|
|
233
|
+
Base64.encodeToString(baos.toByteArray(), Base64.NO_WRAP)
|
|
234
|
+
} else {
|
|
235
|
+
baos.toString("UTF-8")
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
val ret = JSObject()
|
|
239
|
+
ret.put("data", result)
|
|
240
|
+
call.resolve(ret)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} catch (e: Exception) {
|
|
244
|
+
Log.e(TAG, "readFile failed", e)
|
|
245
|
+
call.reject("Read failed: " + e.message)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@PluginMethod
|
|
250
|
+
fun remove(call: PluginCall) {
|
|
251
|
+
val path = call.getString("path")
|
|
252
|
+
if (path == null) {
|
|
253
|
+
call.reject("path is required")
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (deleteRecursively(File(path))) {
|
|
258
|
+
call.resolve()
|
|
259
|
+
} else {
|
|
260
|
+
call.reject("Delete failed")
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@PluginMethod
|
|
265
|
+
fun mkdir(call: PluginCall) {
|
|
266
|
+
val path = call.getString("path")
|
|
267
|
+
if (path == null) {
|
|
268
|
+
call.reject("path is required")
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
val dir = File(path)
|
|
273
|
+
if (dir.exists() || dir.mkdirs()) {
|
|
274
|
+
call.resolve()
|
|
275
|
+
} else {
|
|
276
|
+
call.reject("Failed to create directory")
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
@PluginMethod
|
|
281
|
+
fun exists(call: PluginCall) {
|
|
282
|
+
val path = call.getString("path")
|
|
283
|
+
if (path == null) {
|
|
284
|
+
call.reject("path is required")
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
val ret = JSObject()
|
|
289
|
+
ret.put("exists", File(path).exists())
|
|
290
|
+
call.resolve(ret)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
private fun deleteRecursively(file: File): Boolean {
|
|
294
|
+
if (file.isDirectory) {
|
|
295
|
+
val children = file.listFiles()
|
|
296
|
+
if (children != null) {
|
|
297
|
+
for (child in children) {
|
|
298
|
+
if (!deleteRecursively(child)) {
|
|
299
|
+
return false
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return file.delete()
|
|
305
|
+
}
|
|
306
|
+
}
|
package/dist/FileSystem.d.ts
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
1
|
import type { FileInfo, StorageType } from "./FileSystemPlugin";
|
|
2
2
|
import type { Bytes } from "@simplysm/core-common";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* - Android 11+:
|
|
6
|
-
* - Android 10-: READ/WRITE_EXTERNAL_STORAGE
|
|
7
|
-
* - Browser: IndexedDB
|
|
4
|
+
* 파일 시스템 접근 플러그인
|
|
5
|
+
* - Android 11+: MANAGE_EXTERNAL_STORAGE 권한을 통한 전체 파일 시스템 접근
|
|
6
|
+
* - Android 10-: READ/WRITE_EXTERNAL_STORAGE 권한
|
|
7
|
+
* - Browser: IndexedDB 기반 에뮬레이션
|
|
8
8
|
*/
|
|
9
9
|
export declare abstract class FileSystem {
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* 권한 확인
|
|
12
12
|
*/
|
|
13
13
|
static checkPermissions(): Promise<boolean>;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* - Android 11+:
|
|
17
|
-
* - Android 10-:
|
|
15
|
+
* 권한 요청
|
|
16
|
+
* - Android 11+: 설정 화면으로 이동
|
|
17
|
+
* - Android 10-: 권한 대화상자 표시
|
|
18
18
|
*/
|
|
19
19
|
static requestPermissions(): Promise<void>;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* 디렉토리 읽기
|
|
22
22
|
*/
|
|
23
23
|
static readdir(dirPath: string): Promise<FileInfo[]>;
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
* @param type
|
|
27
|
-
* - external:
|
|
28
|
-
* - externalFiles:
|
|
29
|
-
* - externalCache:
|
|
30
|
-
* - externalMedia:
|
|
31
|
-
* - appData:
|
|
32
|
-
* - appFiles:
|
|
33
|
-
* - appCache:
|
|
25
|
+
* 저장소 경로 조회
|
|
26
|
+
* @param type 저장소 유형
|
|
27
|
+
* - external: 외부 저장소 루트 (Environment.getExternalStorageDirectory)
|
|
28
|
+
* - externalFiles: 앱 전용 외부 파일 디렉토리
|
|
29
|
+
* - externalCache: 앱 전용 외부 캐시 디렉토리
|
|
30
|
+
* - externalMedia: 앱 전용 외부 미디어 디렉토리
|
|
31
|
+
* - appData: 앱 데이터 디렉토리
|
|
32
|
+
* - appFiles: 앱 파일 디렉토리
|
|
33
|
+
* - appCache: 앱 캐시 디렉토리
|
|
34
34
|
*/
|
|
35
35
|
static getStoragePath(type: StorageType): Promise<string>;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* 파일 URI 조회 (FileProvider)
|
|
38
38
|
*/
|
|
39
39
|
static getUri(filePath: string): Promise<string>;
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* 파일 쓰기
|
|
42
42
|
*/
|
|
43
43
|
static writeFile(filePath: string, data: string | Bytes): Promise<void>;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* 파일 읽기 (기본: Bytes, encoding "utf8" 지정 시: string)
|
|
46
46
|
*/
|
|
47
47
|
static readFile(filePath: string): Promise<Bytes>;
|
|
48
48
|
static readFile(filePath: string, encoding: "utf8"): Promise<string>;
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* 파일/디렉토리 삭제 (재귀)
|
|
51
51
|
*/
|
|
52
52
|
static remove(targetPath: string): Promise<void>;
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* 디렉토리 생성 (재귀)
|
|
55
55
|
*/
|
|
56
56
|
static mkdir(targetPath: string): Promise<void>;
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
58
|
+
* 존재 여부 확인
|
|
59
59
|
*/
|
|
60
60
|
static exists(targetPath: string): Promise<boolean>;
|
|
61
61
|
}
|