@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @simplysm/capacitor-plugin-usb-storage
2
2
 
3
- Simplysm Package - Capacitor USB Storage Plugin. Provides USB Mass Storage device access on Android via the libaums library, with IndexedDB-based browser emulation.
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
- | `UsbStorage` | class | USB storage access plugin (static methods) |
18
- | `UsbStoragePlugin` | interface | Low-level Capacitor plugin interface for USB storage |
19
- | `UsbDeviceInfo` | interface | USB device information |
20
- | `UsbDeviceFilter` | interface | USB device filter (vendor/product ID pair) |
21
- | `UsbFileInfo` | interface | File/directory entry on USB device |
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
- ### `UsbDeviceInfo`
25
+ ### UsbDeviceInfo
26
+
27
+ Metadata about a connected USB mass storage device.
26
28
 
27
29
  | Field | Type | Description |
28
30
  |-------|------|-------------|
29
- | `deviceName` | `string` | Device name |
30
- | `manufacturerName` | `string` | Manufacturer name |
31
- | `productName` | `string` | Product name |
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
- ### `UsbDeviceFilter`
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
- ### `UsbFileInfo`
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` | File or directory name |
47
- | `isDirectory` | `boolean` | Whether the entry is a directory |
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
- ### `UsbStoragePlugin`
57
+ Native plugin interface for USB storage operations.
50
58
 
51
59
  | Method | Signature | Description |
52
60
  |--------|-----------|-------------|
53
- | `getDevices` | `() => Promise<{ devices: UsbDeviceInfo[] }>` | Get connected USB devices |
54
- | `requestPermissions` | `(options: UsbDeviceFilter) => Promise<{ granted: boolean }>` | Request USB device permission |
55
- | `checkPermissions` | `(options: UsbDeviceFilter) => Promise<{ granted: boolean }>` | Check USB device permission |
56
- | `readdir` | `(options: UsbDeviceFilter & { path: string }) => Promise<{ files: UsbFileInfo[] }>` | Read directory from USB |
57
- | `readFile` | `(options: UsbDeviceFilter & { path: string }) => Promise<{ data: string \| null }>` | Read file from USB (base64) |
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
- ### `UsbStorage`
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
- Abstract class with static methods for USB Mass Storage access.
73
+ All methods are static.
62
74
 
63
75
  | Method | Signature | Description |
64
76
  |--------|-----------|-------------|
65
- | `getDevices` | `() => Promise<UsbDeviceInfo[]>` | Get list of connected USB devices |
66
- | `requestPermissions` | `(filter: UsbDeviceFilter) => Promise<boolean>` | Request USB device access permission |
67
- | `checkPermissions` | `(filter: UsbDeviceFilter) => Promise<boolean>` | Check USB device access permission |
68
- | `readdir` | `(filter: UsbDeviceFilter, dirPath: string) => Promise<UsbFileInfo[]>` | Read directory contents from USB device |
69
- | `readFile` | `(filter: UsbDeviceFilter, filePath: string) => Promise<Bytes \| undefined>` | Read file from USB device |
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
- ### List and read from USB device
85
+ ### Discover and access a USB device
74
86
 
75
- ```typescript
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
- if (devices.length > 0) {
82
- const filter = { vendorId: devices[0].vendorId, productId: devices[0].productId };
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
- // Request permission
85
- const granted = await UsbStorage.requestPermissions(filter);
112
+ ### Read a file from USB storage
113
+
114
+ ```ts
115
+ import { UsbStorage } from "@simplysm/capacitor-plugin-usb-storage";
86
116
 
87
- if (granted) {
88
- // Read directory
89
- const files = await UsbStorage.readdir(filter, "/");
117
+ const filter = { vendorId: 0x1234, productId: 0x5678 };
90
118
 
91
- // Read a file
92
- const data = await UsbStorage.readFile(filter, "/document.txt");
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
  ```
@@ -1,4 +1,5 @@
1
1
  apply plugin: 'com.android.library'
2
+ apply plugin: 'kotlin-android'
2
3
 
3
4
  android {
4
5
  namespace "kr.co.simplysm.capacitor.usbstorage"
@@ -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
+ }
@@ -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
- * Plugin for interacting with USB storage devices
5
- * - Android: USB Mass Storage access via libaums library
6
- * - Browser: IndexedDB-based virtual USB storage emulation
4
+ * USB 저장 장치 접근 플러그인
5
+ * - Android: libaums 라이브러리를 통한 USB Mass Storage 접근
6
+ * - Browser: IndexedDB 기반 가상 USB 저장소 에뮬레이션
7
7
  */
8
8
  export declare abstract class UsbStorage {
9
9
  /**
10
- * Get list of connected USB devices
11
- * @returns Array of connected USB device info
10
+ * 연결된 USB 장치 목록 조회
11
+ * @returns 연결된 USB 장치 정보 배열
12
12
  */
13
13
  static getDevices(): Promise<UsbDeviceInfo[]>;
14
14
  /**
15
- * Request USB device access permission
16
- * @param filter vendorId and productId of the USB device to request permission for
17
- * @returns Whether permission was granted
15
+ * USB 장치 접근 권한 요청
16
+ * @param filter 권한을 요청할 USB 장치의 vendorId productId
17
+ * @returns 권한 승인 여부
18
18
  */
19
19
  static requestPermissions(filter: UsbDeviceFilter): Promise<boolean>;
20
20
  /**
21
- * Check if USB device access permission is granted
22
- * @param filter vendorId and productId of the USB device to check permission for
23
- * @returns Whether permission is held
21
+ * USB 장치 접근 권한 확인
22
+ * @param filter 권한을 확인할 USB 장치의 vendorId productId
23
+ * @returns 권한 보유 여부
24
24
  */
25
25
  static checkPermissions(filter: UsbDeviceFilter): Promise<boolean>;
26
26
  /**
27
- * Read directory contents from USB storage device
28
- * @param filter vendorId and productId of the target USB device
29
- * @param dirPath Directory path to read
30
- * @returns Array of file/folder info in the directory
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
- * Read a file from USB storage device
35
- * @param filter vendorId and productId of the target USB device
36
- * @param filePath File path to read
37
- * @returns Bytes containing file data, or undefined
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
  }
@@ -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
- web: async () => {
5
- const { UsbStorageWeb } = await import("./web/UsbStorageWeb");
6
- return new UsbStorageWeb();
7
- }
4
+ web: async () => {
5
+ const { UsbStorageWeb } = await import("./web/UsbStorageWeb.js");
6
+ return new UsbStorageWeb();
7
+ },
8
8
  });
9
- class UsbStorage {
10
- /**
11
- * Get list of connected USB devices
12
- * @returns Array of connected USB device info
13
- */
14
- static async getDevices() {
15
- const result = await usbStoragePlugin.getDevices();
16
- return result.devices;
17
- }
18
- /**
19
- * Request USB device access permission
20
- * @param filter vendorId and productId of the USB device to request permission for
21
- * @returns Whether permission was granted
22
- */
23
- static async requestPermissions(filter) {
24
- const result = await usbStoragePlugin.requestPermissions(filter);
25
- return result.granted;
26
- }
27
- /**
28
- * Check if USB device access permission is granted
29
- * @param filter vendorId and productId of the USB device to check permission for
30
- * @returns Whether permission is held
31
- */
32
- static async checkPermissions(filter) {
33
- const result = await usbStoragePlugin.checkPermissions(filter);
34
- return result.granted;
35
- }
36
- /**
37
- * Read directory contents from USB storage device
38
- * @param filter vendorId and productId of the target USB device
39
- * @param dirPath Directory path to read
40
- * @returns Array of file/folder info in the directory
41
- */
42
- static async readdir(filter, dirPath) {
43
- const result = await usbStoragePlugin.readdir({ ...filter, path: dirPath });
44
- return result.files;
45
- }
46
- /**
47
- * Read a file from USB storage device
48
- * @param filter vendorId and productId of the target USB device
49
- * @param filePath File path to read
50
- * @returns Bytes containing file data, or undefined
51
- */
52
- static async readFile(filter, filePath) {
53
- const result = await usbStoragePlugin.readFile({ ...filter, path: filePath });
54
- if (result.data == null) {
55
- return void 0;
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
- export {
61
- UsbStorage
62
- };
63
- //# sourceMappingURL=UsbStorage.js.map
65
+ //# sourceMappingURL=UsbStorage.js.map
@@ -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"}
@@ -1 +1,2 @@
1
- //# sourceMappingURL=UsbStoragePlugin.js.map
1
+ export {};
2
+ //# sourceMappingURL=UsbStoragePlugin.js.map
@@ -1,6 +1 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "mappings": "",
5
- "names": []
6
- }
1
+ {"version":3,"file":"UsbStoragePlugin.js","sourceRoot":"","sources":["..\\src\\UsbStoragePlugin.ts"],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ // USB 저장소
1
2
  export * from "./UsbStoragePlugin.js";
2
3
  export * from "./UsbStorage.js";
3
- //# sourceMappingURL=index.js.map
4
+ //# sourceMappingURL=index.js.map