@simplysm/capacitor-plugin-usb-storage 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 +73 -43
- package/android/build.gradle +1 -0
- package/android/src/main/java/kr/co/simplysm/capacitor/usbstorage/UsbStoragePlugin.kt +269 -0
- package/dist/UsbStorage.d.ts +19 -19
- package/dist/UsbStorage.js +59 -57
- package/dist/UsbStorage.js.map +1 -6
- package/dist/UsbStoragePlugin.js +2 -1
- package/dist/UsbStoragePlugin.js.map +1 -6
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -6
- package/dist/web/UsbStorageWeb.d.ts +3 -3
- package/dist/web/UsbStorageWeb.js +72 -75
- package/dist/web/UsbStorageWeb.js.map +1 -6
- package/dist/web/VirtualUsbStorage.js +36 -39
- package/dist/web/VirtualUsbStorage.js.map +1 -6
- package/package.json +8 -8
- package/src/UsbStorage.ts +19 -19
- package/src/index.ts +1 -1
- package/src/web/UsbStorageWeb.ts +3 -3
- package/android/src/main/java/kr/co/simplysm/capacitor/usbstorage/UsbStoragePlugin.java +0 -278
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @simplysm/capacitor-plugin-usb-storage
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Capacitor USB mass storage plugin using the libaums library on Android.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -14,82 +14,112 @@ npm install @simplysm/capacitor-plugin-usb-storage
|
|
|
14
14
|
|
|
15
15
|
| API | Type | Description |
|
|
16
16
|
|-----|------|-------------|
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
17
|
+
| `UsbDeviceInfo` | Interface | Metadata about a connected USB mass storage device |
|
|
18
|
+
| `UsbDeviceFilter` | Interface | Vendor/product ID pair used to target a specific USB device |
|
|
19
|
+
| `UsbFileInfo` | Interface | File entry metadata from a USB storage directory listing |
|
|
20
|
+
| `UsbStoragePlugin` | Interface | Native plugin interface for USB storage operations |
|
|
21
|
+
| `UsbStorage` | Class | Static API for USB mass storage access |
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
## Interfaces
|
|
24
24
|
|
|
25
|
-
###
|
|
25
|
+
### UsbDeviceInfo
|
|
26
|
+
|
|
27
|
+
Metadata about a connected USB mass storage device.
|
|
26
28
|
|
|
27
29
|
| Field | Type | Description |
|
|
28
30
|
|-------|------|-------------|
|
|
29
|
-
| `deviceName` | `string` |
|
|
30
|
-
| `manufacturerName` | `string` |
|
|
31
|
-
| `productName` | `string` |
|
|
31
|
+
| `deviceName` | `string` | System-assigned device name |
|
|
32
|
+
| `manufacturerName` | `string` | USB device manufacturer name |
|
|
33
|
+
| `productName` | `string` | USB device product name |
|
|
32
34
|
| `vendorId` | `number` | USB vendor ID |
|
|
33
35
|
| `productId` | `number` | USB product ID |
|
|
34
36
|
|
|
35
|
-
###
|
|
37
|
+
### UsbDeviceFilter
|
|
38
|
+
|
|
39
|
+
Identifies a specific USB device by its vendor and product IDs. Used as a parameter for all device-specific operations.
|
|
36
40
|
|
|
37
41
|
| Field | Type | Description |
|
|
38
42
|
|-------|------|-------------|
|
|
39
|
-
| `vendorId` | `number` | USB vendor ID |
|
|
40
|
-
| `productId` | `number` | USB product ID |
|
|
43
|
+
| `vendorId` | `number` | USB vendor ID of the target device |
|
|
44
|
+
| `productId` | `number` | USB product ID of the target device |
|
|
41
45
|
|
|
42
|
-
###
|
|
46
|
+
### UsbFileInfo
|
|
47
|
+
|
|
48
|
+
Metadata for a single file or directory entry on a USB storage device.
|
|
43
49
|
|
|
44
50
|
| Field | Type | Description |
|
|
45
51
|
|-------|------|-------------|
|
|
46
|
-
| `name` | `string` |
|
|
47
|
-
| `isDirectory` | `boolean` |
|
|
52
|
+
| `name` | `string` | Name of the file or directory |
|
|
53
|
+
| `isDirectory` | `boolean` | `true` if the entry is a directory |
|
|
54
|
+
|
|
55
|
+
### UsbStoragePlugin
|
|
48
56
|
|
|
49
|
-
|
|
57
|
+
Native plugin interface for USB storage operations.
|
|
50
58
|
|
|
51
59
|
| Method | Signature | Description |
|
|
52
60
|
|--------|-----------|-------------|
|
|
53
|
-
| `getDevices` | `() => Promise<{ devices: UsbDeviceInfo[] }>` |
|
|
54
|
-
| `requestPermissions` | `(options: UsbDeviceFilter) => Promise<{ granted: boolean }>` | Request USB device
|
|
55
|
-
| `checkPermissions` | `(options: UsbDeviceFilter) => Promise<{ granted: boolean }>` | Check USB device
|
|
56
|
-
| `readdir` | `(options: UsbDeviceFilter & { path: string }) => Promise<{ files: UsbFileInfo[] }>` |
|
|
57
|
-
| `readFile` | `(options: UsbDeviceFilter & { path: string }) => Promise<{ data: string \| null }>` | Read file from USB
|
|
61
|
+
| `getDevices` | `() => Promise<{ devices: UsbDeviceInfo[] }>` | List all connected USB mass storage devices |
|
|
62
|
+
| `requestPermissions` | `(options: UsbDeviceFilter) => Promise<{ granted: boolean }>` | Request permission to access a specific USB device |
|
|
63
|
+
| `checkPermissions` | `(options: UsbDeviceFilter) => Promise<{ granted: boolean }>` | Check if permission is granted for a specific USB device |
|
|
64
|
+
| `readdir` | `(options: UsbDeviceFilter & { path: string }) => Promise<{ files: UsbFileInfo[] }>` | List files in a directory on the USB device |
|
|
65
|
+
| `readFile` | `(options: UsbDeviceFilter & { path: string }) => Promise<{ data: string \| null }>` | Read a file from the USB device as a base64 string |
|
|
66
|
+
|
|
67
|
+
## Classes
|
|
68
|
+
|
|
69
|
+
### UsbStorage
|
|
58
70
|
|
|
59
|
-
|
|
71
|
+
USB mass storage access plugin. On Android it uses the libaums library for direct USB communication. On the browser it falls back to IndexedDB-based virtual USB storage emulation.
|
|
60
72
|
|
|
61
|
-
|
|
73
|
+
All methods are static.
|
|
62
74
|
|
|
63
75
|
| Method | Signature | Description |
|
|
64
76
|
|--------|-----------|-------------|
|
|
65
|
-
| `getDevices` | `()
|
|
66
|
-
| `requestPermissions` | `(filter: UsbDeviceFilter)
|
|
67
|
-
| `checkPermissions` | `(filter: UsbDeviceFilter)
|
|
68
|
-
| `readdir` | `(filter: UsbDeviceFilter, dirPath: string)
|
|
69
|
-
| `readFile` | `(filter: UsbDeviceFilter, filePath: string)
|
|
77
|
+
| `getDevices` | `static async getDevices(): Promise<UsbDeviceInfo[]>` | List all connected USB mass storage devices |
|
|
78
|
+
| `requestPermissions` | `static async requestPermissions(filter: UsbDeviceFilter): Promise<boolean>` | Request permission to access the specified USB device. Returns `true` if granted. |
|
|
79
|
+
| `checkPermissions` | `static async checkPermissions(filter: UsbDeviceFilter): Promise<boolean>` | Check if permission is granted for the specified USB device |
|
|
80
|
+
| `readdir` | `static async readdir(filter: UsbDeviceFilter, dirPath: string): Promise<UsbFileInfo[]>` | List files and directories at the given path on the USB device |
|
|
81
|
+
| `readFile` | `static async readFile(filter: UsbDeviceFilter, filePath: string): Promise<Bytes \| undefined>` | Read a file from the USB device. Returns `Bytes` on success, `undefined` if the file does not exist or data is null. |
|
|
70
82
|
|
|
71
83
|
## Usage Examples
|
|
72
84
|
|
|
73
|
-
###
|
|
85
|
+
### Discover and access a USB device
|
|
74
86
|
|
|
75
|
-
```
|
|
87
|
+
```ts
|
|
76
88
|
import { UsbStorage } from "@simplysm/capacitor-plugin-usb-storage";
|
|
77
89
|
|
|
78
|
-
// List connected devices
|
|
90
|
+
// List connected USB devices
|
|
79
91
|
const devices = await UsbStorage.getDevices();
|
|
92
|
+
if (devices.length === 0) {
|
|
93
|
+
throw new Error("No USB storage device connected");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const device = devices[0];
|
|
97
|
+
const filter = { vendorId: device.vendorId, productId: device.productId };
|
|
98
|
+
|
|
99
|
+
// Request permission
|
|
100
|
+
const granted = await UsbStorage.requestPermissions(filter);
|
|
101
|
+
if (!granted) {
|
|
102
|
+
throw new Error("USB permission denied");
|
|
103
|
+
}
|
|
80
104
|
|
|
81
|
-
|
|
82
|
-
|
|
105
|
+
// List root directory
|
|
106
|
+
const files = await UsbStorage.readdir(filter, "/");
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
console.log(`${file.name} (${file.isDirectory ? "dir" : "file"})`);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
83
111
|
|
|
84
|
-
|
|
85
|
-
|
|
112
|
+
### Read a file from USB storage
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { UsbStorage } from "@simplysm/capacitor-plugin-usb-storage";
|
|
86
116
|
|
|
87
|
-
|
|
88
|
-
// Read directory
|
|
89
|
-
const files = await UsbStorage.readdir(filter, "/");
|
|
117
|
+
const filter = { vendorId: 0x1234, productId: 0x5678 };
|
|
90
118
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
119
|
+
const data = await UsbStorage.readFile(filter, "/data/export.csv");
|
|
120
|
+
if (data !== undefined) {
|
|
121
|
+
// Convert Bytes to string for text files
|
|
122
|
+
const text = new TextDecoder().decode(data);
|
|
123
|
+
processCSV(text);
|
|
94
124
|
}
|
|
95
125
|
```
|
package/android/build.gradle
CHANGED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
package kr.co.simplysm.capacitor.usbstorage
|
|
2
|
+
|
|
3
|
+
import android.app.PendingIntent
|
|
4
|
+
import android.content.BroadcastReceiver
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
7
|
+
import android.content.IntentFilter
|
|
8
|
+
import android.hardware.usb.UsbManager
|
|
9
|
+
import android.os.Build
|
|
10
|
+
import android.util.Base64
|
|
11
|
+
import android.util.Log
|
|
12
|
+
import com.getcapacitor.JSArray
|
|
13
|
+
import com.getcapacitor.JSObject
|
|
14
|
+
import com.getcapacitor.Plugin
|
|
15
|
+
import com.getcapacitor.PluginCall
|
|
16
|
+
import com.getcapacitor.PluginMethod
|
|
17
|
+
import com.getcapacitor.annotation.CapacitorPlugin
|
|
18
|
+
import me.jahnen.libaums.core.UsbMassStorageDevice
|
|
19
|
+
import me.jahnen.libaums.core.fs.UsbFileInputStream
|
|
20
|
+
import java.nio.ByteBuffer
|
|
21
|
+
|
|
22
|
+
@CapacitorPlugin(name = "UsbStorage")
|
|
23
|
+
class UsbStoragePlugin : Plugin() {
|
|
24
|
+
|
|
25
|
+
companion object {
|
|
26
|
+
private const val TAG = "UsbStoragePlugin"
|
|
27
|
+
private const val ACTION_USB_PERMISSION = "kr.co.simplysm.capacitor.usbstorage.USB_PERMISSION"
|
|
28
|
+
private const val MAX_FILE_SIZE = 100L * 1024 * 1024 // 100MB
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@PluginMethod
|
|
32
|
+
fun getDevices(call: PluginCall) {
|
|
33
|
+
try {
|
|
34
|
+
val devices = UsbMassStorageDevice.getMassStorageDevices(context)
|
|
35
|
+
|
|
36
|
+
val result = JSArray()
|
|
37
|
+
for (device in devices) {
|
|
38
|
+
val usbDevice = device.usbDevice
|
|
39
|
+
|
|
40
|
+
val deviceObj = JSObject()
|
|
41
|
+
deviceObj.put("deviceName", usbDevice.deviceName)
|
|
42
|
+
deviceObj.put("manufacturerName", usbDevice.manufacturerName)
|
|
43
|
+
deviceObj.put("productName", usbDevice.productName)
|
|
44
|
+
deviceObj.put("vendorId", usbDevice.vendorId)
|
|
45
|
+
deviceObj.put("productId", usbDevice.productId)
|
|
46
|
+
result.put(deviceObj)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
val ret = JSObject()
|
|
50
|
+
ret.put("devices", result)
|
|
51
|
+
call.resolve(ret)
|
|
52
|
+
} catch (e: Exception) {
|
|
53
|
+
Log.e(TAG, "getDevices failed", e)
|
|
54
|
+
call.reject("getDevices failed: ${e.message}")
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@PluginMethod
|
|
59
|
+
fun requestPermissions(call: PluginCall) {
|
|
60
|
+
val vendorId = call.getInt("vendorId")
|
|
61
|
+
val productId = call.getInt("productId")
|
|
62
|
+
|
|
63
|
+
if (vendorId == null || productId == null) {
|
|
64
|
+
call.reject("vendorId and productId are required")
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
val device = getDevice(vendorId, productId)
|
|
70
|
+
val usbDevice = device.usbDevice
|
|
71
|
+
|
|
72
|
+
val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
|
|
73
|
+
if (usbManager.hasPermission(usbDevice)) {
|
|
74
|
+
val ret = JSObject()
|
|
75
|
+
ret.put("granted", true)
|
|
76
|
+
call.resolve(ret)
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
val receiver = object : BroadcastReceiver() {
|
|
81
|
+
override fun onReceive(context: Context, intent: Intent) {
|
|
82
|
+
try {
|
|
83
|
+
context.unregisterReceiver(this)
|
|
84
|
+
val granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
|
|
85
|
+
val ret = JSObject()
|
|
86
|
+
ret.put("granted", granted)
|
|
87
|
+
call.resolve(ret)
|
|
88
|
+
} catch (e: Exception) {
|
|
89
|
+
Log.e(TAG, "requestPermission callback failed", e)
|
|
90
|
+
call.reject("requestPermission failed: ${e.message}")
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
val filter = IntentFilter(ACTION_USB_PERMISSION)
|
|
96
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
97
|
+
context.registerReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED)
|
|
98
|
+
} else {
|
|
99
|
+
context.registerReceiver(receiver, filter)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
103
|
+
PendingIntent.FLAG_MUTABLE
|
|
104
|
+
} else {
|
|
105
|
+
0
|
|
106
|
+
}
|
|
107
|
+
val permissionIntent = PendingIntent.getBroadcast(
|
|
108
|
+
context, 0, Intent(ACTION_USB_PERMISSION), flags
|
|
109
|
+
)
|
|
110
|
+
usbManager.requestPermission(usbDevice, permissionIntent)
|
|
111
|
+
} catch (e: Exception) {
|
|
112
|
+
Log.e(TAG, "requestPermission failed", e)
|
|
113
|
+
call.reject("requestPermission failed: ${e.message}")
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@PluginMethod
|
|
118
|
+
fun checkPermissions(call: PluginCall) {
|
|
119
|
+
val vendorId = call.getInt("vendorId")
|
|
120
|
+
val productId = call.getInt("productId")
|
|
121
|
+
|
|
122
|
+
if (vendorId == null || productId == null) {
|
|
123
|
+
call.reject("vendorId and productId are required")
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
val device = getDevice(vendorId, productId)
|
|
129
|
+
val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
|
|
130
|
+
val hasPermission = usbManager.hasPermission(device.usbDevice)
|
|
131
|
+
|
|
132
|
+
val ret = JSObject()
|
|
133
|
+
ret.put("granted", hasPermission)
|
|
134
|
+
call.resolve(ret)
|
|
135
|
+
} catch (e: Exception) {
|
|
136
|
+
Log.e(TAG, "hasPermission failed", e)
|
|
137
|
+
call.reject("hasPermission failed: ${e.message}")
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@PluginMethod
|
|
142
|
+
fun readdir(call: PluginCall) {
|
|
143
|
+
val vendorId = call.getInt("vendorId")
|
|
144
|
+
val productId = call.getInt("productId")
|
|
145
|
+
val path = call.getString("path")
|
|
146
|
+
|
|
147
|
+
if (vendorId == null || productId == null || path == null) {
|
|
148
|
+
call.reject("vendorId, productId, and path are required")
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
val device = getDevice(vendorId, productId)
|
|
154
|
+
|
|
155
|
+
val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
|
|
156
|
+
if (!usbManager.hasPermission(device.usbDevice)) {
|
|
157
|
+
call.reject("No permission for this USB device")
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
device.init()
|
|
162
|
+
try {
|
|
163
|
+
val fs = device.partitions[0].fileSystem
|
|
164
|
+
val root = fs.rootDirectory
|
|
165
|
+
val dir = root.search(path)
|
|
166
|
+
|
|
167
|
+
if (dir == null || !dir.isDirectory) {
|
|
168
|
+
call.reject("Directory not found: $path")
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
val files = dir.listFiles()
|
|
173
|
+
|
|
174
|
+
val result = JSArray()
|
|
175
|
+
for (file in files) {
|
|
176
|
+
val info = JSObject()
|
|
177
|
+
info.put("name", file.name)
|
|
178
|
+
info.put("isDirectory", file.isDirectory)
|
|
179
|
+
result.put(info)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
val ret = JSObject()
|
|
183
|
+
ret.put("files", result)
|
|
184
|
+
call.resolve(ret)
|
|
185
|
+
} finally {
|
|
186
|
+
device.close()
|
|
187
|
+
}
|
|
188
|
+
} catch (e: Exception) {
|
|
189
|
+
Log.e(TAG, "readdir failed", e)
|
|
190
|
+
call.reject("readdir failed: ${e.message}")
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@PluginMethod
|
|
195
|
+
fun readFile(call: PluginCall) {
|
|
196
|
+
val vendorId = call.getInt("vendorId")
|
|
197
|
+
val productId = call.getInt("productId")
|
|
198
|
+
val path = call.getString("path")
|
|
199
|
+
|
|
200
|
+
if (vendorId == null || productId == null || path == null) {
|
|
201
|
+
call.reject("vendorId, productId, and path are required")
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
val device = getDevice(vendorId, productId)
|
|
207
|
+
|
|
208
|
+
val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
|
|
209
|
+
if (!usbManager.hasPermission(device.usbDevice)) {
|
|
210
|
+
call.reject("No permission for this USB device")
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
device.init()
|
|
215
|
+
try {
|
|
216
|
+
val fs = device.partitions[0].fileSystem
|
|
217
|
+
val root = fs.rootDirectory
|
|
218
|
+
val usbFile = root.search(path)
|
|
219
|
+
|
|
220
|
+
if (usbFile == null) {
|
|
221
|
+
val ret = JSObject()
|
|
222
|
+
ret.put("data", null as String?)
|
|
223
|
+
call.resolve(ret)
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (usbFile.isDirectory) {
|
|
228
|
+
call.reject("Path is a directory: $path")
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
val fileLength = usbFile.length
|
|
233
|
+
if (fileLength > MAX_FILE_SIZE) {
|
|
234
|
+
call.reject("File too large: $fileLength bytes (max $MAX_FILE_SIZE)")
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
val buffer = ByteBuffer.allocate(fileLength.toInt())
|
|
238
|
+
|
|
239
|
+
val inputStream = UsbFileInputStream(usbFile)
|
|
240
|
+
val tmpBuf = ByteArray(fs.chunkSize)
|
|
241
|
+
var count: Int
|
|
242
|
+
while (inputStream.read(tmpBuf).also { count = it } != -1) {
|
|
243
|
+
buffer.put(tmpBuf, 0, count)
|
|
244
|
+
}
|
|
245
|
+
inputStream.close()
|
|
246
|
+
|
|
247
|
+
val base64Data = Base64.encodeToString(buffer.array(), Base64.NO_WRAP)
|
|
248
|
+
|
|
249
|
+
val ret = JSObject()
|
|
250
|
+
ret.put("data", base64Data)
|
|
251
|
+
call.resolve(ret)
|
|
252
|
+
} finally {
|
|
253
|
+
device.close()
|
|
254
|
+
}
|
|
255
|
+
} catch (e: Exception) {
|
|
256
|
+
Log.e(TAG, "readFile failed", e)
|
|
257
|
+
call.reject("readFile failed: ${e.message}")
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
@Throws(Exception::class)
|
|
262
|
+
private fun getDevice(vendorId: Int, productId: Int): UsbMassStorageDevice {
|
|
263
|
+
val devices = UsbMassStorageDevice.getMassStorageDevices(context)
|
|
264
|
+
return devices.firstOrNull { device ->
|
|
265
|
+
val usbDevice = device.usbDevice
|
|
266
|
+
usbDevice.vendorId == vendorId && usbDevice.productId == productId
|
|
267
|
+
} ?: throw Exception("USB device not found: vendorId=$vendorId, productId=$productId")
|
|
268
|
+
}
|
|
269
|
+
}
|
package/dist/UsbStorage.d.ts
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
import type { UsbDeviceFilter, UsbDeviceInfo, UsbFileInfo } from "./UsbStoragePlugin";
|
|
2
2
|
import type { Bytes } from "@simplysm/core-common";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* - Android: USB Mass Storage
|
|
6
|
-
* - Browser: IndexedDB
|
|
4
|
+
* USB 저장 장치 접근 플러그인
|
|
5
|
+
* - Android: libaums 라이브러리를 통한 USB Mass Storage 접근
|
|
6
|
+
* - Browser: IndexedDB 기반 가상 USB 저장소 에뮬레이션
|
|
7
7
|
*/
|
|
8
8
|
export declare abstract class UsbStorage {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @returns
|
|
10
|
+
* 연결된 USB 장치 목록 조회
|
|
11
|
+
* @returns 연결된 USB 장치 정보 배열
|
|
12
12
|
*/
|
|
13
13
|
static getDevices(): Promise<UsbDeviceInfo[]>;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* @param filter
|
|
17
|
-
* @returns
|
|
15
|
+
* USB 장치 접근 권한 요청
|
|
16
|
+
* @param filter 권한을 요청할 USB 장치의 vendorId 및 productId
|
|
17
|
+
* @returns 권한 승인 여부
|
|
18
18
|
*/
|
|
19
19
|
static requestPermissions(filter: UsbDeviceFilter): Promise<boolean>;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @param filter
|
|
23
|
-
* @returns
|
|
21
|
+
* USB 장치 접근 권한 확인
|
|
22
|
+
* @param filter 권한을 확인할 USB 장치의 vendorId 및 productId
|
|
23
|
+
* @returns 권한 보유 여부
|
|
24
24
|
*/
|
|
25
25
|
static checkPermissions(filter: UsbDeviceFilter): Promise<boolean>;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
* @param filter
|
|
29
|
-
* @param dirPath
|
|
30
|
-
* @returns
|
|
27
|
+
* USB 저장 장치에서 디렉토리 내용 읽기
|
|
28
|
+
* @param filter 대상 USB 장치의 vendorId 및 productId
|
|
29
|
+
* @param dirPath 읽을 디렉토리 경로
|
|
30
|
+
* @returns 디렉토리 내 파일/폴더 정보 배열
|
|
31
31
|
*/
|
|
32
32
|
static readdir(filter: UsbDeviceFilter, dirPath: string): Promise<UsbFileInfo[]>;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
* @param filter
|
|
36
|
-
* @param filePath
|
|
37
|
-
* @returns
|
|
34
|
+
* USB 저장 장치에서 파일 읽기
|
|
35
|
+
* @param filter 대상 USB 장치의 vendorId 및 productId
|
|
36
|
+
* @param filePath 읽을 파일 경로
|
|
37
|
+
* @returns 파일 데이터를 포함하는 Bytes, 또는 undefined
|
|
38
38
|
*/
|
|
39
39
|
static readFile(filter: UsbDeviceFilter, filePath: string): Promise<Bytes | undefined>;
|
|
40
40
|
}
|
package/dist/UsbStorage.js
CHANGED
|
@@ -1,63 +1,65 @@
|
|
|
1
1
|
import { registerPlugin } from "@capacitor/core";
|
|
2
2
|
import { bytes } from "@simplysm/core-common";
|
|
3
3
|
const usbStoragePlugin = registerPlugin("UsbStorage", {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
web: async () => {
|
|
5
|
+
const { UsbStorageWeb } = await import("./web/UsbStorageWeb.js");
|
|
6
|
+
return new UsbStorageWeb();
|
|
7
|
+
},
|
|
8
8
|
});
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
9
|
+
/**
|
|
10
|
+
* USB 저장 장치 접근 플러그인
|
|
11
|
+
* - Android: libaums 라이브러리를 통한 USB Mass Storage 접근
|
|
12
|
+
* - Browser: IndexedDB 기반 가상 USB 저장소 에뮬레이션
|
|
13
|
+
*/
|
|
14
|
+
export class UsbStorage {
|
|
15
|
+
/**
|
|
16
|
+
* 연결된 USB 장치 목록 조회
|
|
17
|
+
* @returns 연결된 USB 장치 정보 배열
|
|
18
|
+
*/
|
|
19
|
+
static async getDevices() {
|
|
20
|
+
const result = await usbStoragePlugin.getDevices();
|
|
21
|
+
return result.devices;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* USB 장치 접근 권한 요청
|
|
25
|
+
* @param filter 권한을 요청할 USB 장치의 vendorId 및 productId
|
|
26
|
+
* @returns 권한 승인 여부
|
|
27
|
+
*/
|
|
28
|
+
static async requestPermissions(filter) {
|
|
29
|
+
const result = await usbStoragePlugin.requestPermissions(filter);
|
|
30
|
+
return result.granted;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* USB 장치 접근 권한 확인
|
|
34
|
+
* @param filter 권한을 확인할 USB 장치의 vendorId 및 productId
|
|
35
|
+
* @returns 권한 보유 여부
|
|
36
|
+
*/
|
|
37
|
+
static async checkPermissions(filter) {
|
|
38
|
+
const result = await usbStoragePlugin.checkPermissions(filter);
|
|
39
|
+
return result.granted;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* USB 저장 장치에서 디렉토리 내용 읽기
|
|
43
|
+
* @param filter 대상 USB 장치의 vendorId 및 productId
|
|
44
|
+
* @param dirPath 읽을 디렉토리 경로
|
|
45
|
+
* @returns 디렉토리 내 파일/폴더 정보 배열
|
|
46
|
+
*/
|
|
47
|
+
static async readdir(filter, dirPath) {
|
|
48
|
+
const result = await usbStoragePlugin.readdir({ ...filter, path: dirPath });
|
|
49
|
+
return result.files;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* USB 저장 장치에서 파일 읽기
|
|
53
|
+
* @param filter 대상 USB 장치의 vendorId 및 productId
|
|
54
|
+
* @param filePath 읽을 파일 경로
|
|
55
|
+
* @returns 파일 데이터를 포함하는 Bytes, 또는 undefined
|
|
56
|
+
*/
|
|
57
|
+
static async readFile(filter, filePath) {
|
|
58
|
+
const result = await usbStoragePlugin.readFile({ ...filter, path: filePath });
|
|
59
|
+
if (result.data == null) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return bytes.fromBase64(result.data);
|
|
56
63
|
}
|
|
57
|
-
return bytes.fromBase64(result.data);
|
|
58
|
-
}
|
|
59
64
|
}
|
|
60
|
-
|
|
61
|
-
UsbStorage
|
|
62
|
-
};
|
|
63
|
-
//# sourceMappingURL=UsbStorage.js.map
|
|
65
|
+
//# sourceMappingURL=UsbStorage.js.map
|
package/dist/UsbStorage.js.map
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/UsbStorage.ts"],
|
|
4
|
-
"mappings": "AAAA,SAAS,sBAAsB;AAQ/B,SAAS,aAAa;AAEtB,MAAM,mBAAmB,eAAiC,cAAc;AAAA,EACtE,KAAK,YAAY;AACf,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,qBAAqB;AAC5D,WAAO,IAAI,cAAc;AAAA,EAC3B;AACF,CAAC;AAOM,MAAe,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/B,aAAa,aAAuC;AAClD,UAAM,SAAS,MAAM,iBAAiB,WAAW;AACjD,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,mBAAmB,QAA2C;AACzE,UAAM,SAAS,MAAM,iBAAiB,mBAAmB,MAAM;AAC/D,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,iBAAiB,QAA2C;AACvE,UAAM,SAAS,MAAM,iBAAiB,iBAAiB,MAAM;AAC7D,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,QAAQ,QAAyB,SAAyC;AACrF,UAAM,SAAS,MAAM,iBAAiB,QAAQ,EAAE,GAAG,QAAQ,MAAM,QAAQ,CAAC;AAC1E,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,SAAS,QAAyB,UAA8C;AAC3F,UAAM,SAAS,MAAM,iBAAiB,SAAS,EAAE,GAAG,QAAQ,MAAM,SAAS,CAAC;AAC5E,QAAI,OAAO,QAAQ,MAAM;AACvB,aAAO;AAAA,IACT;AACA,WAAO,MAAM,WAAW,OAAO,IAAI;AAAA,EACrC;AACF;",
|
|
5
|
-
"names": []
|
|
6
|
-
}
|
|
1
|
+
{"version":3,"file":"UsbStorage.js","sourceRoot":"","sources":["..\\src\\UsbStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAQjD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE9C,MAAM,gBAAgB,GAAG,cAAc,CAAmB,YAAY,EAAE;IACtE,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QAC9D,OAAO,IAAI,aAAa,EAAE,CAAC;IAC7B,CAAC;CACF,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,OAAgB,UAAU;IAC9B;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,UAAU;QACrB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,CAAC;QACnD,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAuB;QACrD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACjE,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAuB;QACnD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC/D,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAuB,EAAE,OAAe;QAC3D,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5E,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAuB,EAAE,QAAgB;QAC7D,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9E,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;CACF"}
|
package/dist/UsbStoragePlugin.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=UsbStoragePlugin.js.map
|
package/dist/index.js
CHANGED