Android BLE 蓝牙开发——扫码枪基于BLESSED
一、蓝牙模式HID与BLE
当扫码枪与手机连接时,通常采用的是蓝牙HID(Human Interface Device)模式。本质上是一个把扫码枪作为一个硬件键盘,按照键盘协议把扫码后的结果逐个输入到对应的控件上。
优点:无需开发集成,配对就可以立即作为键盘输入使用。可以使用输入框等组件直接接收扫码结果。
缺点:对非数字支持不佳,与输入法相关,在某些时候会触发英文联想-_-||,与虚拟键盘会发生冲突,连接扫码枪时需要切换键盘输入法输入。
而我们要扫描的标签,不仅有英文,特殊符号,还有中文,因此以HID模式接入的蓝牙扫码枪,最终是不能满足要求的。于是重新选型了支持BLE模式的扫码枪。
BLE模式扫码枪
优点:兼容性好,遵循蓝牙协议,与键盘输入法无关。更底层,直接返回原始二进制数据流,方便判定编码以及进行字符编码转换。
缺点:需要进行原生开发, 处理设备扫描,连接,数据读写等操作。
二、BLE协议白话
好在有github,其中的 BLESSED for Android - BLE made easy 项目,就是一个致力于简化android上BLE开发工作的开源库。但在撸代码前还是要简单理解下BLE协议的主要概念。
较为重要的两个东西是Service(服务) 与Characteristic(特性,译为功能可能更好理解),简而言之,一个设备可以提供多个服务,每个服务可以提供多个特性功能,每个服务及特性对应一个UUID。
与设备的通信通过功能进行,每个功能通过Properties(属性)表明该特性支持读,写或者通知。
为了便于理解BLE协议,推荐下载一个叫做“BLE调试助手”的APP。下面是APP的截图。
截图演示了如何从一个支持BLE协议的设备中读取电量,不需要提前配对,打开APP扫描到对应设备后,点击Connect, 随后列出的就是一堆上面说的Service(服务),能够显示服务名称的如“Battery Service”,是根据UUID的约定取得的。
如电池服务为0x180F。点开服务后是Characteristic,其中的Battery Level(也是UUID约定 0x2A19)的Properties为 READ NOTIFY,表明该特性支持读取和通知。
点击那个下箭头,点击读取,显示出返回数据为0x5D(十进制估计九十多:-0)。
电池服务是一个在协议中约定的标准服务,但扫码枪的似乎不是,我们还需要找到扫码后,是通过哪个Service的哪个Characteristic进行通知的,通过这个工具APP也不难找,注意,要打开那个接受通知数据。
扫码后会有数据显示,找到之后就可以开始编码了。
三、第三方库 BLESSED for Android 的使用
https://github.com/weliem/blessed-android
下面进入具体的撸代码环节
安装 gradle file加入
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
} dependencies {
implementation 'com.github.weliem:blessed-android:2.0.6'
}
扫描设备
BluetoothCentralManager central = new BluetoothCentralManager(AppContext.baseAppContext,
bluetoothCentralManagerCallback,
new Handler(Looper.getMainLooper()));
central.scanForPeripherals();
bluetoothCentralManagerCallback是扫描回调方法,重要的有下面三个
//发现了一个设备
@Override
public void onDiscoveredPeripheral(BluetoothPeripheral peripheral, ScanResult scanResult)
//连接设备
@Override
public void onConnectedPeripheral(BluetoothPeripheral peripheral)
//设备断开
@Override
public void onDisconnectedPeripheral(BluetoothPeripheral peripheral, HciStatus status)
发现设备后onDiscoveredPeripheral,连接设备,停止扫描 。bluetoothPeripheralCallback 为设备回调,用于接受通知
central.autoConnectPeripheral(peripheral, bluetoothPeripheralCallback);
central.stopScan();
onConnectedPeripheral连接后查询提供的服务及特性
Log.i("BLE","onConnectedPeripheral");
List<BluetoothGattService> serviceList = peripheral.getServices();
for (int i = 0; i < serviceList.size(); i++) {
Log.i("BLE", "Service: " + serviceList.get(i).getUuid());
if(serviceList.get(i).getUuid().toString().equals("6e400001-b5a3-f393-e0a9-e50e24dcca9e")){
List<BluetoothGattCharacteristic> list= serviceList.get(i).getCharacteristics();
for (int j = 0; j < list.size(); j++) {
Log.i("BLE", "Characteristic: " + list.get(j).getUuid());
}
}
}
onConnectedPeripheral后,对特性开启通知,接受扫码结果,服务的和特性的UUID,需要对应填写,扫码结果是以通知信息返回的。
BluetoothGattCharacteristic currentTimeCharacteristic = peripheral.getCharacteristic(SERVICE_UUID, CURRENT_TIME_CHARACTERISTIC_UUID);
if (currentTimeCharacteristic != null) {
//开启通知
peripheral.setNotify(currentTimeCharacteristic, true);
}
//与设备通信需要创建绑定
boolean bret= peripheral.createBond();
断开重连可以在onDisconnectedPeripheral中处理
接收扫码结果 在设备回调类 bluetoothPeripheralCallback中的下列方法处理。其中value为扫到的二维码值
@Override
public void onCharacteristicUpdate(@NonNull BluetoothPeripheral peripheral, @NonNull byte[] value, @NonNull BluetoothGattCharacteristic characteristic, @NonNull GattStatus status)
另:
- 中文编码通常为GBK或者UTF8,需要猜测判断,最后附了个工具函数
- 因为BLE默认数据包较短,对大量数据,会拆分多次发送,onCharacteristicUpdate会被调用多次,需要将value拼接后,进行字符编码判断处理。


