更新记录

1.0.0(2026-10-26)

首个版本:SPP 连接管理、Android 12+ 权限适配、打印任务队列与超时保护、TSPL 指令生成(五种标签元素、六种条码)、JSON 模板体系、内置固定资产与仓库货位模板、指令预览调试、Demo 工程、43 项指令生成自动化测试。


平台兼容性

uni-app

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× √ - - √ × √ - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

szhzy-labelprint 蓝牙 TSPL 工业标签打印插件

面向固定资产管理、仓库管理、设备管理、生产制造与零售系统的 Android 蓝牙标签打印 UTS 插件。

通过 Bluetooth Classic SPP(串口) 通道向 TSPL / TSPL2 协议标签打印机发送指令,提供从权限检测、设备连接到任务队列的完整打印链路,以及 JSON 标签模板体系(文本 / 条码 / 二维码 / 直线 / 方框)与指令预览调试能力。

内置固定资产标签与仓库货位标签两套开箱即用的模板,Demo 工程包含设备配对连接、模板选择、打印参数设置、打印日志四个完整页面。


⚠️ 购买前必读

  1. 本插件仅支持 Android App 平台(面向传统 uni-app Vue3 项目开发与验证;uni-app x 端按兼容模式编写但未实测)。iOS、鸿蒙、Web、小程序均不支持,请确认你的业务平台后再购买。
  2. 仅支持 TSPL / TSPL2 协议 + 蓝牙 Classic SPP 的打印机。不支持 ESC/POS(小票)、CPCL、ZPL 协议,不支持 BLE(低功耗蓝牙)-only 设备。常见适配目标见插件内《设备兼容说明》。
  3. 打印中文需要打印机内置中文字库(如 TSS24.BF2)。绝大多数中国市场主流 TSPL 桌面机内置简体中文字库,但部分海外版机型没有,购买前建议先用 Demo 工程在你的打印机上实测。
  4. 诚实的验证状态:指令生成核心逻辑已经过 43 项自动化测试(含两套内置模板的完整输出比对);但蓝牙通道与设备端物理打印未经本插件作者真机验证(开发期无打印机),购买后请先在 Demo 工程中完成真机自测,若有不适配可联系作者处理。
  5. 付费版授权与打包规则(DCloud 市场机制):本插件为付费插件,由插件市场自动加密——普通授权版买家不可见插件源码,需要阅读或修改源码请购买源码授权版;加密插件仅支持云端传统打包,不支持离线打包与安心打包;试用版仅可用于打包自定义基座调试,不能用于正式发布;授权绑定 AppID 与包名,购买后更换任一信息需重新购买授权。

环境要求

项 要求
HBuilderX 3.99+(建议使用最新 4.x 版本)
项目类型 uni-app(Vue3,主要支持目标);uni-app x(兼容模式编写,未实测)
Android 最低版本 6.0(API 23)
打印机 支持蓝牙 SPP 的 TSPL/TSPL2 协议标签打印机(203/300/600 dpi)
其他 无第三方原生 SDK 依赖,无需申请任何厂商授权

真机运行提示:UTS 插件不能在 HBuilderX 标准基座上直接运行。导入插件后,请在 HBuilderX 中执行「运行 → 运行到手机或模拟器 → 制作自定义基座」,基座制作完成后选择「使用自定义基座运行」;正式打包请使用云打包。Android 编译环境配置见 DCloud 官方文档《uts插件Android运行配置》。

快速开始

1. 安装与权限

通过 HBuilderX 导入插件到项目的 uni_modules 目录。插件已自带 utssdk/app-android/AndroidManifest.xml 声明蓝牙权限,云打包时自动合并;如你的项目需要显式管理权限,也可在 manifest.json -> app-plus -> distribute -> android -> permissions 中添加:

"permissions": [
    "<uses-permission android:name=\"android.permission.BLUETOOTH\" android:maxSdkVersion=\"30\"/>",
    "<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" android:maxSdkVersion=\"30\"/>",
    "<uses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\"/>"
]

Android 12+ 的 BLUETOOTH_CONNECT 为运行时权限,插件内部会在连接前检查并引导申请(见 requestBluetoothPermission())。

2. 连接打印机并打印

import {
  requestBluetoothPermission, getPairedDevices, connect,
  getTemplates, printTemplate, getConnectionInfo
} from '@/uni_modules/szhzy-labelprint'

