经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android接入USB扫码模块的方法
来源:jb51  时间:2021/9/28 12:15:52  对本文有异议

前言

USB扫码模块可以是扫描盒子或者扫码枪之类的,一根USB线作为供电和数据通信使用,有些扫码模块支持虚拟串口模式,虚拟串口模式读取数据会比较简单一点,和普通的串口一样操作即可,就是通过虚拟串口口+波特率即可获取到数据,这里主要讲读取USB模式下的数据。

1.读取USB模式下的数据

USB模式下的扫码模块相当于一个外接键盘,也就是它必须在有光标的地方才能进行扫码,且是直接把扫到的内容自动输入到输入框中,并不受我们的控制,所以我们必须另外想办法,安卓系统中有这么个方dispatchKeyEvent(KeyEvent event),它就是用来处理我们键盘的输入事件的,如果我们拦截该方法,把它交给我们自己去处理,这样我们就可以不通过Edittext从而获取到扫码头传过来的数据了。

值得注意的是扫码输出字符是连续输出的,也就是说扫码的数据并不是一下子输出所有的数据,而是有间隔的输出字符,间隔是比较短的,大概有10ms左右,有些扫码模块有回车结束符,有些没有,所以我们需要封装代码使用,如下:

  1. import android.os.Build;
  2. import android.os.Handler;
  3. import android.util.Log;
  4. import android.view.KeyEvent;
  5.  
  6. import org.greenrobot.eventbus.EventBus;
  7.  
  8. import java.util.ArrayList;
  9. import java.util.List;
  10.  
  11. public class ScanGunHelper {
  12.  
  13. private final static long MESSAGE_DELAY = 200;
  14.  
  15. private StringBuffer mStringBufferResult = new StringBuffer();
  16.  
  17. private Handler mHandler = new Handler();
  18.  
  19. private Runnable mScanningFishedRunnable = new Runnable() {
  20. @Override
  21. public void run() {
  22. performScanSuccess();
  23. }
  24. };
  25.  
  26.  
  27. private List<Integer> keyCodeList = new ArrayList<>();
  28.  
  29. private static class SingletonHolder {
  30. private static final ScanGunHelper instance = new ScanGunHelper();
  31. }
  32.  
  33. private ScanGunHelper() {
  34.  
  35. }
  36.  
  37. public static ScanGunHelper getInstance() {
  38. return ScanGunHelper.SingletonHolder.instance;
  39. }
  40.  
  41. /**
  42. * 返回扫码成功后的结果
  43. */
  44. private void performScanSuccess() {
  45. try {
  46.  
  47. boolean mCaps = keyCodeList.contains(KeyEvent.KEYCODE_SHIFT_RIGHT) || keyCodeList.contains(KeyEvent.KEYCODE_SHIFT_LEFT);
  48.  
  49. for (int keyCode : keyCodeList) {
  50.  
  51. char aChar = getInputCode(keyCode, mCaps);
  52. if (aChar != 0) {
  53. mStringBufferResult.append(aChar);
  54. }
  55. }
  56. String barcode = mStringBufferResult.toString();
  57.  
  58. Log.e("ScanGunHelper", "barcode==" + barcode);
  59.  
  60. mStringBufferResult.setLength(0);
  61.  
  62. keyCodeList.clear();
  63.  
  64. if (mHandler != null) {
  65. mHandler.removeCallbacks(mScanningFishedRunnable);
  66. }
  67. } catch (Exception e) {
  68. e.printStackTrace();
  69. }
  70. }
  71.  
  72.  
  73. /**
  74. * 扫码枪事件解析
  75. */
  76. public void analysisKeyEvent(KeyEvent event) {
  77.  
  78. //Virtual是我所使用机器的内置软键盘的名字
  79. //在这判断是因为项目中避免和软键盘冲突(扫码枪和软键盘都属于按键事件)
  80. int keyCode = event.getKeyCode();
  81.  
  82. if (event.getAction() == KeyEvent.ACTION_UP) {
  83.  
  84. keyCodeList.add(keyCode);
  85.  
  86. if (keyCode == KeyEvent.KEYCODE_ENTER) {
  87. mHandler.removeCallbacks(mScanningFishedRunnable);
  88. mHandler.post(mScanningFishedRunnable);
  89. } else {
  90. mHandler.removeCallbacks(mScanningFishedRunnable);
  91. mHandler.postDelayed(mScanningFishedRunnable, MESSAGE_DELAY);
  92. }
  93. }
  94. }
  95.  
  96.  
  97. //获取扫描内容
  98. private char getInputCode(int keyCode, boolean mCaps) {
  99. char aChar;
  100. if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) {
  101. //字母
  102. aChar = (char) ((mCaps ? 'A' : 'a') + keyCode - KeyEvent.KEYCODE_A);
  103. } else if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
  104. //数字
  105. aChar = (char) ('0' + keyCode - KeyEvent.KEYCODE_0);
  106. } else {
  107. //其他符号
  108. switch (keyCode) {
  109. case KeyEvent.KEYCODE_PERIOD:
  110. aChar = '.';
  111. break;
  112. case KeyEvent.KEYCODE_MINUS:
  113. aChar = mCaps ? '_' : '-';
  114. break;
  115. case KeyEvent.KEYCODE_SLASH:
  116. aChar = '/';
  117. break;
  118. case KeyEvent.KEYCODE_BACKSLASH:
  119. aChar = mCaps ? '|' : '\\';
  120. break;
  121. default:
  122. aChar = 0;
  123. break;
  124. }
  125. }
  126. return aChar;
  127. }
  128.  
  129. /**
  130. * 输入设备是否存在
  131. */
  132. public static boolean isScanGunExist(KeyEvent event) {
  133. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  134. Log.e("ScanGunHelper", "ProductId==" + event.getDevice().getProductId() + ",VendorId==" + event.getDevice().getVendorId());
  135. if (event.getDevice().getVendorId() == 1409 && event.getDevice().getProductId() == 262) {
  136. return true;
  137. }
  138. }
  139. return false;
  140. }
  141.  
  142. }

