uniapp外接USB扫码枪并获取扫码数据

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未能监听到键盘事件。

这种方案应该是最合适的,但是测试未成功,这里仅提供一个思路,可能我的实现方法错了,虚心求教有思路的小伙伴。







监听设备键盘事件可参考:监听事件(系统事件+设备按键事件+自定义事件)。

  • 方案三:参考原生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);                     
},

分析:系统设置中,连接到实体键盘时,虚拟键盘默认在屏幕上保持显示状态
解决方案:设置当连接到实体键盘时,关闭虚拟键盘(无实体键盘时才会弹出软键盘)
步骤:设置 -> 语言和输入法 -> 实体键盘 -> 关闭显示虚拟键盘

uniapp外接USB扫码枪并获取扫码数据_第1张图片
关闭软键盘.png

4.3 输入法默认为中文导致扫码数据乱码问题

说明:系统默认输入法是谷歌拼音输入法(中文输入法),导致扫码扫出来中文,扫码数据不对
解决方案:切换输入法为英文输入法。
步骤:设置 -> 语言和输入法 -> 虚拟键盘 -> 管理键盘 -> 打开Android键盘(英文输入法)

uniapp外接USB扫码枪并获取扫码数据_第2张图片
切换为英文输入法.png

注意:虽然系统设置为英文输入法,但是若在登录输入时(或其他情况的输入)软键盘需要切换为中文进行手动输入,仍会导致之后的扫码乱码。解决办法就是输入后软键盘再切换为英文。
uniapp外接USB扫码枪并获取扫码数据_第3张图片
软键盘输入法.png

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销毁又重建
解决方案:先接线,后打开应用
注意:接线时,若转接头和平板连接后再连接扫码枪,无法给扫码枪供电;正确的接线顺序为,转接头和扫码枪连接后再连接平板。
备注:该方案仅能规避连接扫码枪时应用重启问题,尚未找到解决断开扫码枪时应用重启问题的方案

uniapp外接USB扫码枪并获取扫码数据_第4张图片
插拔重启.png

拓展:热插拔

备注:完整代码示例







你可能感兴趣的:(uniapp外接USB扫码枪并获取扫码数据)