// ① 确保蓝牙权限(Android 12+ 需要;打印机需先在系统蓝牙设置中完成配对)
const perm = await requestBluetoothPermission()
if (!perm.ok) {
  uni.showToast({ title: perm.message, icon: 'none' })
  return
}

// ② 获取已配对设备并连接(SPP)
const devices = await getPairedDevices()
if (!devices.ok) {
  uni.showToast({ title: devices.message, icon: 'none' })
  return
}
const printer = devices.devices[0] // { name, address }

const conn = await connect({ address: printer.address, timeout: 8000, secure: true })
if (!conn.ok) {
  uni.showToast({ title: conn.message, icon: 'none' })
  return
}

// ③ 使用内置固定资产模板打印
const tplRes = getTemplates()
const asset = tplRes.templates.find(t => t.id === 'asset')
const template = JSON.parse(asset.json)

const result = await printTemplate(template, {
  company: 'XX科技有限公司',
  assetCode: 'ZC-2026-0001',
  assetName: '贴片机 SM-482',
  spec: 'YSM-482/V2',
  dept: '生产一部',
  date: '2026-01-15'
}, { copies: 1, density: 8 })

if (result.ok) {
  // ok 仅代表指令字节流已写入蓝牙连接(详见下文「结果语义」)
  console.log(`已写入 ${result.bytes} 字节,耗时 ${result.elapsed}ms`)
} else {
  console.error(`[${result.code}] ${result.message}`)
}

也可用 printLabel(label) 直接按标签描述对象打印,或用 printCommand(command) 发送你自行拼接的原始 TSPL 指令。

API 参考

所有异步 API 返回 Promise<UTSJSONObject>,统一信封结构,不通过 reject 抛业务错误:

{ ok: boolean, code: string, message: string, ...业务字段 }

权限与系统

API 说明 返回
checkBluetoothPermission() 同步检查蓝牙权限状态 { granted, needRequest, message }
requestBluetoothPermission() 申请 Android 12+ 运行时权限 { ok, code, message, granted, doNotAskAgain? }
openBluetoothSettings() 跳转系统蓝牙设置页(配对入口) 无
getAdapterState() 蓝牙适配器状态 { state: "on" / "off" / "unavailable" }

设备与连接

API 说明 返回
getPairedDevices() 已配对蓝牙设备列表(需权限) { ok, code, message, devices: [{ name, address }] }
connect(options) 建立 SPP 连接 { ok, code, message, address?, deviceName?, elapsed? }
disconnect() 断开连接(幂等) { ok, code, message }
getConnectionInfo() 当前连接信息(同步) { state, address, deviceName }

connect 参数:

字段 类型 必填 说明
address string 是 已配对设备的 MAC 地址
timeout number 否 连接超时毫秒,默认 8000,范围 1000-60000
secure boolean 否 是否使用加密 RFCOMM,默认 true;部分入门机型连接失败时可尝试 false

连接语义:重复 connect 同一地址且当前已连接时幂等返回成功;连接其他地址时会先断开旧连接再连接新设备。

模板与指令生成

API 说明 返回
getTemplates() 内置模板元信息 + 完整 JSON { ok, code, message, templates: [...] }
getTemplateJson(id) 按 ID 取模板 JSON 文本 string \| null
buildLabelCommand(label, vars?) 按标签描述生成指令(不发送) { ok, code, message, command, warnings, encoding }
renderTemplateCommand(template, vars?, overrides?) 渲染模板生成指令(不发送) 同上
inspectTemplateText(text) 校验模板 JSON 文本并返回元信息 { ok, code, message, template? }

打印与队列

API 说明 返回
printTemplate(template, vars?, overrides?) 渲染模板并打印(入队) PrintResult
printLabel(label, vars?, options?) 按标签描述打印(入队) PrintResult
printCommand(command, options?) 发送原始 TSPL 指令(入队) PrintResult
getQueueInfo() 队列与连接信息(同步) { pending, connection }
cancelPendingTasks() 取消全部待执行任务(同步) { cancelled }

PrintResult:

{
  ok: boolean,          // true = 指令字节流已完整写入蓝牙连接
  code: string,
  message: string,
  taskId: string,       // 任务 ID
  bytes: number,        // 写入字节数
  elapsed: number,      // 耗时 ms
  pending: number,      // 执行后队列剩余任务数
  physicalPrintConfirmed: false  // 恒为 false,见「结果语义」
}

错误码

