@posx/capacitor-usb-printer 0.0.5 → 0.0.7

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
@@ -153,6 +153,7 @@ addListener(eventName: 'deviceDetached', listenerFunc: (device: UsbDevice) => vo
153
153
  | **`vendorId`** | <code>number</code> |
154
154
  | **`productId`** | <code>number</code> |
155
155
  | **`deviceName`** | <code>string</code> |
156
+ | **`portPath`** | <code>string</code> |
156
157
  | **`manufacturerName`** | <code>string</code> |
157
158
  | **`productName`** | <code>string</code> |
158
159
  | **`serialNumber`** | <code>string</code> |
@@ -9,9 +9,12 @@ import android.hardware.usb.*;
9
9
  import android.os.Build;
10
10
  import android.util.Log;
11
11
 
12
+ import java.io.File;
12
13
  import java.util.ArrayList;
14
+ import java.util.Collections;
13
15
  import java.util.List;
14
16
  import java.util.Map;
17
+ import java.util.Scanner;
15
18
  import java.util.concurrent.ConcurrentHashMap;
16
19
 
17
20
  public class UsbPrinter {
@@ -24,12 +27,30 @@ public class UsbPrinter {
24
27
 
25
28
  public UsbPrinter(Context context) {
26
29
  usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
30
+ if (usbManager == null) Log.e(TAG, "USB service unavailable on this device");
27
31
  }
28
32
 
29
33
  public List<UsbDevice> listDevices() {
34
+ if (usbManager == null) return Collections.emptyList();
30
35
  return new ArrayList<>(usbManager.getDeviceList().values());
31
36
  }
32
37
 
38
+ public String getPortPath(UsbDevice device) {
39
+ String[] parts = device.getDeviceName().split("/");
40
+ try {
41
+ int busNum = Integer.parseInt(parts[parts.length - 2]);
42
+ int devNum = Integer.parseInt(parts[parts.length - 1]);
43
+ for (File f : new File("/sys/bus/usb/devices").listFiles()) {
44
+ File bf = new File(f, "busnum"), df = new File(f, "devnum");
45
+ if (!bf.exists()) continue;
46
+ if (Integer.parseInt(new Scanner(bf).nextLine()) == busNum &&
47
+ Integer.parseInt(new Scanner(df).nextLine()) == devNum)
48
+ return f.getName();
49
+ }
50
+ } catch (Exception ignored) {}
51
+ return "";
52
+ }
53
+
33
54
  public String getSerialNumber(UsbDevice device) {
34
55
  try {
35
56
  return device.getSerialNumber() != null ? device.getSerialNumber() : "";
@@ -39,6 +60,7 @@ public class UsbPrinter {
39
60
  }
40
61
 
41
62
  public void requestPermission(Context context, UsbDevice device, PermissionCallback callback) {
63
+ if (usbManager == null) { callback.onResult(false); return; }
42
64
  if (usbManager.hasPermission(device)) {
43
65
  callback.onResult(true);
44
66
  return;
@@ -70,6 +92,7 @@ public class UsbPrinter {
70
92
  }
71
93
 
72
94
  public boolean connect(UsbDevice device) {
95
+ if (usbManager == null) return false;
73
96
  int id = device.getDeviceId();
74
97
  if (connections.containsKey(id)) return true;
75
98
 
@@ -101,7 +124,11 @@ public class UsbPrinter {
101
124
  }
102
125
 
103
126
  try {
104
- conn.claimInterface(usbInterface, true);
127
+ if (!conn.claimInterface(usbInterface, true)) {
128
+ conn.close();
129
+ Log.e(TAG, "Failed to claim interface for device " + id);
130
+ return false;
131
+ }
105
132
  String name = device.getProductName() != null ? device.getProductName() : device.getDeviceName();
106
133
  String serial = getSerialNumber(device);
107
134
  connections.put(id, new DeviceConnection(conn, bulkOut, usbInterface, name, serial));
@@ -129,8 +156,8 @@ public class UsbPrinter {
129
156
  DeviceConnection dc = connections.get(deviceId);
130
157
  if (dc == null) return false;
131
158
  int result = dc.connection.bulkTransfer(dc.bulkOut, data, data.length, 10000);
132
- if (result < 0) Log.e(TAG, "Transfer failed for device " + deviceId + ": " + result);
133
- return result >= 0;
159
+ if (result <= 0) Log.e(TAG, "Transfer failed for device " + deviceId + ": " + result);
160
+ return result > 0;
134
161
  }
135
162
 
136
163
  public DeviceConnection getConnection(int deviceId) {
@@ -138,6 +165,7 @@ public class UsbPrinter {
138
165
  }
139
166
 
140
167
  public UsbDevice findDevice(int deviceId) {
168
+ if (usbManager == null) return null;
141
169
  for (UsbDevice device : usbManager.getDeviceList().values()) {
142
170
  if (device.getDeviceId() == deviceId) return device;
143
171
  }
@@ -148,8 +176,12 @@ public class UsbPrinter {
148
176
  if (hex.length() % 2 != 0) throw new IllegalArgumentException("Hex string length must be even");
149
177
  int len = hex.length();
150
178
  byte[] data = new byte[len / 2];
151
- for (int i = 0; i < len; i += 2)
152
- data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
179
+ for (int i = 0; i < len; i += 2) {
180
+ int hi = Character.digit(hex.charAt(i), 16);
181
+ int lo = Character.digit(hex.charAt(i + 1), 16);
182
+ if (hi < 0 || lo < 0) throw new IllegalArgumentException("Invalid hex char at position " + i);
183
+ data[i / 2] = (byte) ((hi << 4) + lo);
184
+ }
153
185
  return data;
154
186
  }
155
187
 
@@ -39,7 +39,7 @@ public class UsbPrinterPlugin extends Plugin {
39
39
  notifyListeners("deviceDetached", data);
40
40
  } else {
41
41
  // request permission first so serialNumber is readable
42
- implementation.requestPermission(ctx, device, granted -> {
42
+ implementation.requestPermission(getContext(), device, granted -> {
43
43
  data.put("serialNumber", implementation.getSerialNumber(device));
44
44
  notifyListeners("deviceAttached", data);
45
45
  });
@@ -85,6 +85,7 @@ public class UsbPrinterPlugin extends Plugin {
85
85
  d.put("vendorId", device.getVendorId());
86
86
  d.put("productId", device.getProductId());
87
87
  d.put("deviceName", device.getDeviceName());
88
+ d.put("portPath", implementation.getPortPath(device));
88
89
  d.put("manufacturerName", device.getManufacturerName() != null ? device.getManufacturerName() : "");
89
90
  d.put("productName", device.getProductName() != null ? device.getProductName() : "");
90
91
  return d;
@@ -173,6 +174,8 @@ public class UsbPrinterPlugin extends Plugin {
173
174
  boolean success = implementation.print(deviceId, bytes);
174
175
  if (success) call.resolve();
175
176
  else call.reject("Not connected or transfer failed");
177
+ } catch (IllegalArgumentException e) {
178
+ call.reject("Invalid hex data: " + e.getMessage());
176
179
  } catch (Exception e) {
177
180
  call.reject("Failed to print", e);
178
181
  }
package/dist/docs.json CHANGED
@@ -184,6 +184,13 @@
184
184
  "complexTypes": [],
185
185
  "type": "string"
186
186
  },
187
+ {
188
+ "name": "portPath",
189
+ "tags": [],
190
+ "docs": "",
191
+ "complexTypes": [],
192
+ "type": "string"
193
+ },
187
194
  {
188
195
  "name": "manufacturerName",
189
196
  "tags": [],
@@ -4,6 +4,7 @@ export interface UsbDevice {
4
4
  vendorId: number;
5
5
  productId: number;
6
6
  deviceName: string;
7
+ portPath: string;
7
8
  manufacturerName: string;
8
9
  productName: string;
9
10
  serialNumber: string;
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\r\n\r\nexport interface UsbDevice {\r\n deviceId: number;\r\n vendorId: number;\r\n productId: number;\r\n deviceName: string;\r\n manufacturerName: string;\r\n productName: string;\r\n serialNumber: string;\r\n}\r\n\r\nexport interface UsbPrinterPlugin {\r\n listDevices(): Promise<{ devices: UsbDevice[] }>;\r\n requestPermission(options: { deviceId: number }): Promise<{ granted: boolean }>;\r\n connect(options: { deviceId: number }): Promise<{ connected: boolean }>;\r\n disconnect(options: { deviceId: number }): Promise<void>;\r\n print(options: { deviceId: number; data: string }): Promise<void>;\r\n getStatus(options: { deviceId: number }): Promise<{ connected: boolean; deviceName: string; serialNumber: string }>;\r\n addListener(eventName: 'deviceAttached', listenerFunc: (device: UsbDevice) => void): Promise<PluginListenerHandle>;\r\n addListener(eventName: 'deviceDetached', listenerFunc: (device: UsbDevice) => void): Promise<PluginListenerHandle>;\r\n}\r\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\r\n\r\nexport interface UsbDevice {\r\n deviceId: number;\r\n vendorId: number;\r\n productId: number;\r\n deviceName: string;\r\n portPath: string;\r\n manufacturerName: string;\r\n productName: string;\r\n serialNumber: string;\r\n}\r\n\r\nexport interface UsbPrinterPlugin {\r\n listDevices(): Promise<{ devices: UsbDevice[] }>;\r\n requestPermission(options: { deviceId: number }): Promise<{ granted: boolean }>;\r\n connect(options: { deviceId: number }): Promise<{ connected: boolean }>;\r\n disconnect(options: { deviceId: number }): Promise<void>;\r\n print(options: { deviceId: number; data: string }): Promise<void>;\r\n getStatus(options: { deviceId: number }): Promise<{ connected: boolean; deviceName: string; serialNumber: string }>;\r\n addListener(eventName: 'deviceAttached', listenerFunc: (device: UsbDevice) => void): Promise<PluginListenerHandle>;\r\n addListener(eventName: 'deviceDetached', listenerFunc: (device: UsbDevice) => void): Promise<PluginListenerHandle>;\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,63 +1,63 @@
1
- {
2
- "name": "@posx/capacitor-usb-printer",
3
- "version": "0.0.5",
4
- "description": "Capacitor plugin for USB ESC/POS thermal printer via Android USB Host API",
5
- "main": "dist/plugin.cjs.js",
6
- "module": "dist/esm/index.js",
7
- "types": "dist/esm/index.d.ts",
8
- "unpkg": "dist/plugin.js",
9
- "files": [
10
- "android/src/main/",
11
- "android/build.gradle",
12
- "dist/"
13
- ],
14
- "author": "posx team",
15
- "license": "MIT",
16
- "keywords": [
17
- "capacitor",
18
- "plugin",
19
- "native"
20
- ],
21
- "scripts": {
22
- "verify": "npm run verify:android && npm run verify:web",
23
- "verify:android": "cd android && ./gradlew clean build test && cd ..",
24
- "verify:web": "npm run build",
25
- "lint": "npm run eslint && npm run prettier -- --check",
26
- "fmt": "npm run eslint -- --fix && npm run prettier -- --write",
27
- "eslint": "eslint . --ext ts",
28
- "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
29
- "docgen": "docgen --api UsbPrinterPlugin --output-readme README.md --output-json dist/docs.json",
30
- "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
31
- "clean": "rimraf ./dist",
32
- "p": "npm run build && npm publish",
33
- "bump": "bumpp patch --commit --tag --push --yes",
34
- "watch": "tsc --watch",
35
- "prepublishOnly": "npm run build"
36
- },
37
- "devDependencies": {
38
- "@capacitor/android": "^5.7.8",
39
- "@capacitor/core": "^5.7.8",
40
- "@capacitor/docgen": "^0.3.1",
41
- "@ionic/eslint-config": "^0.4.0",
42
- "@ionic/prettier-config": "^4.0.0",
43
- "bumpp": "10.4.1",
44
- "eslint": "^8.57.1",
45
- "prettier": "^3.6.2",
46
- "prettier-plugin-java": "^2.7.7",
47
- "rimraf": "^6.1.0",
48
- "rollup": "^4.53.2",
49
- "typescript": "^5.9.3"
50
- },
51
- "peerDependencies": {
52
- "@capacitor/core": ">=5.0.0"
53
- },
54
- "prettier": "@ionic/prettier-config",
55
- "eslintConfig": {
56
- "extends": "@ionic/eslint-config/recommended"
57
- },
58
- "capacitor": {
59
- "android": {
60
- "src": "android"
61
- }
62
- }
63
- }
1
+ {
2
+ "name": "@posx/capacitor-usb-printer",
3
+ "version": "0.0.7",
4
+ "description": "Capacitor plugin for USB ESC/POS thermal printer via Android USB Host API",
5
+ "main": "dist/plugin.cjs.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "unpkg": "dist/plugin.js",
9
+ "files": [
10
+ "android/src/main/",
11
+ "android/build.gradle",
12
+ "dist/"
13
+ ],
14
+ "author": "posx team",
15
+ "license": "MIT",
16
+ "keywords": [
17
+ "capacitor",
18
+ "plugin",
19
+ "native"
20
+ ],
21
+ "scripts": {
22
+ "verify": "npm run verify:android && npm run verify:web",
23
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
24
+ "verify:web": "npm run build",
25
+ "lint": "npm run eslint && npm run prettier -- --check",
26
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write",
27
+ "eslint": "eslint . --ext ts",
28
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
29
+ "docgen": "docgen --api UsbPrinterPlugin --output-readme README.md --output-json dist/docs.json",
30
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
31
+ "clean": "rimraf ./dist",
32
+ "p": "npm run build && npm publish",
33
+ "bump": "bumpp patch --commit --tag --push --yes",
34
+ "watch": "tsc --watch",
35
+ "prepublishOnly": "npm run build"
36
+ },
37
+ "devDependencies": {
38
+ "@capacitor/android": "^5.7.8",
39
+ "@capacitor/core": "^5.7.8",
40
+ "@capacitor/docgen": "^0.3.1",
41
+ "@ionic/eslint-config": "^0.4.0",
42
+ "@ionic/prettier-config": "^4.0.0",
43
+ "bumpp": "10.4.1",
44
+ "eslint": "^8.57.1",
45
+ "prettier": "^3.6.2",
46
+ "prettier-plugin-java": "^2.7.7",
47
+ "rimraf": "^6.1.0",
48
+ "rollup": "^4.53.2",
49
+ "typescript": "^5.9.3"
50
+ },
51
+ "peerDependencies": {
52
+ "@capacitor/core": ">=5.0.0"
53
+ },
54
+ "prettier": "@ionic/prettier-config",
55
+ "eslintConfig": {
56
+ "extends": "@ionic/eslint-config/recommended"
57
+ },
58
+ "capacitor": {
59
+ "android": {
60
+ "src": "android"
61
+ }
62
+ }
63
+ }