更新记录
1.0.1(2026-07-31)
- 优化
- 更新文档
1.0.0(2026-07-31)
- 新版发布
平台兼容性
uni-app(5.01)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | × | × | 5.0 | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(5.01)
| Chrome | Safari | Android | Android插件版本 | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|---|
| × | × | 5.0 | 1.0.0 | × | × | × |
yt-usbscan
Android USB / 蓝牙 HID 扫码枪后台监听插件(UTS)。
兼容 uni-app 与 uni-app x。无需输入框、无需焦点、无需弹出软键盘。
特别提醒
- 购买本插件前,请先试用,请先试用,请先试用,确认满足需求之后再行购买。虚拟物品一旦购买之后无法退款。
- 如有使用上的疑问、bug,可以进交流群联系作者;
- 请在合法范围内使用,若使用本插件做非法开发,本方概不负责;
- 插件需先引入再打自定义基座后运行测试
平台
| 项目类型 | Android | iOS | Harmony |
|---|---|---|---|
| uni-app(vue/nvue) | √ | - | - |
| uni-app x | √ | - | - |
建议 HBuilderX 4.27+(原生混编 Kotlin;@UTSJS.keepAlive 需 4.27+)。
API
setOnScanListener(options)
启动后台静默扫码监听。
| 字段 | 类型 | 说明 |
|---|---|---|
| interCharTimeoutMs | number? | 字符间隔阈值(ms),默认 100。详见下方说明 |
| finishTimeoutMs | number? | 无结束符时的静默提交超时(ms),默认 120;传 0 关闭。详见下方说明 |
| onScanSuccess | (res) => void | 成功回调,res.code 为扫码内容 |
| fail | (err) => void | 失败回调 |
| complete | (res) => void | 结束回调 |
removeOnScanListener()
停止监听并恢复原始 Window.Callback。
isScanListening()
是否正在监听。
拼码超时参数说明
扫码枪在 HID 键盘模式下,会把条码模拟成一串极快的按键。插件用缓冲拼码,依赖下面两个时间参数区分「同一次扫码 / 下一次扫码 / 是否该提交」。
interCharTimeoutMs(字符间隔阈值)
作用: 两次按键间隔若超过该值,丢弃当前缓冲,当作新一次扫码开始。用来区分扫码枪的极速输入和人手慢速打字,也避免半截旧码与下一次扫码粘在一起。
怎么设:
| 场景 | 建议值 | 说明 |
|---|---|---|
| 多数有线 USB 扫码枪 | 100(默认) |
一般无需改 |
| 枪很快、码很短 | 50~80 |
更严格,更不易把慢打字当成扫码 |
| 蓝牙 / 无线枪、偶发卡顿 | 150~250 |
间隔偶发变大时,避免一次扫码被拆成两段 |
| 同屏还有实体键盘输入 | 保持偏小(如 80~100) |
降低把人手输入拼进条码的概率 |
设错了会怎样:
- 过大(如
500):人手慢打、误触也可能被拼进缓冲,出现「乱码 / 把键盘输入当扫码」 - 过小(如
20):无线延迟或个别慢枪会导致一次扫码被拆成多次短结果,或中间被清空丢码
finishTimeoutMs(无结束符时的静默提交)
作用: 每追加一个有效字符后重置定时器;若在超时内没有新字符、也没收到 Enter(或 \n/\r),就把当前缓冲当作一次完整扫码提交。用于兼容未配置扫码后缀 Enter 的设备。传 0 关闭该逻辑,只认结束符才提交。
怎么设:
| 场景 | 建议值 | 说明 |
|---|---|---|
| 扫码枪已开启后缀 Enter(推荐) | 120(默认)或 0 |
有 Enter 时主要靠结束符提交;0 可彻底关掉静默提交 |
| 枪未开 Enter / 无法改配置 | 100~200 |
必须靠静默超时出结果;宜略大于枪的字符间隔 |
| 只要「绝对完整、宁可不出」 | 0 |
强制要求设备发 Enter,否则永不自动提交 |
设错了会怎样:
- 过大(如
800):无 Enter 时结果出来很慢;若用户紧接着再扫一次,还可能把两次码拼在一起 - 过小(如
30):枪还没打完整个条码就提前提交 → 结果被截断 - 在未开 Enter 时设为
0:永远等不到结束符 → 一直无回调
两个参数的关系(简记)
| 参数 | 超时后做什么 |
|---|---|
interCharTimeoutMs |
间隔太大 → 丢弃旧缓冲,准备接新扫码 |
finishTimeoutMs |
静默一段时间 → 提交当前缓冲 |
推荐优先在扫码枪上开启 Enter 后缀,超时参数保持默认即可。仅当出现「拆码 / 粘码 / 截断 / 无回调」时,再按上表微调。
更多好用插件推荐
- 高德定位连续定位后台定位保活定位
- 百度汽车摩托车导航插件
- 百度鹰眼轨迹插件支持后台采集、保活
- 百度定位插件、连续定位、保活、坐标系转换、支持双端
- 计步器插件,支持Android、iOS双端
- uts经典蓝牙插件、蓝牙电子秤
- 获取唯一标识、ServiceID、卸载更新不变iOS+Android
- Android经典蓝牙
- 华为ScanKit统一扫码插件支持iOS+Android原生插件
- 【华为扫码】统一扫码插件支持多码连续扫码支持半屏扫码uts插件iOS+Android+HarmonyOS
- 截屏、录屏、防截屏、录屏iOS、Android
- 人脸采集插件 最新百度SDK 离线人脸采集、活体检测
- 页面截长图、截取WebView内容,生成长截图Android+iOS
- Android无预览拍照、录制、静默拍照、静默录制、抓拍插件支持
- uni高德地图功能拓展地图截图
- 科大讯飞离线合成插件支持iOS、android
- iOS保活Android保活鸿蒙保活定位插件系统定位
- 高德定位、猎鹰轨迹插件
- 海康威视综合安防平台视频播放插件
- 支持NFC读写功能检测支持Android iOS HarmonyOS
- 自定义相机
- VLC视频播放器-兼容式组件
- VLC视频播放器-标准模式组件
- 桌面小组件
- 海康网络摄像头
- 百度OCR
- 录音pcm播放插件
- 原生离线语音合成原生TTS
- 科大讯飞离线语音合成、识别插件
- 科大讯飞离线语音听写
完整示例
以下为 Demo 页完整源码,可直接复制到对应项目使用。
uni-app x(pages/index/index.uvue)
<template>
<view class="page">
<text class="title">USB 扫码枪监听</text>
<text class="hint">无需输入框 / 无需焦点</text>
<text class="hint">请直接用扫码枪扫描</text>
<view class="actions">
<button type="primary" :disabled="listening" @click="startListen">开始监听</button>
<button type="warn" :disabled="!listening" style="margin-top: 16rpx;" @click="stopListen">停止监听</button>
</view>
<text class="label">监听状态:{{ listening ? '已开启' : '未开启' }}</text>
<text class="label">最近一次结果</text>
<text class="result">{{ lastCode }}</text>
<view class="divider"></view>
<text class="label">历史记录({{ history.length }})</text>
<scroll-view class="history" scroll-y="true">
<text class="history-item" v-for="(item, index) in history" :key="index">
{{ index + 1 }}. {{ item }}
</text>
</scroll-view>
</view>
</template>
<script lang="uts">
import {
setOnScanListener,
removeOnScanListener,
isScanListening,
SetOnScanListenerOptions,
ScanSuccessResult,
UsbScanFail
} from '@/uni_modules/yt-usbscan'
export default {
data() {
return {
lastCode: '(等待扫码…)',
listening: false,
history: [] as string[]
}
},
onLoad() {
// 进入页面自动开启后台监听(等价插件 setOnScanListener)
this.startListen()
},
onUnload() {
this.stopListen()
},
methods: {
startListen() {
const that = this
const options : SetOnScanListenerOptions = {
onScanSuccess: (res : ScanSuccessResult) => {
console.log('onScanSuccess --->', res.code)
that.lastCode = res.code
const list = that.history.slice()
list.unshift(res.code)
that.history = list
uni.showToast({
title: res.code,
icon: 'none'
})
},
fail: (err : UsbScanFail) => {
console.error('usbscan fail', err.errCode, err.errMsg)
uni.showToast({
title: err.errMsg,
icon: 'none'
})
},
complete: (_ : any) => {
that.listening = isScanListening()
}
}
setOnScanListener(options)
},
stopListen() {
removeOnScanListener()
this.listening = false
}
}
}
</script>
<style>
.page {
flex: 1;
padding: 10rpx;
background-color: #ffffff;
}
.title {
font-size: 32rpx;
font-weight: bold;
color: #111111;
text-align: center;
}
.hint {
margin-top: 8rpx;
font-size: 28rpx;
color: #757575;
text-align: center;
}
.actions {
margin-top: 48rpx;
}
.label {
margin-top: 20rpx;
font-size: 28rpx;
color: #6200EE;
font-weight: bold;
}
.result {
margin-top: 16rpx;
font-size: 36rpx;
color: #111111;
text-align: center;
}
.divider {
margin-top: 40rpx;
margin-bottom: 8rpx;
height: 1px;
background-color: #E0E0E0;
}
.history {
flex: 1;
margin-top: 16rpx;
}
.history-item {
font-size: 28rpx;
color: #333333;
margin-bottom: 12rpx;
}
</style>
uni-app(pages/index/index.vue)
<template>
<view class="page">
<text class="title">USB 扫码枪监听</text>
<text class="hint">无需输入框 / 无需焦点</text>
<text class="hint">请直接用扫码枪扫描</text>
<view class="actions">
<button type="primary" :disabled="listening" @click="startListen">开始监听</button>
<button type="warn" :disabled="!listening" style="margin-top: 16rpx;" @click="stopListen">停止监听</button>
</view>
<text class="label">监听状态:{{ listening ? '已开启' : '未开启' }}</text>
<text class="label">最近一次结果</text>
<text class="result">{{ lastCode }}</text>
<view class="divider"></view>
<text class="label">历史记录({{ history.length }})</text>
<scroll-view class="history" scroll-y="true">
<text class="history-item" v-for="(item, index) in history" :key="index">
{{ index + 1 }}. {{ item }}
</text>
</scroll-view>
</view>
</template>
<script lang="uts">
import {
setOnScanListener,
removeOnScanListener,
isScanListening,
SetOnScanListenerOptions,
ScanSuccessResult,
UsbScanFail
} from '@/uni_modules/yt-usbscan'
export default {
data() {
return {
lastCode: '(等待扫码…)',
listening: false,
history: []
}
},
onLoad() {
// 进入页面自动开启后台监听(等价插件 setOnScanListener)
this.startListen()
},
onUnload() {
this.stopListen()
},
methods: {
startListen() {
const that = this
const options : SetOnScanListenerOptions = {
onScanSuccess: (res) => {
console.log('onScanSuccess --->', res.code)
that.lastCode = res.code
const list = that.history.slice()
list.unshift(res.code)
that.history = list
uni.showToast({
title: res.code,
icon: 'none'
})
},
fail: (err) => {
console.error('usbscan fail', err['errCode'], err['errMsg'])
uni.showToast({
title: err['errMsg'],
icon: 'none'
})
},
complete: (_) => {
that.listening = isScanListening()
}
}
setOnScanListener(options)
},
stopListen() {
removeOnScanListener()
this.listening = false
}
}
}
</script>
<style>
.page {
flex: 1;
padding: 10rpx;
background-color: #ffffff;
}
.title {
font-size: 32rpx;
font-weight: bold;
color: #111111;
text-align: center;
}
.hint {
margin-top: 8rpx;
font-size: 28rpx;
color: #757575;
text-align: center;
}
.actions {
margin-top: 48rpx;
}
.label {
margin-top: 20rpx;
font-size: 28rpx;
color: #6200EE;
font-weight: bold;
}
.result {
margin-top: 16rpx;
font-size: 36rpx;
color: #111111;
text-align: center;
}
.divider {
margin-top: 40rpx;
margin-bottom: 8rpx;
height: 1px;
background-color: #E0E0E0;
}
.history {
flex: 1;
margin-top: 16rpx;
}
.history-item {
font-size: 28rpx;
color: #333333;
margin-bottom: 12rpx;
}
</style>
注意事项
- 扫码枪需设置为 HID / 键盘楔入 / 自感模式
- 建议开启扫码后缀 Enter
- 二维码 / 条码内容含中文时,可能扫不出来或结果乱码。 本插件按 HID 键盘按键的 Unicode 拼码;中文通常依赖扫码枪输出编码(如 UTF-8 / GBK)及系统输入法状态,很多枪在键盘模式下对中文支持不佳。业务上尽量使用数字、字母等 ASCII 内容;若必须含中文,请先在扫码枪说明书中确认键盘模式下的中文输出能力,或改用厂商私有协议 / 串口方案
- 仅在 App 前台有效;页面销毁请调用
removeOnScanListener - 首次使用需制作自定义基座或云打包后真机调试
- Android uni-app(非 x)依赖
@UTSJS.keepAlive,否则第二次扫码会报「回调函数已释放」;请勿频繁重复调用setOnScanListener。修改插件导出方式后请删除unpackage再编译,避免旧产物残留

收藏人数:
购买源码授权版(
试用
赞赏(2)
下载 541
赞赏 13
下载 12473930
赞赏 1936
赞赏
京公网安备:11010802035340号