code 含义 建议处理
SUCCESS 成功 -
INVALID_PARAM 参数缺失或非法 检查调用参数
INVALID_TEMPLATE 标签/模板结构校验失败 查看 message 中的具体字段提示
PERMISSION_DENIED 蓝牙权限被拒绝 引导用户授权或前往系统设置
BLUETOOTH_OFF 系统蓝牙未开启 引导开启蓝牙
BLUETOOTH_UNAVAILABLE 蓝牙适配器不可用 设备不支持或系统异常
NO_ACTIVITY 无法获取当前 Activity 环境异常,重启页面
CONNECT_TIMEOUT 连接超时 检查打印机开机/距离,或调大 timeout
CONNECT_FAILED 连接失败 尝试 secure:false、重新配对
NOT_CONNECTED 没有可用连接 先调用 connect()
WRITE_TIMEOUT 写入超时(连接已断开) 重新连接后重试
WRITE_FAILED 写入失败(连接已断开) 重新连接后重试
TASK_CANCELLED 任务执行前被取消 -

JSON 标签模板规范

模板即数据,业务系统可以下发任意符合规范的模板 JSON。

{
  "id": "asset",
  "name": "固定资产标签",
  "width": 60, "height": 40, "gap": 2, "dpi": 203,
  "density": 8, "speed": 3, "direction": 1, "encoding": "gbk",
  "vars": [ { "key": "assetCode", "label": "资产编号", "sample": "ZC-2026-0001" } ],
  "elements": [
    { "type": "box", "x": 1, "y": 1, "width": 58, "height": 38, "thickness": 2 },
    { "type": "text", "x": 3, "y": 3, "content": "{{company}}", "font": "TSS24.BF2" },
    { "type": "barcode", "x": 3, "y": 20.6, "barcodeType": "CODE128", "height": 7, "readable": 0, "content": "{{assetCode}}" },
    { "type": "qrcode", "x": 36, "y": 2.2, "content": "{{qrData}}", "ecc": "H", "cellSize": 4 }
  ]
}

标签级字段

字段 类型 默认 说明
width / height number 必填 标签宽高(毫米),范围 1-300 / 1-600
gap number 2 标签间隙(毫米)
dpi number 203 打印机分辨率:203 / 300 / 600(换算 8 / 12 / 24 点每毫米)
density number 8 打印浓度 0-15
speed number 3 打印速度 1-5(英寸/秒;部分入门机型仅支持 1-4)
copies number 1 打印张数 1-999
direction number 1 打印方向 0 / 1
encoding string gbk 指令文本编码:gbk / utf8 / ascii
vars array - 变量元信息(供业务系统渲染表单),打印逻辑只认 {{key}} 占位符
elements array 必填 标签元素,至少 1 个

元素字段

单位约定:坐标与几何尺寸用毫米(按 dpi 换算为打印点);字高、条码宽窄、二维码单元、方框线宽用打印点。

type 字段
text x, y(毫米);content(必填,支持 {{var}});font(默认 "TSS24.BF2",可缩放字体用 "0");fontHeight(font 为 "0" 时的字高,打印点,默认 24);rotation(0/90/180/270);xmul, ymul(放大倍数 1-8)
barcode x, y;content(必填);barcodeType(CODE128/CODE39/EAN13/EAN8/UPCA/UPCE,默认 CODE128);height(毫米,默认 10);readable(0/1 或 true/false,人眼可读);rotation;narrow, wide(打印点,CODE39 默认 2/5,其余 2/2)
qrcode x, y;content(必填);ecc(L/M/Q/H,默认 H);cellSize(1-10,默认 4);rotation;model(M1/M2,默认 M2);mask(S0-S8,默认 S7)
line x, y, width(毫米);height(毫米,即线宽,最小 1 个打印点)
box x, y, width, height(毫米);thickness(打印点,默认 2,范围 1-20)

校验行为

  • 报错(INVALID_TEMPLATE):必填字段缺失、数值越界超限、条码字符集/长度/校验位不符、dpi/编码非法等,错误信息会指明 elements[i].字段 位置;
  • 警告(warnings,不阻断):可选字段越界自动收敛(如 density 超出 0-15)、变量缺失替换为空串、坐标超出标签范围等;
  • 内容中的双引号、回车、换行、制表符会被替换为空格,防止破坏 TSPL 指令结构;变量值中的 {{ }} 不会二次展开(单趟替换,防注入)。

printTemplate 的 overrides