public static Boolean isUtf8(byte[] buffer) {
boolean isUtf8 = true;
int end = buffer.length;
for (int i = 0; i < end; i++) {
byte temp = buffer[i];
if ((temp & 0x80) == 0) {// 0xxxxxxx
continue;
} else if ((temp & 0xC0) == 0xC0 && (temp & 0x20) == 0) {// 110xxxxx 10xxxxxx
if (i + 1 < end && (buffer[i + 1] & 0x80) == 0x80 && (buffer[i + 1] & 0x40) == 0) {
i = i + 1;
continue;
}
} else if ((temp & 0xE0) == 0xE0 && (temp & 0x10) == 0) {// 1110xxxx 10xxxxxx 10xxxxxx
if (i + 2 < end && (buffer[i + 1] & 0x80) == 0x80 && (buffer[i + 1] & 0x40) == 0
&& (buffer[i + 2] & 0x80) == 0x80 && (buffer[i + 2] & 0x40) == 0) {
i = i + 2;
continue;
}
} else if ((temp & 0xF0) == 0xF0 && (temp & 0x08) == 0) {// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
if (i + 3 < end && (buffer[i + 1] & 0x80) == 0x80 && (buffer[i + 1] & 0x40) == 0
&& (buffer[i + 2] & 0x80) == 0x80 && (buffer[i + 2] & 0x40) == 0
&& (buffer[i + 3] & 0x80) == 0x80 && (buffer[i + 3] & 0x40) == 0) {
i = i + 3;
continue;
}
}
isUtf8 = false;
break;
}
return isUtf8;
}
isUtf8
Android BLE 蓝牙开发——扫码枪基于BLESSED的更多相关文章
- android ble蓝牙开发略解
Android 蓝牙4.0开发 1. 权限和相关属性 “android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行,这个4.3之前 ...
- Android Studio 蓝牙开发实例——基于Android 6.0
因项目需要做一个Android 的蓝牙app来通过手机蓝牙传输数据以及控制飞行器,在此,我对这段时间里写的蓝牙app的代码进行知识梳理和出现错误的总结. 该应用的Compile Sdk Version ...
- Android BLE蓝牙开发-读写数据 获取UUID
https://www.jianshu.com/p/3711cfbf7128 一个ble蓝牙设备有多个包括多个Profile 一个Profile中有多个服务Service(通过服务的uuid找到对应的 ...
- Android BLE蓝牙详细解读
代码地址如下:http://www.demodashi.com/demo/15062.html 随着物联网时代的到来,越来越多的智能硬件设备开始流行起来,比如智能手环.心率检测仪.以及各式各样的智能家 ...
- Android ble 蓝牙4.0 总结
本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...
- Android ble 蓝牙4.0 总结一
本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...
- Android BLE 蓝牙编程(一)
最近在研究这个,等我有时间来写吧! 终于在端午节给自己放个假,现在就来说说关于android蓝牙ble的 最近的学习成果吧!! 需要材料(写个简单教程吧--关于小米手环的哦!嘿嘿) Android 手 ...
- Android ble蓝牙使用注意
以下均为自己在Android ble开发项目中遇到的问题 1.尽量不要在BluetoothGattCallback里面的回调函数中执行读写通知操作,最多一个,因为例如在onServicesDiscov ...
- Android BLE 蓝牙低功耗教程,中央BluetoothGatt和周边BluetoothGattServer的实现
http://blog.csdn.net/wave_1102/article/details/39271693 分类: Android(105) 作者同类文章X Android4.3 规范了BLE的A ...
随机推荐
- vmstat监视内存的使用情况
vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写,可实时动态监视操作系统的虚拟内存.进程.CPU活动. vmstat的语法 vmstat [-V] [-n] [ ...
- .Net Core AOP之IExceptionFilter
一.简介 在.net core 中Filter分为以下六大类: 1.AuthorizeAttribute(权限验证) 2.IResourceFilter(资源缓存) 3.IActionFilter(执 ...
- ansible中的hostvars
首先来看一个例子:假设我想得到主机IP为172.25.250.9的完全限定域名(FQDN),但是我无法登录该主机,那么就可以用本机里面的hostvars魔法变量(后面会分享我对魔法这个词的理解)这个字 ...
- 我哭了 看到RCNN 和FAST RCNN时 想着为什么要选候选框呢?能不能直接回归出来候选框?
这是不是一个超级好的IDEA 我是不是要发顶会了!!! 看到yolo 直接绝望 果然 你能想到的都已经被发表了. 生不逢时啊!!!
- 创新引领,再获嘉誉!Smartbi亮相亚太银行数博会,共话未来银行数字化趋势
4月21日,以"加速数字化,引领银行业务创新"为主题的第六届亚太银行数字化创新博览会在上海盛大开幕.本次高峰论坛吸引了400多位来自学术界.咨询行业以及银行业等不同领域的行业大咖齐 ...
- uniapp vue3 $on/$once/$off 的替代方案
仅作参考 仅作参考 仅作参考 并且只支持页面生命周期使用 不支持组件 不支持页面函数方法 下面说了思路需要的话自己添加 今天用到 $once 时发现报错了,原理是vue3移除了该api.我一开始想的是 ...
- 使用Helm安装harbor
使用nfs共享存储搭建的pvc(此次都放在一个vpc下): harbor使用nodePort方式部署,不使用ssl: 准备工作: 准备好harbor用的pvc: 安装好helm,添加好可用源: 因为使 ...
- C# $的简介
无意中看到这个$格式字符串,然后学习一下.$是C#6.0的新特性. 比如我们以前是这么做的,内插字符串. var anInt = 1; var aBool = true; var aString = ...
- sqlplus / as sysdba 详解
转至:https://www.cnblogs.com/jijm123/p/12821654.html 在命令窗口输入"sqlplus / as sysdba"后回车,即可连接到Or ...
- ajax发送json格式与文件数据、django自带的序列化器(了解)
上期内容回顾 聚合查询和分组查询 # 聚合查询 max min sum avg count # 查询关键字:aggregate from django.db.models import Max, Mi ...