全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2025-05-19_Android串口,USB,打印机,扫码枪,支付盒子,键盘,鼠标,U盘等开发使用一网打尽

您的位置:首页 >> 新闻 >> 行业资讯

Android串口,USB,打印机,扫码枪,支付盒子,键盘,鼠标,U盘等开发使用一网打尽 点击关注公众号,“技术干货” 及时达!?众里寻他千百度,蓦然回首,那人却在灯火阑珊处 ?一、前言在 Android 智能设备开发过程中, 难免会遇到串口,USB, 扫码枪,支付盒子,打印机,键盘,鼠标等接入场景,其实这些很简单,只是大多数情况下,大家都在做手机端的 App 开发,接触这方面的很少。本文重点介绍下这些在 Android 系统下是怎么接入使用的。 二 、串口接入使用1. 可以到官网下载串口包里面含有「libprt_serial_port.so」这个库, 下载下来按照so使用方式接入就行了,还有「SerialPort」类: 如下: publicclassSerialPort{ privatestaticfinalStringTAG="SerialPort"; /* * Do not remove or rename the field mFd: it is used by native method close(); */ privateFileDescriptor mFd; privateFileInputStream mFileInputStream; privateFileOutputStream mFileOutputStream; publicSerialPort(File device,intbaudrate,intflags)throwsSecurityException, IOException { mFd = open(device.getAbsolutePath(), baudrate, flags); if(mFd ==null) { Log.e(TAG,"native open returns null"); thrownewIOException(); } mFileInputStream =newFileInputStream(mFd); mFileOutputStream =newFileOutputStream(mFd); } // Getters and setters publicInputStreamgetInputStream(){ returnmFileInputStream; } publicOutputStreamgetOutputStream(){ returnmFileOutputStream; } // JNI privatenativestaticFileDescriptoropen(String path,intbaudrate,intflags); publicnativevoidclose(); static{ System.loadLibrary("serial_port"); }}2. 使用串口读取或者写入数据需要配置串口路径和波特率,如下:路径为:/dev/ttyS4, 波特率为9600, 这 2 个参数是硬件厂商约定好的。 valserialPort = SerialPort(File("/dev/ttyS4"),9600,0);读写数据需要从串口里面拿到「输入输出流」: inputStream= serialPort.inputStream //outputStream= serialPort.outputStream比如读取数据: vallength=inputStream!!.available()valbytes=newbyte[length];inputStream.read(bytes);到此,串口的使用基本就完成了。 至于串口读取后的数据怎么解析? 需要看串口数据的文档,不同硬件设备读取的不同内容出来格式不一样,按照厂商给的格式文档解析就完了,比如,串口连接的是秤,秤厂商硬件那边约定好的数据格式是怎样的,数据第 1 位什么意思,第 2 到第 X 位什么意思,xxx 位什么意思,这不同的厂商不同的,如果串口连接的不是秤,是其他硬件,约定的格式可能又不一样。 同理: 串口写数据,使用outputStream流写入就行了, 写的具体内容,具体硬件厂商会有写入的文档,写入哪个数据是干什么用的,都在文档里面有。不同的写入功能,对应不同的写入内容命令。 三 、USB 接入使用1、在 AndroidManifest 中添加 USB 使用配置 uses-permissionandroid:name="android.permission.USB_PERMISSION"/uses-featureandroid:name="android.hardware.usb.host"/ meta-dataandroid:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/meta-dataandroid:name="android.hardware.usb.action.USB_DEVICE_DETACHED"/ 2、防止 USB 插入拔出导致 Activity 生命周期发生变化需要在 Activity 下添加配置android:configChanges="orientation|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"3、代码中具体使用:比如接入 USB 打印机: //拿到USB管理器mUsbManager = context.getSystemService(Context.USB_SERVICE) asUsbManagermPermissionIntent=PendingIntent.getBroadcast(context,0, Intent(ACTION_USB_PERMISSION),0)valfilter=IntentFilter(USBPrinter.ACTION_USB_PERMISSION)filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)//注册监听USB插入拔出监听广播context.registerReceiver(mUsbDeviceReceiver, filter)//开始检索出已经连接的USB设备setUsbDevices()找到打印机设备,打印机设备的接口类型值固定式为 7(usbInterface.interfaceClass) /*** 检索usb打印设备*/privatefunsetUsbDevices(){ // 列出所有的USB设备,并且都请求获取USB权限 mUsbManager?.deviceList?.let { for(deviceinit.values) { valusbInterface = device.getInterface(0) if(usbInterface.interfaceClass ==7) { //连接了多个USB打印机设备需要 判断vid,pid,(硬件厂商会给这个值的)来确定哪一个打印机 //检查该USB设备是否有权限 if(!mUsbManager!!.hasPermission(device)) { //申请该打印机USB权限 mUsbManager!!.requestPermission(device, mPermissionIntent) }else{ connectUsbPrinter(device) } break } } }}USB 权限广播 action 收到后,就可以连接打印了 privatevalmUsbDeviceReceiver =object: BroadcastReceiver() { overridefunonReceive(context:Context, intent:Intent){ valaction = intent.action if(ACTION_USB_PERMISSION == action) { synchronized(this) { valusbDevice = intent.getParcelableExtraUsbDevice(UsbManager.EXTRA_DEVICE) if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,false)) { //UsbDevice:在Android开发中用于表示连接到Android设备的USB设备 mUsbDevice = usbDevice if(mUsbDevice !=null) { connectUsbPrinter(mUsbDevice) } }else{ WLog.e(this,"Permission denied for device$usbDevice") } } }elseif(UsbManager.ACTION_USB_DEVICE_ATTACHED == action) { //USB插入了 }elseif(UsbManager.ACTION_USB_DEVICE_DETACHED == action) { //USB拔出了 if(mUsbDevice !=null) { WLog.e(this,"Device closed") if(mUsbDeviceConnection !=null) { mUsbDeviceConnection!!.close() } } } }}四、打印机的使用Android 上面的打印机大多数是 USB 连接的打印机,还有蓝牙打印机。下面重点介绍 USB 打印机的使用: 在前面代码里找到 USB 打印设备后,我们需要拿到打印机的UsbEndpoint,如下: //UsbEndpoint:表示USB设备的单个端点。USB协议中,端点是用于发送和接收数据的逻辑privatevarprinterEp: UsbEndpoint? =nullprivatevarusbInterface: UsbInterface? =null funconnectUsbPrinter(mUsbDevice:UsbDevice?){ if(mUsbDevice !=null) { usbInterface = mUsbDevice.getInterface(0) for(iin0until usbInterface!!.endpointCount) { valep = usbInterface!!.getEndpoint(i) if(ep.type == UsbConstants.USB_ENDPOINT_XFER_BULK) { if(ep.direction == UsbConstants.USB_DIR_OUT) { mUsbManager?.let { //与USB设备建立连接 mUsbDeviceConnection = mUsbManager!!.openDevice(mUsbDevice) //拿到USB设备的端点 printerEp = ep//拿到UsbEndpoint } } } } }}开始打印:写入打印数据: /*** usb写入**@parambytes*/funwrite(bytes:ByteArray){ if(mUsbDeviceConnection !=null) { try{ mUsbDeviceConnection!!.claimInterface(usbInterface,true) //注意设定合理的超时值,以避免长时间阻塞 valb = mUsbDeviceConnection!!.bulkTransfer(printerEp, bytes, bytes.size, USBPrinter.TIME_OUT) mUsbDeviceConnection!!.releaseInterface(usbInterface) }catch(e: Exception) { e.printStackTrace() } }}一般通用 USB 打印命令都是 ESC 打印命令如下: 初始化打印机指令 //初始化打印机publicstaticbyte[]init_printer(){ byte[] result =newbyte[2]; result[0] = ESC; result[1] =0x40; returnresult;}打印位置设置为居左对齐指令 /** * 居左 */ publicstaticbyte[]alignLeft(){ byte[] result =newbyte[3]; result[0] = ESC; result[1] =97; result[2] =0; returnresult; }打印位置设置为居中对齐指令 /** * 居中对齐 */ publicstaticbyte[]alignCenter(){ byte[] result =newbyte[3]; result[0] = ESC; result[1] =97; result[2] =1; returnresult; }打印位置设置居右对齐指令 /** * 居右 */ publicstaticbyte[]alignRight(){ byte[] result =newbyte[3]; result[0] = ESC; result[1] =97; result[2] =2; returnresult; }打印结束切刀指令 //切刀 publicstaticbyte[]cutter(){ byte[] box =newbyte[6]; box[0] =0x1B; box[1] =0x64; box[2] =0x01; box[3] =0x1d; box[4] =0x56; box[5] =0x31;// byte[] data = new byte[]{0x1d, 0x56, 0x01}; return }打印文字 /*** 打印文字**@parammsg*////**// * 安卓9.0之前// * 只要你传送的数据不大于16384 bytes,传送不会出问题,一旦数据大于16384 bytes,也可以传送,// * 只是大于16384后面的数据就会丢失,获取到的数据永远都是前面的16384 bytes,// * 所以,android USB Host 模式与HID使用bulkTransfer(endpoint,buffer,length,timeout)通讯时// * buffer的长度不能超过16384。// * // * controlTransfer( int requestType, int request , int value , int index , byte[] buffer , int length , int timeout)// * 该方法通过0节点向此设备传输数据,传输的方向取决于请求的类别,如果requestType 为 USB_DIR_OUT 则为写数据 , USB _DIR_IN ,则为读数据// */funprintText(msg:String){ try{ write(msg.toByteArray(charset("gbk"))) }catch(e: UnsupportedEncodingException) { e.printStackTrace() }}打印图片,条码,二维码,可以将图片条码二维码转化为 bitmap, 然后再打印 //光栅位图打印publicstaticbyte[]printBitmap(Bitmap bitmap){ byte[] bytes1 =newbyte[4]; bytes1[0] = GS; bytes1[1] =0x76; bytes1[2] =0x30; bytes1[3] =0x00; byte[] bytes2 = getBytesFromBitMap(bitmap); returnbyteMerger(bytes1, bytes2);}蓝牙打印机,放在下一篇文章介绍吧,一起介绍蓝牙,及蓝牙打印 五、扫码枪、支付盒子、键盘、鼠标使用扫码枪,支付盒子,键盘,鼠标都是 USB 连接设备,只需要插入 Android 设备即可,前提是 Android 设备硬件含有 USB 接口,比如智能硬件 收银机,收银秤,车载插入 U 盘等 收银机「扫码枪、支付盒子」怎么扫码的? 大家知道,我们的支付码,条码,其实是一串数字内容的,扫到后是怎么解析的? 有两种方式的 「方式 1:广播接收如下:」1. 「先注册扫码广播」receiverandroid: intent-filter !-- 这里的 "SCAN_ACTION" 是扫码枪触发的action,需要替换为实际的值 -- actionandroid:/ /intent-filter/receiver2. 「在广播接收器里面拿到扫码内容」importandroid.content.BroadcastReceiver;importandroid.content.Context;importandroid.content.Intent; publicclassScanGunReceiverextendsBroadcastReceiver{ @Override publicvoidonReceive(Context context, Intent intent) { // 获取扫码内容,这里的 "SCAN_RESULT" 是扫码枪提供的action,具体可能不同 StringscanContent = intent.getStringExtra("SCAN_RESULT"); // 处理扫码内容 if(scanContent !=null) { // 扫码内容非空,执行相关逻辑 } }}「方式 2:在 Activity 的onKeyDown方法中监听,或者在Dialog.setOnKeyListener里面onKey中接收」1. Activity 中 onKeyDown:中解析每一个 keyCode 对应的数字值overridefunonKeyDown(keyCode:Int, event:KeyEvent?):Boolean{ if(KeyUtils.doNotSwitchViewPagerByKey(keyCode)) { //按了键盘上 左右键 tab 键 returntrue } scanHelpL.get().acceptKey(this, keyCode) { viewModel.scanByBarcode(it) } returnsuper.onKeyDown(keyCode, event)}2. keyCode 值与具体对照值如下:objectKeyUtils { //控制按键 左右 tab 键 不切换 viewpage fundoNotSwitchViewPagerByKey(keyCode:Int)= keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_TAB /** * keyCode转换为字符 */ funkeyCodeToChar(code:Int, isShift:Boolean): String{ returnwhen(code) { KeyEvent.KEYCODE_SHIFT_LEFT -"" KeyEvent.KEYCODE_0 -if(isShift)")"else"0" KeyEvent.KEYCODE_1 -if(isShift)"!"else"1" KeyEvent.KEYCODE_2 -if(isShift)"@"else"2" KeyEvent.KEYCODE_3 -if(isShift)"#"else"3" KeyEvent.KEYCODE_4 -if(isShift)"$"else"4" KeyEvent.KEYCODE_5 -if(isShift)"%"else"5" KeyEvent.KEYCODE_6 -if(isShift)"^"else"6" KeyEvent.KEYCODE_7 -if(isShift)"&"else"7" KeyEvent.KEYCODE_8 -if(isShift)"*"else"8" KeyEvent.KEYCODE_9 -if(isShift)"("else"9" KeyEvent.KEYCODE_A -if(isShift)"A"else"a" KeyEvent.KEYCODE_B -if(isShift)"B"else"b" KeyEvent.KEYCODE_C -if(isShift)"C"else"c" KeyEvent.KEYCODE_D -if(isShift)"D"else"d" KeyEvent.KEYCODE_E -if(isShift)"E"else"e" KeyEvent.KEYCODE_F -if(isShift)"F"else"f" KeyEvent.KEYCODE_G -if(isShift)"G"else"g" KeyEvent.KEYCODE_H -if(isShift)"H"else"h" KeyEvent.KEYCODE_I -if(isShift)"I"else"i" KeyEvent.KEYCODE_J -if(isShift)"J"else"j" KeyEvent.KEYCODE_K -if(isShift)"K"else"k" KeyEvent.KEYCODE_L -if(isShift)"L"else"l" KeyEvent.KEYCODE_M -if(isShift)"M"else"m" KeyEvent.KEYCODE_N -if(isShift)"N"else"n" KeyEvent.KEYCODE_O -if(isShift)"O"else"o" KeyEvent.KEYCODE_P -if(isShift)"P"else"p" KeyEvent.KEYCODE_Q -if(isShift)"Q"else"q" KeyEvent.KEYCODE_R -if(isShift)"R"else"r" KeyEvent.KEYCODE_S -if(isShift)"S"else"s" KeyEvent.KEYCODE_T -if(isShift)"T"else"t" KeyEvent.KEYCODE_U -if(isShift)"U"else"u" KeyEvent.KEYCODE_V -if(isShift)"V"else"v" KeyEvent.KEYCODE_W -if(isShift)"W"else"w" KeyEvent.KEYCODE_X -if(isShift)"X"else"x" KeyEvent.KEYCODE_Y -if(isShift)"Y"else"y" KeyEvent.KEYCODE_Z -if(isShift)"Z"else"z" else-"" } }}3. 扫码枪和支付盒子扫完,最后一位是回车键:检测到回车键值时候,就可以将扫到的码的内容 提交出去处理支付等操作。如下:privatefunacceptKey(keyCode:Int, block: (result:String) -Unit){ //监听扫码广播 if(keyCode != KeyEvent.KEYCODE_ENTER) { if(isDeleteStringBuilder) { valtmp: String = KeyUtils.keyCodeToChar(keyCode, hasShift) stringBuilder.append(tmp) hasShift = keyCode == KeyEvent.KEYCODE_SHIFT_LEFT } }elseif(keyCode == KeyEvent.KEYCODE_ENTER) { if(isDeleteStringBuilder) { isDeleteStringBuilder =false if(!TextUtils.isEmpty(stringBuilder.toString())) { block?.invoke(stringBuilder.toString()) } stringBuilder.delete(0, stringBuilder.length) isDeleteStringBuilder =true } }}?需要注意的是,扫码枪,支付盒子,键盘都是输入设备,要避免 UI 视图上面 控件焦点设置为 false, 同时界面不能有 EditText 控件,否则会将扫到的内容自动填入 EditText 控件里面去。 ?六、总结本文重点介绍了 Android 智能嵌入式设备,接入串口,USB, 打印机,扫码枪支付盒子,键盘鼠标等,接入的简单开发。当然涉及到的蓝牙,蓝牙打印机,分屏这些会在后面的文章中进行介绍。 关注更多AI编程资讯请去AI Coding专区:https://juejin.cn/aicoding 点击"阅读原文"了解详情~ 阅读原文

上一篇:2024-12-23_豆包说要「普惠」,于是大模型处理图片按「厘」计价了 下一篇:2022-06-06_不一样的品牌公益,看见大品牌的社会担当

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价