1. 原理
说明:项目中使用的是标准的扫码枪,标准的意思就是它都不给开发文档。走的标准“输入事件”,和外接键盘是一样的。扫码枪扫描到的条形码每一位会触发一次onkeydown事件。比如扫描条码位‘1234567890’的条形码,会连续执行10次onkeydown事件,条码扫描到最后一位,会直接触发Enter(标准扫描枪扫描数据会触发KEYCODE_ENTER键)。
拓展:
扫码枪的种类有蓝牙、USB、串口等等,目前USB的扫码枪主流的就是以下两种:
- USB HID-KBW:支持 Android 热插拔USB扫描枪会在有EditText时,扫描枪扫描内容自动输入到编辑框了,即扫码器会将扫描出来的内容转化为键盘事件,就是Android中KeyEvent里面对应的常量(KeyEvent.KEYCODE_*)。但是有很多输入法兼容的问题,比如搜狗输入法识别到HID设备时会隐藏无法弹出,如果输入法切换成中文时会输入中文等等。
- USB 虚拟串口:通过串口的方式直接获取原始数据,不再跟输入法产生冲突。可使用android-serialport-api连接到UsbDevice进行通信,读取数据;但扫码枪设备要支持串口(扫码枪若是USB HID则不支持串口)。
2. 优缺点
(1) 优点:
- 不需要额外供电以及价格便宜
- 即插即用:实质其实就是相当于设备的外接键盘,也就是它必须在有光标的地方才能进行扫码,且是直接把扫到的内容自动输入到输入框中,并不受我们的控制
- 直接通过串口读取流里面的数据
(2) 缺点:需要知道每一款扫码器的型号以获取波特率及Android设备的串口地址。
备注:我的项目在实现获取扫码枪数据的过程中并未体现该缺点。
3. 监听扫码枪事件获取数据
备注:扫码枪就是 = 键盘 + 回车,即外接接盘。所以建个txt文本文档或者doc随便,打开,然后连接扫码枪,开始扫描,扫码结果就会自动填入你的文档。
- 方案一:监听键盘的keydown事件
分析:uniapp无document对象,无法获取keydown事件。无键盘事件,不支持键盘修饰符。 - 方案二:使用 5+ 的api监听键盘事件
分析:H5 和小程序不能监听键盘事件,但是app端可通过使用 5+ 的api监听键盘事件。经测试,app端使用 5+ 的api未能监听到键盘事件。
这种方案应该是最合适的,但是测试未成功,这里仅提供一个思路,可能我的实现方法错了,虚心求教有思路的小伙伴。
plus监听原生扩展事件:扫码结果{{resultValue}}
监听设备键盘事件可参考:监听事件(系统事件+设备按键事件+自定义事件)。
- 方案三:参考原生Android外接USB扫码枪,生成插件在uniapp中使用。
分析:原生实现中是通过拦截dispatchKeyEvent(KeyEvent event)方法来自己处理键盘的输入事件。是否能封装成插件尚在研究中。 - 方案四:使用 input 输入框控件来接收
分析:输入框可直接接收扫码枪数据
方案:主要通过使用 input 的 @input 和 @confirm 事件来实现
备注:页面其实并不需要显示input控件,这里只作为接受数据的作用,所以尽可能在界面中隐藏该控件,从而达到既不影响用户体验又能实现我们的功能
说明:具体实现过程中有一些细节问题需要处理,详情见下问题汇总
。
4. 问题汇总
4.1 失焦导致无法获取扫码数据
说明:输入框聚焦后扫码枪才可以把内容输出到输入框中,失去焦点将导致不能获取到扫码数据,或者说是需手动聚焦后才能获取到扫码数据。
(1) 失焦描述1:虽然设置了输入框的聚焦属性,扫码一次后就会失去焦点
解决方案:输入框失焦时重新在 @blur 事件中重新设置焦点
注意:此时需在输入事件中设置焦点属性为false,之后 @blur 事件会自动被调用,从而获取到焦点。
input:function(e){
console.log("键盘输入:" + e.detail.value);
_self.isFocus = false;
},
focus:function(){
console.log("输入框聚焦");
},
blur:function(){
console.log("输入框失去焦点");
_self.isFocus = true;
},
(2) 失焦描述2:点击界面上除输入框的其他位置,也会导致输入框失去焦点
解决方案:给整个页面的根节点设置点击事件,重新获取焦点。
注意:此时需设置焦点属性为false,之后 @blur 事件会自动被调用,从而获取到焦点。
setFocus:function(){
console.log("setFocus-1: " + _self.isFocus + "");
_self.isFocus = false;
console.log("setFocus-2: " + _self.isFocus + "");
},
备注
:经验证,还需在manifest.json配置文件关闭沉浸式
,否则无法重新获取焦点(刚好项目之前因需去掉原生导航故关闭了沉浸式,所以开始的没发现需关闭沉浸式才能重新聚焦的问题)。原因未知,望知道的小伙伴告知一下。
/* 5+App特有相关 */
"app-plus": {
"statusbar" : {
"immersed" : false //关闭沉浸式:解决去掉原生导航后,主内容顶到状态栏的问题;扫码枪-输入框聚焦问题(原因未知)
},
},
拓展:窗体默认是沉浸式(即全屏可写内容)。若不启用原生导航,手机顶部状态栏区域会被页面内容覆盖;而系统导航栏会自动处理状态栏高度占位问题,不会出现手机顶部状态栏区域被页面内容覆盖的问题。参考自定义导航栏使用注意。
4.2 聚集导致屏幕弹出软键盘问题
描述:连接扫码枪后,每次聚焦操作都会引起页面弹出软键盘
说明:使用官网的隐藏软键盘api并不能完全禁用软键盘
focus:function(){
console.log("输入框聚焦");
// 并不能完全禁用软键盘
setTimeout(function(){
uni.hideKeyboard();//隐藏软键盘:隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作
// plus.key.hideSoftKeybord();//隐藏软键盘:隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作
},250);
},
分析:系统设置中,连接到实体键盘时,虚拟键盘默认在屏幕上保持显示状态
解决方案:设置当连接到实体键盘时,关闭虚拟键盘(无实体键盘时才会弹出软键盘)
步骤:设置 -> 语言和输入法 -> 实体键盘 -> 关闭
显示虚拟键盘
4.3 输入法默认为中文导致扫码数据乱码问题
说明:系统默认输入法是谷歌拼音输入法(中文输入法),导致扫码扫出来中文,扫码数据不对
解决方案:切换输入法为英文输入法。
步骤:设置 -> 语言和输入法 -> 虚拟键盘 -> 管理键盘 -> 打开
Android键盘(英文输入法)
注意:虽然系统设置为英文输入法,但是若在登录输入时(或其他情况的输入)软键盘需要切换为中文进行手动输入,仍会导致之后的扫码乱码。解决办法就是输入后软键盘再切换为英文。
4.4 字符截取问题
说明:每次扫码数据都会拼接到输入框中(输入框默认最大输入长度maxlength为140),但是我们只需要每次的扫码数据
解决方案1(双向绑定未成功):使用双向绑定,并监听每次扫码的完成事件 @confirm,获取当次扫码数据后清空输入框数据。
分析:在输入完成事件中清空输入框将导致下次扫码获取到错误数据,可能和输入框的输入事件@input 是一个字符一个字符读取有关。
解决方案2(扫码位数有局限性):设置不限制输入框的最大长度(maxlength = -1),在输入完成事件中截取最后约定的位数作为扫码结果。
分析:所要扫的有效二维码位数已固定。
confirm:function(e){
console.log("点击完成按钮");
var str = e.detail.value;
var result = str.substring(str.length-13);//截取后13位
uni.showToast({
title: result
});
},
解决方案3(成功截取每次扫码结果):通过当前扫码输入框字符串减去上次扫码输入框字符串,获取到每次扫码结果
data() {
return {
lastInputValue:"",
}
},
methods: {
confirm:function(e){
console.log("点击完成按钮");
var currentInputValue = e.detail.value;
var newValue = "";
if(_self.lastInputValue == ""){
newValue = currentInputValue;
}else{
//newValue = currentInputValue.replace(_self.lastInputValue,"");
newValue = currentInputValue.substring(_self.lastInputValue.length);
}
_self.lastInputValue = currentInputValue;
console.log("扫码结果:" + newValue);
uni.showToast({
title: newValue
});
},
},
4.5 应用重启问题
描述: 当应用打开时,插拔键盘或扫码枪会导致应用重启,连接扫码枪时扫码枪恢复出厂设置也会导致应用重启
分析:可能是检测到键盘类型改变引起的,类似android中屏幕旋转导致activity销毁又重建
解决方案:先接线,后打开应用
注意:接线时,若转接头和平板连接后再连接扫码枪,无法给扫码枪供电;正确的接线顺序为,转接头和扫码枪连接后再连接平板。
备注
:该方案仅能规避连接扫码枪时应用重启问题,尚未找到解决断开扫码枪时应用重启问题的方案
拓展:热插拔
备注
:完整代码示例