@m430/capacitor-label-printer 0.1.0
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/API.md +218 -0
- package/LICENSE +21 -0
- package/M430CapacitorLabelPrinter.podspec +21 -0
- package/README.md +190 -0
- package/android/build.gradle +46 -0
- package/android/libs/.gitkeep +1 -0
- package/android/libs/fat-generic-tspl-bluetooth-classic-0.1.16-GA.jar +0 -0
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/java/com/m430/capacitor/labelprinter/.gitkeep +1 -0
- package/android/src/main/java/com/m430/capacitor/labelprinter/AndroidPrinterManager.java +132 -0
- package/android/src/main/java/com/m430/capacitor/labelprinter/AndroidStatusMapper.java +54 -0
- package/android/src/main/java/com/m430/capacitor/labelprinter/LabelPrinterPlugin.java +273 -0
- package/android/src/main/java/com/m430/capacitor/labelprinter/VendorAndroidDeviceCatalog.java +81 -0
- package/android/src/main/java/com/m430/capacitor/labelprinter/VendorAndroidPrinterSession.java +189 -0
- package/capacitor-label-printer.podspec +21 -0
- package/dist/docs.json +443 -0
- package/dist/esm/cpcl/builder.d.ts +10 -0
- package/dist/esm/cpcl/builder.js +35 -0
- package/dist/esm/definitions.d.ts +107 -0
- package/dist/esm/definitions.js +1 -0
- package/dist/esm/errors.d.ts +1 -0
- package/dist/esm/errors.js +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/tspl/builder.d.ts +13 -0
- package/dist/esm/tspl/builder.js +45 -0
- package/dist/esm/tspl/helpers.d.ts +2 -0
- package/dist/esm/tspl/helpers.js +6 -0
- package/dist/esm/types.d.ts +12 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/web.d.ts +21 -0
- package/dist/esm/web.js +34 -0
- package/dist/plugin.cjs.js +143 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +136 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/.gitkeep +1 -0
- package/ios/Plugin/IOSPrinterManager.swift +230 -0
- package/ios/Plugin/IOSStatusMapper.swift +57 -0
- package/ios/Plugin/LabelPrinterPlugin.swift +141 -0
- package/ios/VendorFrameworks/.gitkeep +1 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/BasedOtherConnectedDevice.h +17 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/ConnectedDevice.h +213 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/IPRTBlueToothBaseDef.h +22 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/KeepStateConnectedDevice.h +18 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/QueueConfig.h +18 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/ReadOptions.h +22 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/WroteReporter.h +23 -0
- package/ios/VendorFrameworks/adapter.framework/Headers/adapter.h +18 -0
- package/ios/VendorFrameworks/adapter.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/adapter.framework/Modules/module.modulemap +6 -0
- package/ios/VendorFrameworks/adapter.framework/adapter +0 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/adapter.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/adapter.framework/_CodeSignature/CodeResources +101 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/adapter.framework/adapter +0 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/ibridge.framework/Frameworks/adapter.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/ibridge.framework/Frameworks/adapter.framework/adapter +0 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/ibridge.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/ibridge.framework/_CodeSignature/CodeResources +132 -0
- package/ios/VendorFrameworks/appleble.framework/Frameworks/ibridge.framework/ibridge +0 -0
- package/ios/VendorFrameworks/appleble.framework/Headers/AppleBle.h +25 -0
- package/ios/VendorFrameworks/appleble.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/appleble.framework/Modules/module.modulemap +6 -0
- package/ios/VendorFrameworks/appleble.framework/_CodeSignature/CodeResources +252 -0
- package/ios/VendorFrameworks/appleble.framework/appleble +0 -0
- package/ios/VendorFrameworks/father.framework/Frameworks/adapter.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/father.framework/Frameworks/adapter.framework/adapter +0 -0
- package/ios/VendorFrameworks/father.framework/Headers/Appendat.h +28 -0
- package/ios/VendorFrameworks/father.framework/Headers/Arg.h +22 -0
- package/ios/VendorFrameworks/father.framework/Headers/BasicBatteryVolumeArg.h +16 -0
- package/ios/VendorFrameworks/father.framework/Headers/BinaryCommand.h +17 -0
- package/ios/VendorFrameworks/father.framework/Headers/CPCLCommand.h +10 -0
- package/ios/VendorFrameworks/father.framework/Headers/CallbackData.h +26 -0
- package/ios/VendorFrameworks/father.framework/Headers/Checker.h +16 -0
- package/ios/VendorFrameworks/father.framework/Headers/Command.h +25 -0
- package/ios/VendorFrameworks/father.framework/Headers/CommandClause.h +33 -0
- package/ios/VendorFrameworks/father.framework/Headers/Commander.h +31 -0
- package/ios/VendorFrameworks/father.framework/Headers/DataWriteOperation.h +42 -0
- package/ios/VendorFrameworks/father.framework/Headers/DefaultCommand.h +16 -0
- package/ios/VendorFrameworks/father.framework/Headers/EasyArg.h +16 -0
- package/ios/VendorFrameworks/father.framework/Headers/FastBinary.h +20 -0
- package/ios/VendorFrameworks/father.framework/Headers/HexOutput.h +19 -0
- package/ios/VendorFrameworks/father.framework/Headers/IDataWriteCallback.h +25 -0
- package/ios/VendorFrameworks/father.framework/Headers/Lifecycle.h +21 -0
- package/ios/VendorFrameworks/father.framework/Headers/NewLineArg.h +15 -0
- package/ios/VendorFrameworks/father.framework/Headers/OnlyBinaryHeaderArg.h +15 -0
- package/ios/VendorFrameworks/father.framework/Headers/OnlyTextHeaderArg.h +16 -0
- package/ios/VendorFrameworks/father.framework/Headers/PImageTool.h +22 -0
- package/ios/VendorFrameworks/father.framework/Headers/PReplaceKit.h +16 -0
- package/ios/VendorFrameworks/father.framework/Headers/PSDK.h +60 -0
- package/ios/VendorFrameworks/father.framework/Headers/PVariableKit.h +18 -0
- package/ios/VendorFrameworks/father.framework/Headers/PsdkConst.h +33 -0
- package/ios/VendorFrameworks/father.framework/Headers/Raw.h +22 -0
- package/ios/VendorFrameworks/father.framework/Headers/SimpleCheck.h +16 -0
- package/ios/VendorFrameworks/father.framework/Headers/SingleCommand.h +32 -0
- package/ios/VendorFrameworks/father.framework/Headers/TSPLCommand.h +10 -0
- package/ios/VendorFrameworks/father.framework/Headers/WriteControl.h +12 -0
- package/ios/VendorFrameworks/father.framework/Headers/WriteOptions.h +28 -0
- package/ios/VendorFrameworks/father.framework/Headers/father.h +21 -0
- package/ios/VendorFrameworks/father.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/father.framework/Modules/module.modulemap +6 -0
- package/ios/VendorFrameworks/father.framework/father +0 -0
- package/ios/VendorFrameworks/tspl.framework/Frameworks/father.framework/Frameworks/adapter.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/tspl.framework/Frameworks/father.framework/Frameworks/adapter.framework/adapter +0 -0
- package/ios/VendorFrameworks/tspl.framework/Frameworks/father.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/tspl.framework/Frameworks/father.framework/father +0 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/BasicTSPL.h +146 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/BasicTSPLArg.h +17 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/GenericTSPL.h +16 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TBar.h +30 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TBarCode.h +54 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TBatteryVolume.h +19 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TBox.h +32 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TCircle.h +26 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TCleanBmpFlash.h +20 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TClear.h +20 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TCut.h +21 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TDensity.h +21 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TDirection.h +51 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TDmatrix.h +29 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TDownloadBmpFlash.h +16 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TGap.h +21 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TImage.h +36 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TLine.h +34 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TMddle.h +16 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TPage.h +22 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TPrint.h +21 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TQRCode.h +35 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TReadState.h +16 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TReverse.h +27 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSN.h +19 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLCodeType.h +53 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLCorrectLevel.h +21 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLFont.h +83 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLImageMode.h +30 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLLineMode.h +37 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLLineType.h +21 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLOutDirection.h +27 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLRotation.h +36 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPLShowType.h +36 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSPL_.h +18 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TSpeed.h +20 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TText.h +38 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TTextBox.h +44 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/TVersion.h +19 -0
- package/ios/VendorFrameworks/tspl.framework/Headers/tspl.h +45 -0
- package/ios/VendorFrameworks/tspl.framework/Info.plist +0 -0
- package/ios/VendorFrameworks/tspl.framework/Modules/module.modulemap +6 -0
- package/ios/VendorFrameworks/tspl.framework/tspl +0 -0
- package/package.json +95 -0
package/API.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# API
|
|
2
|
+
|
|
3
|
+
`@m430/capacitor-label-printer` 当前公开的是一组偏底层的打印能力,业务层建议自行封装打印模板、重试策略和任务队列。
|
|
4
|
+
|
|
5
|
+
## 方法
|
|
6
|
+
|
|
7
|
+
### `isSupported()`
|
|
8
|
+
|
|
9
|
+
判断当前运行环境是否支持原生标签打印。
|
|
10
|
+
|
|
11
|
+
返回:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
Promise<{ supported: boolean }>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### `checkPermissions()`
|
|
18
|
+
|
|
19
|
+
查询当前蓝牙权限状态。
|
|
20
|
+
|
|
21
|
+
返回:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
Promise<PrinterPermissionResult>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### `ensurePermissions()`
|
|
28
|
+
|
|
29
|
+
确保蓝牙访问权限已就绪。
|
|
30
|
+
|
|
31
|
+
- Android:会主动触发“附近设备”权限申请
|
|
32
|
+
- iOS:首版会返回结构化权限状态,真实系统授权仍由蓝牙扫描/连接行为触发
|
|
33
|
+
|
|
34
|
+
返回:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
Promise<PrinterPermissionResult>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `discoverDevices(options?)`
|
|
41
|
+
|
|
42
|
+
发现可用于连接的打印机列表。
|
|
43
|
+
|
|
44
|
+
参数:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
interface DiscoverDevicesOptions {
|
|
48
|
+
timeout?: number;
|
|
49
|
+
namePrefixes?: string[];
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
返回:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
Promise<{ devices: PrinterDevice[] }>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
说明:
|
|
60
|
+
|
|
61
|
+
- Android 上如果权限不足,插件会在内部先尝试申请权限
|
|
62
|
+
- 权限仍不足时会抛出 `PERMISSION_DENIED`
|
|
63
|
+
|
|
64
|
+
### `connect(options)`
|
|
65
|
+
|
|
66
|
+
连接指定打印机。
|
|
67
|
+
|
|
68
|
+
参数:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
interface ConnectOptions {
|
|
72
|
+
deviceId: string;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
返回:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
Promise<void>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `disconnect()`
|
|
83
|
+
|
|
84
|
+
断开当前打印机连接。
|
|
85
|
+
|
|
86
|
+
返回:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
Promise<void>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `getConnectionState()`
|
|
93
|
+
|
|
94
|
+
查询当前连接状态。
|
|
95
|
+
|
|
96
|
+
返回:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
Promise<{ state: PrinterConnectionState }>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
其中 `PrinterConnectionState` 为:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
type PrinterConnectionState = 'disconnected' | 'connecting' | 'connected';
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `print(options)`
|
|
109
|
+
|
|
110
|
+
发送原始打印负载到打印机。
|
|
111
|
+
|
|
112
|
+
参数:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
interface PrintOptions {
|
|
116
|
+
payload: string;
|
|
117
|
+
language?: PrinterLanguage;
|
|
118
|
+
copies?: number;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
其中 `PrinterLanguage` 为:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
type PrinterLanguage = 'tspl' | 'cpcl' | 'raw';
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
返回:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
Promise<void>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### `getStatus()`
|
|
135
|
+
|
|
136
|
+
查询当前打印机状态。
|
|
137
|
+
|
|
138
|
+
返回:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
Promise<PrinterStatus>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
interface PrinterStatus {
|
|
146
|
+
connected: boolean;
|
|
147
|
+
ready?: boolean;
|
|
148
|
+
paperOut?: boolean;
|
|
149
|
+
coverOpen?: boolean;
|
|
150
|
+
overheating?: boolean;
|
|
151
|
+
message?: string;
|
|
152
|
+
raw?: unknown;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### `openAppSettings()`
|
|
157
|
+
|
|
158
|
+
跳转到应用系统设置页。
|
|
159
|
+
|
|
160
|
+
返回:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
Promise<void>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 主要类型
|
|
167
|
+
|
|
168
|
+
### `PrinterPermissionResult`
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
interface PrinterPermissionResult {
|
|
172
|
+
granted: boolean;
|
|
173
|
+
canPrompt: boolean;
|
|
174
|
+
shouldOpenSettings: boolean;
|
|
175
|
+
permissions: {
|
|
176
|
+
bluetoothConnect?: PermissionState;
|
|
177
|
+
bluetoothScan?: PermissionState;
|
|
178
|
+
bluetooth?: PermissionState;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied';
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### `PrinterDevice`
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
interface PrinterDevice {
|
|
191
|
+
id: string;
|
|
192
|
+
name: string;
|
|
193
|
+
address?: string;
|
|
194
|
+
transport: PrinterTransport;
|
|
195
|
+
bonded?: boolean;
|
|
196
|
+
rssi?: number;
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
type PrinterTransport = 'classic' | 'ble';
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## 导出的 Builder 与 Helper
|
|
205
|
+
|
|
206
|
+
除了 `LabelPrinter` 插件对象,包里还导出了:
|
|
207
|
+
|
|
208
|
+
- `CpclBuilder`
|
|
209
|
+
- `TsplBuilder`
|
|
210
|
+
- `mmToDots`
|
|
211
|
+
- `escapeTsplText`
|
|
212
|
+
|
|
213
|
+
推荐业务层先用 `CpclBuilder` 或 `TsplBuilder` 组装 `payload`,再调用 `print()`。
|
|
214
|
+
|
|
215
|
+
## 额外说明
|
|
216
|
+
|
|
217
|
+
- Web 端只有 `isSupported()` 和 `getConnectionState()` / `getStatus()` 的兜底返回,其余方法会抛错
|
|
218
|
+
- 自动生成的结构化 API 元数据位于 `dist/docs.json`
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andy Zheng
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
repository_url = package.dig('repository', 'url').to_s.sub(/^git\+/, '')
|
|
5
|
+
homepage_url = repository_url.sub(/\.git$/, '')
|
|
6
|
+
|
|
7
|
+
Pod::Spec.new do |s|
|
|
8
|
+
s.name = 'M430CapacitorLabelPrinter'
|
|
9
|
+
s.version = package['version']
|
|
10
|
+
s.summary = package['description']
|
|
11
|
+
s.license = package['license']
|
|
12
|
+
s.homepage = homepage_url
|
|
13
|
+
s.author = package['author']
|
|
14
|
+
s.source = { git: repository_url, tag: s.version.to_s }
|
|
15
|
+
s.source_files = 'ios/Plugin/**/*.{swift,h,m,mm}'
|
|
16
|
+
s.vendored_frameworks = 'ios/VendorFrameworks/*.framework', 'ios/VendorFrameworks/*.xcframework'
|
|
17
|
+
s.preserve_paths = 'ios/VendorFrameworks/**/*'
|
|
18
|
+
s.ios.deployment_target = '13.0'
|
|
19
|
+
s.dependency 'Capacitor'
|
|
20
|
+
s.swift_version = '5.9'
|
|
21
|
+
end
|
package/README.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# @m430/capacitor-label-printer
|
|
2
|
+
|
|
3
|
+
面向启锐 `QR-365` 及同类标签热敏打印机的 `Capacitor 7` 插件,内置 `CPCL` / `TSPL` 指令发送能力。
|
|
4
|
+
|
|
5
|
+
这个包的目标不是把业务模板写死在插件里,而是提供一层可复用的原生打印通道,统一暴露设备发现、连接、状态查询和标签打印能力,并随 npm 包分发 Android `jar` 与 iOS `framework`。
|
|
6
|
+
|
|
7
|
+
## 当前状态
|
|
8
|
+
|
|
9
|
+
- 已完成独立仓库、npm 包、Capacitor 插件骨架和 `example-app`
|
|
10
|
+
- 已完成 Android `jar` 与 iOS `framework` 的随包分发
|
|
11
|
+
- 已完成统一 JS API、`CPCL` / `TSPL` builder、Android/iOS 编译链路验证
|
|
12
|
+
- 当前 `AndroidPrinterManager` 与 `IOSPrinterManager` 仍是首版骨架,真实厂商 SDK 的会话管理、写入和状态回传逻辑需要继续结合真机联调补齐
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @m430/capacitor-label-printer
|
|
18
|
+
npx cap sync
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
如果宿主项目还没有添加原生平台,请先执行:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx cap add android
|
|
25
|
+
npx cap add ios
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 宿主项目权限
|
|
29
|
+
|
|
30
|
+
### Android
|
|
31
|
+
|
|
32
|
+
Android 蓝牙权限已经随插件一起分发并参与宿主 Manifest 合并,通常不需要宿主项目再手写:
|
|
33
|
+
|
|
34
|
+
- `BLUETOOTH`、`BLUETOOTH_ADMIN`,并带 `maxSdkVersion=30`
|
|
35
|
+
- `BLUETOOTH_CONNECT`
|
|
36
|
+
- `BLUETOOTH_SCAN`,并带 `neverForLocation`
|
|
37
|
+
|
|
38
|
+
体验约定:
|
|
39
|
+
|
|
40
|
+
- 首次调用 `discoverDevices()` 时,插件会自动触发“附近设备”权限申请
|
|
41
|
+
- 也可以先主动调用 `ensurePermissions()`,拿到结构化权限状态后再决定是否继续
|
|
42
|
+
- 如果用户永久拒绝权限,可调用 `openAppSettings()` 引导跳转系统设置页
|
|
43
|
+
|
|
44
|
+
### iOS
|
|
45
|
+
|
|
46
|
+
宿主项目需要在自己的 `Info.plist` 中补充蓝牙用途说明:
|
|
47
|
+
|
|
48
|
+
```xml
|
|
49
|
+
<key>NSBluetoothAlwaysUsageDescription</key>
|
|
50
|
+
<string>App 需要连接蓝牙标签打印机以打印物流面单与条码标签</string>
|
|
51
|
+
<key>NSBluetoothPeripheralUsageDescription</key>
|
|
52
|
+
<string>App 需要访问蓝牙设备以完成标签打印</string>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 快速使用
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { CpclBuilder, LabelPrinter } from '@m430/capacitor-label-printer';
|
|
59
|
+
|
|
60
|
+
async function printDemoLabel() {
|
|
61
|
+
const support = await LabelPrinter.isSupported();
|
|
62
|
+
if (!support.supported) {
|
|
63
|
+
throw new Error('当前平台不支持原生标签打印');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const permissionResult = await LabelPrinter.ensurePermissions();
|
|
67
|
+
if (!permissionResult.granted) {
|
|
68
|
+
if (permissionResult.shouldOpenSettings) {
|
|
69
|
+
await LabelPrinter.openAppSettings();
|
|
70
|
+
}
|
|
71
|
+
throw new Error('需要先允许蓝牙附近设备权限');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { devices } = await LabelPrinter.discoverDevices({
|
|
75
|
+
namePrefixes: ['QR', 'QIRUI', 'BEEPRT']
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!devices.length) {
|
|
79
|
+
throw new Error('没有找到可用打印机');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await LabelPrinter.connect({ deviceId: devices[0].id });
|
|
83
|
+
|
|
84
|
+
const payload = new CpclBuilder()
|
|
85
|
+
.page(640, 1)
|
|
86
|
+
.pageWidth(576)
|
|
87
|
+
.text(4, 0, 40, 40, 'YT1234567890')
|
|
88
|
+
.barcode128(40, 120, 80, 'YT1234567890')
|
|
89
|
+
.form()
|
|
90
|
+
.print()
|
|
91
|
+
.build();
|
|
92
|
+
|
|
93
|
+
await LabelPrinter.print({
|
|
94
|
+
payload,
|
|
95
|
+
language: 'cpcl',
|
|
96
|
+
copies: 1
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const status = await LabelPrinter.getStatus();
|
|
100
|
+
console.log(status);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## API 概览
|
|
105
|
+
|
|
106
|
+
插件当前公开这些方法:
|
|
107
|
+
|
|
108
|
+
- `isSupported`
|
|
109
|
+
- `checkPermissions`
|
|
110
|
+
- `ensurePermissions`
|
|
111
|
+
- `discoverDevices`
|
|
112
|
+
- `connect`
|
|
113
|
+
- `disconnect`
|
|
114
|
+
- `getConnectionState`
|
|
115
|
+
- `print`
|
|
116
|
+
- `getStatus`
|
|
117
|
+
- `openAppSettings`
|
|
118
|
+
|
|
119
|
+
完整 API 文档见 [API.md](./API.md)。
|
|
120
|
+
|
|
121
|
+
## Helper
|
|
122
|
+
|
|
123
|
+
已内置 `CpclBuilder`、`TsplBuilder` 与基础 helper,适合物流面单、条码标签这类“一张一张打”的场景:
|
|
124
|
+
|
|
125
|
+
- `page`
|
|
126
|
+
- `pageWidth`
|
|
127
|
+
- `sizeMm`
|
|
128
|
+
- `gapMm`
|
|
129
|
+
- `density`
|
|
130
|
+
- `speed`
|
|
131
|
+
- `cls`
|
|
132
|
+
- `text`
|
|
133
|
+
- `barcode128`
|
|
134
|
+
- `qrcode`
|
|
135
|
+
- `printCopies`
|
|
136
|
+
|
|
137
|
+
## 平台说明
|
|
138
|
+
|
|
139
|
+
### Android
|
|
140
|
+
|
|
141
|
+
- 当前集成的是厂商 `TSPL classic bluetooth` 方向的 `jar`
|
|
142
|
+
- 插件包内已带上 `android/libs/fat-generic-tspl-bluetooth-classic-0.1.16-GA.jar`
|
|
143
|
+
- 现阶段 `discoverDevices` 主要基于已配对设备过滤,适合作为 `QR-365` 的首版接入基线
|
|
144
|
+
- `discoverDevices()` 与 `connect()` 会在 Android 12+ 自动兜底附近设备权限
|
|
145
|
+
|
|
146
|
+
### iOS
|
|
147
|
+
|
|
148
|
+
- 当前包内已带上 `ios/VendorFrameworks/` 下的厂商 `framework`
|
|
149
|
+
- `CocoaPods` 集成使用的是 `M430CapacitorLabelPrinter.podspec`
|
|
150
|
+
- 已验证 `npx cap sync ios` 与 `xcodebuild` 编译链路可通过
|
|
151
|
+
- iOS 仍需要宿主在 `Info.plist` 中声明蓝牙用途说明
|
|
152
|
+
|
|
153
|
+
### Web
|
|
154
|
+
|
|
155
|
+
- 不支持
|
|
156
|
+
- `isSupported()` 返回 `false`
|
|
157
|
+
- 其余原生能力会抛出 `Label printing is not supported on web.`
|
|
158
|
+
|
|
159
|
+
## 开发与发布校验
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npm run verify
|
|
163
|
+
npm run verify:ios
|
|
164
|
+
npm run verify:release
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
其中:
|
|
168
|
+
|
|
169
|
+
- `verify` 会执行单测、Android Gradle 构建和插件打包
|
|
170
|
+
- `verify:ios` 会执行 `example-app` 的 `cap sync ios` 与 `xcodebuild`
|
|
171
|
+
- `verify:release` 会串起完整发布前检查,并执行 `npm pack --dry-run`
|
|
172
|
+
|
|
173
|
+
## 已随包分发的原生资源
|
|
174
|
+
|
|
175
|
+
- Android `jar`
|
|
176
|
+
- iOS `framework`
|
|
177
|
+
- iOS `podspec`
|
|
178
|
+
|
|
179
|
+
宿主项目安装后不需要再单独下载一份厂商 SDK。
|
|
180
|
+
|
|
181
|
+
## 已知限制
|
|
182
|
+
|
|
183
|
+
- 当前版本以“统一 API + 原生依赖分发 + 构建链路打通”为主
|
|
184
|
+
- Android 与 iOS 的真实打印链路还需要按厂商 SDK 文档继续接入
|
|
185
|
+
- 还没有内置打印队列、自动重连、模板编辑器和图片调试工具
|
|
186
|
+
|
|
187
|
+
## 仓库
|
|
188
|
+
|
|
189
|
+
- GitHub: `https://github.com/m430/capacitor-label-printer`
|
|
190
|
+
- npm: `@m430/capacitor-label-printer`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
buildscript {
|
|
6
|
+
repositories {
|
|
7
|
+
google()
|
|
8
|
+
mavenCentral()
|
|
9
|
+
}
|
|
10
|
+
dependencies {
|
|
11
|
+
classpath 'com.android.tools.build:gradle:8.7.3'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
apply plugin: 'com.android.library'
|
|
16
|
+
|
|
17
|
+
android {
|
|
18
|
+
namespace "com.m430.capacitor.labelprinter"
|
|
19
|
+
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
|
|
20
|
+
defaultConfig {
|
|
21
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
|
22
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
|
|
23
|
+
versionCode 1
|
|
24
|
+
versionName "0.1.0"
|
|
25
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
26
|
+
}
|
|
27
|
+
lintOptions {
|
|
28
|
+
abortOnError false
|
|
29
|
+
}
|
|
30
|
+
compileOptions {
|
|
31
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
32
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
repositories {
|
|
37
|
+
google()
|
|
38
|
+
mavenCentral()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
dependencies {
|
|
42
|
+
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
|
43
|
+
implementation project(':capacitor-android')
|
|
44
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
45
|
+
testImplementation fileTree(dir: 'gradle/test-libs', include: ['*.jar'])
|
|
46
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
<uses-permission
|
|
3
|
+
android:name="android.permission.BLUETOOTH"
|
|
4
|
+
android:maxSdkVersion="30" />
|
|
5
|
+
<uses-permission
|
|
6
|
+
android:name="android.permission.BLUETOOTH_ADMIN"
|
|
7
|
+
android:maxSdkVersion="30" />
|
|
8
|
+
<uses-permission
|
|
9
|
+
android:name="android.permission.BLUETOOTH_SCAN"
|
|
10
|
+
android:usesPermissionFlags="neverForLocation" />
|
|
11
|
+
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
12
|
+
</manifest>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
package com.m430.capacitor.labelprinter;
|
|
2
|
+
|
|
3
|
+
import com.getcapacitor.JSArray;
|
|
4
|
+
import com.getcapacitor.JSObject;
|
|
5
|
+
import java.io.IOException;
|
|
6
|
+
import java.nio.charset.StandardCharsets;
|
|
7
|
+
import java.util.List;
|
|
8
|
+
|
|
9
|
+
public class AndroidPrinterManager {
|
|
10
|
+
interface DeviceCatalog {
|
|
11
|
+
JSArray discover(List<String> prefixes);
|
|
12
|
+
|
|
13
|
+
PrinterSession openSession(String deviceId);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface PrinterSession {
|
|
17
|
+
void connect() throws IOException;
|
|
18
|
+
|
|
19
|
+
void disconnect();
|
|
20
|
+
|
|
21
|
+
boolean isConnected();
|
|
22
|
+
|
|
23
|
+
String getConnectionState();
|
|
24
|
+
|
|
25
|
+
String getDeviceName();
|
|
26
|
+
|
|
27
|
+
void print(String language, byte[] payload) throws IOException;
|
|
28
|
+
|
|
29
|
+
byte[] queryStatus() throws IOException;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private final DeviceCatalog deviceCatalog;
|
|
33
|
+
private final AndroidStatusMapper statusMapper;
|
|
34
|
+
private PrinterSession session;
|
|
35
|
+
private String connectedDeviceId;
|
|
36
|
+
|
|
37
|
+
public AndroidPrinterManager(DeviceCatalog deviceCatalog, AndroidStatusMapper statusMapper) {
|
|
38
|
+
this.deviceCatalog = deviceCatalog;
|
|
39
|
+
this.statusMapper = statusMapper;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public JSArray getBondedDevices(List<String> prefixes) {
|
|
43
|
+
return deviceCatalog.discover(prefixes);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public void connect(String deviceId) throws IOException {
|
|
47
|
+
if (deviceId == null || deviceId.trim().isEmpty()) {
|
|
48
|
+
throw new IllegalArgumentException("deviceId is required");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
PrinterSession nextSession = deviceCatalog.openSession(deviceId);
|
|
52
|
+
if (nextSession == null) {
|
|
53
|
+
throw new IllegalArgumentException("printer device not found: " + deviceId);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
disconnect();
|
|
57
|
+
nextSession.connect();
|
|
58
|
+
session = nextSession;
|
|
59
|
+
connectedDeviceId = deviceId;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public void disconnect() {
|
|
63
|
+
if (session != null) {
|
|
64
|
+
session.disconnect();
|
|
65
|
+
}
|
|
66
|
+
session = null;
|
|
67
|
+
connectedDeviceId = null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public void print(String payload, String language, int copies) throws IOException {
|
|
71
|
+
if (payload == null || payload.isEmpty()) {
|
|
72
|
+
throw new IllegalArgumentException("payload is empty");
|
|
73
|
+
}
|
|
74
|
+
PrinterSession activeSession = requireSession();
|
|
75
|
+
activeSession.print(language, payload.repeat(Math.max(copies, 1)).getBytes(StandardCharsets.UTF_8));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public JSObject getConnectionState() {
|
|
79
|
+
JSObject state = new JSObject();
|
|
80
|
+
state.put("state", session == null ? "disconnected" : session.getConnectionState());
|
|
81
|
+
return state;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public JSObject getStatus() {
|
|
85
|
+
if (session == null || !session.isConnected()) {
|
|
86
|
+
return statusMapper.disconnected("disconnected");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
JSObject status = statusMapper.toPluginStatus(true, AndroidStatusMapper.STATE_READY, "ready");
|
|
90
|
+
status.put("deviceId", connectedDeviceId);
|
|
91
|
+
status.put("deviceName", session.getDeviceName());
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
byte[] response = session.queryStatus();
|
|
95
|
+
if (response != null && response.length > 0) {
|
|
96
|
+
String rawText = new String(response, StandardCharsets.UTF_8).trim();
|
|
97
|
+
if (!rawText.isEmpty()) {
|
|
98
|
+
status.put("raw", rawText);
|
|
99
|
+
status.put("message", rawText);
|
|
100
|
+
applyStatusHints(status, rawText);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch (IOException exception) {
|
|
104
|
+
status.put("message", exception.getMessage());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return status;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private PrinterSession requireSession() {
|
|
111
|
+
if (session == null || !session.isConnected()) {
|
|
112
|
+
throw new IllegalStateException("printer is not connected");
|
|
113
|
+
}
|
|
114
|
+
return session;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private void applyStatusHints(JSObject status, String rawText) {
|
|
118
|
+
String normalized = rawText.toUpperCase();
|
|
119
|
+
if (normalized.contains("PAPER")) {
|
|
120
|
+
status.put("ready", false);
|
|
121
|
+
status.put("paperOut", true);
|
|
122
|
+
}
|
|
123
|
+
if (normalized.contains("COVER") || normalized.contains("OPEN")) {
|
|
124
|
+
status.put("ready", false);
|
|
125
|
+
status.put("coverOpen", true);
|
|
126
|
+
}
|
|
127
|
+
if (normalized.contains("HEAT")) {
|
|
128
|
+
status.put("ready", false);
|
|
129
|
+
status.put("overheating", true);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
package com.m430.capacitor.labelprinter;
|
|
2
|
+
|
|
3
|
+
import com.getcapacitor.JSObject;
|
|
4
|
+
import org.json.JSONException;
|
|
5
|
+
|
|
6
|
+
public class AndroidStatusMapper {
|
|
7
|
+
public static final int STATE_UNKNOWN = -1;
|
|
8
|
+
public static final int STATE_READY = 0;
|
|
9
|
+
public static final int STATE_PAPER_OUT = 1;
|
|
10
|
+
public static final int STATE_COVER_OPEN = 2;
|
|
11
|
+
public static final int STATE_OVERHEATING = 3;
|
|
12
|
+
|
|
13
|
+
public JSObject toPluginStatus(boolean connected, int stateCode, String message) {
|
|
14
|
+
String messageValue = message == null
|
|
15
|
+
? "null"
|
|
16
|
+
: "\"" + message.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
|
|
17
|
+
String payload = "{"
|
|
18
|
+
+ "\"connected\":" + connected + ","
|
|
19
|
+
+ "\"ready\":" + (stateCode == STATE_READY) + ","
|
|
20
|
+
+ "\"paperOut\":" + (stateCode == STATE_PAPER_OUT) + ","
|
|
21
|
+
+ "\"coverOpen\":" + (stateCode == STATE_COVER_OPEN) + ","
|
|
22
|
+
+ "\"overheating\":" + (stateCode == STATE_OVERHEATING) + ","
|
|
23
|
+
+ "\"message\":" + messageValue + ","
|
|
24
|
+
+ "\"raw\":" + stateCode
|
|
25
|
+
+ "}";
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
return new JSObject(payload);
|
|
29
|
+
} catch (JSONException exception) {
|
|
30
|
+
throw new IllegalStateException("Failed to map printer status", exception);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public JSObject disconnected(String message) {
|
|
35
|
+
String messageValue = message == null
|
|
36
|
+
? "null"
|
|
37
|
+
: "\"" + message.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
|
|
38
|
+
String payload = "{"
|
|
39
|
+
+ "\"connected\":false,"
|
|
40
|
+
+ "\"ready\":false,"
|
|
41
|
+
+ "\"paperOut\":false,"
|
|
42
|
+
+ "\"coverOpen\":false,"
|
|
43
|
+
+ "\"overheating\":false,"
|
|
44
|
+
+ "\"message\":" + messageValue + ","
|
|
45
|
+
+ "\"raw\":null"
|
|
46
|
+
+ "}";
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
return new JSObject(payload);
|
|
50
|
+
} catch (JSONException exception) {
|
|
51
|
+
throw new IllegalStateException("Failed to map disconnected printer status", exception);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|