density / speed / copies / gap / direction / encoding / timeout 可在调用时覆盖模板定义;width / height / dpi 属于版式定义不允许覆盖(会得到警告并被忽略),避免坐标体系与标签尺寸不匹配的错版输出。

打印任务队列

  • 所有连接与写入操作在单一后台线程串行执行,多个打印请求并发提交时按 FIFO 顺序写同一条连接,不会出现交叉写坏的指令流;
  • 每个任务有写入超时保护(默认 10000ms),超时后强制关闭 socket,任务以 WRITE_TIMEOUT 失败返回,不会卡死队列;
  • 已入队未执行的任务可通过 cancelPendingTasks() 取消;正在执行中的任务不可中断;
  • 写入失败(超时或异常)会立即释放连接资源,后续任务返回 NOT_CONNECTED,避免在半开连接上无效重试。

重要:结果语义(请务必阅读)

TSPL 协议在 SPP 蓝牙通道上是单向指令流:打印机收到指令后开始打印,但不会回传“物理打印完成”状态(这也是市面同类插件的通行情况)。

因此本插件的打印结果做了严格区分:

  • ok = true 的含义是指令字节流已完整写入蓝牙连接(含 flush);
  • physicalPrintConfirmed 恒为 false——本插件不会虚报物理打印成功;
  • 缺纸、打印头开盖、碳带耗尽等发生在“写入成功之后”的异常无法通过本协议感知,需要业务方通过实物核对或后续校验流程兜底。

如果你的业务必须确认物理打印结果,建议的落地做法:打印后人工/扫码核对标签,或在流程上采用「打印 → 贴标 → 扫码确认」闭环。

指令预览与调试

renderTemplateCommand / buildLabelCommand 返回完整 TSPL 指令文本(不发送),可用于:

  • 业务系统在界面上展示指令(Demo 的「预览 TSPL 指令」弹层即此用法);
  • 离线排查模板问题(配合 warnings 逐条修正);
  • 把指令交由其他通道发送(如串口、网络打印机网关),printCommand(command) 支持直发原始指令。

常见问题

Q:连接报 CONNECT_FAILED / read failed, socket might closed? 先确认打印机已开机、已与手机在系统蓝牙设置中完成配对;再尝试 secure: false(部分入门机型蓝牙模块协商不稳定);仍失败则删除配对后重新配对。

Q:中文打印乱码或空白? 打印机缺少中文字库(TSS24.BF2 等)或编码不匹配。中国市场主流 TSPL 桌面机一般内置简体中文字库并按 GBK 解码(插件默认 encoding: gbk);若你的机型字库为 UTF-8 解码,将模板 encoding 设为 utf8。无中文字库的机型请把中文内容改为 ASCII(如拼音/编号),或反馈作者评估位图方案。

Q:条码打印出来了但扫不出来? 检查内容是否符合编码规则(EAN13 需 12/13 位且校验位正确,CODE39 仅支持大写字母数字与 -. $/+%,CODE128 仅支持 ASCII 32-126);条码高度建议不低于 7mm;CODE39 保持默认宽窄比 2:5。

Q:打印速度设置 4/5 没生效? 部分入门机型 SPEED 仅支持 1-4,超出范围会被打印机按自身上限处理,请按机型说明书设置。

Q:Android 12 以下还需要申请权限吗? 不需要。Android 11 及以下蓝牙为安装即授予的普通权限;Android 12+ 才需要运行时申请 BLUETOOTH_CONNECT,插件已内置检测与申请。

Q:支持 uni-app x 吗? 插件 API 统一以 UTSJSONObject 交互,代码按 uni-app 与 uni-app x 的兼容模式编写;但当前仅在传统 uni-app(Vue3)上完成设计与指令级验证,uni-app x 端未实测(市场平台声明中标注为不确定)。在 x 项目中使用请先自行评估,其他平台端请用条件编译包裹导入。

技术支持

  • 使用问题与机型适配反馈请通过插件市场页面联系作者;
  • 反馈时请提供:机型与打印机型号、HBuilderX 版本、调用代码片段、code/message 与完整日志。

更新记录

见 changelog.md。设备兼容范围见《设备兼容说明.md》,授权条款见 license.md。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

BLUETOOTH、BLUETOOTH_ADMIN(Android 11 及以下自动授予);BLUETOOTH_CONNECT(Android 12 及以上运行时申请)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据,蓝牙连接与打印全部在设备本地完成,不访问网络

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。