如果用的扫码模块有确定的ProductId和VendorId,可以直接过滤,写死ProductId和VendorId会使得程序很不灵活,万一换了一款扫码模块就不适配了,所以建议做成可配置,避免很多麻烦

如果不用ProductId和VendorId过滤输入事件,那就区分一下软键盘即可,系统自动软件盘的DeviceId为-1,只要不等于-1,就是扫码模块输入的字符。

单列模式封装代码,主要是考虑到一台安卓一体机不可能接入两个扫码模块,当成唯一设备作为处理即可。

2.在基类的Activity中使用,确保每个界面能拦截到数据,方便使用,不需要每个界面都拦截

  1. import android.os.Bundle;
  2. import android.support.annotation.Nullable;
  3. import android.support.v7.app.AppCompatActivity;
  4. import android.view.KeyEvent;
  5. import android.view.WindowManager;
  6.  
  7. public abstract class BaseActivity extends AppCompatActivity {
  8.  
  9.  
  10. @Override
  11. protected void onCreate(@Nullable Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. }
  14.  
  15.  
  16. @Override
  17. public boolean dispatchKeyEvent(KeyEvent event) {
  18. if (event.getDeviceId() > 0) {
  19. ScanGunHelper.getInstance().analysisKeyEvent(event);
  20. return true;
  21. }
  22. return super.dispatchKeyEvent(event);
  23. }
  24. }

总结:

现在的USB扫码模块是比较流行,但是扫码模块与终端设备的通信方式花样百出,有wifi、蓝牙、USB、串口等等,但是万变不离其宗,对于安卓设备而言,扫码模块就是个外接键盘,不管是什么方式通信也好(除了串口以外),最终呈现的形态就是个外接键盘,当然,我们也可以使用蓝牙读取扫码数据,这些都是so esay了,串口更加简单,有实际的串口线更好,虚拟串口会麻烦一点,每次插拔虚拟串口号会不固定,不同的安卓设备表现出的串口号也尽不相同,所以虚拟串口模式需要做很多适配工作,不能写死一个虚拟串口号,这样会照成程序不灵活、不适配,做成可配置,才能应付多变的招标现场或者客户需求现场。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号