一、写在前面的话

  • 一直想写一篇关于蓝牙与ble设备通讯的博客,但是一直也不知道从何下手,可能是之前思路不清晰吧,也就一直拖拖拖,拖到现在。最近又做到关于ble设备的项目了,在此总结一下吧。(如有不到位或者不太对的地方,希望各位多多指教)

二、关于蓝牙

  • 蓝牙是一种短距的无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之前的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的BLE蓝牙称为低功耗蓝牙。
  • 如图:

  • BLE是Bluetooth low energy的意思,属于蓝牙低功耗协议,Android4.3以上及苹果手机等现在都支持蓝牙BLE,主要面向传感器应用市场,进行短时间小数据传输,如健康领域:手机监测血压,体育:手机计步器等。

  • 低功耗蓝牙通讯协议:

三、梳理整体逻辑(思路/步骤)

  1. 权限问题:先判断手机是否满足android4.3以上版本,再判断手机是否开启蓝牙。
  2. 搜索蓝牙:搜索蓝牙,回调接口中查看ble设备相关信息,一定时间停止扫描。
  3. 连接蓝牙:首先获取到ble设备的mac地址,然后调用connect()方法进行连接。
  4. 获取特征:蓝牙连接成功后,需要获取蓝牙的服务特征等,然后开启接收设置。
  5. 发送消息:writeCharacteristic()方法,发送数据给ble设备。
  6. 接收消息:通过蓝牙的回调接口中onCharacteristicRead()方法,接收蓝牙收的消息。
  7. 释放资源:断开连接,关闭资源。

四、具体实现

1、权限问题

step1、在AndroidManifest.xml中声明权限

<!-- 蓝牙所需权限 --><uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  • 第一个权限是允许程序连接到已配对的蓝牙设备。
  • 第二个权限是允许程序发现和配对蓝牙设备。

  • 因为只有在API18(Android4.3)以上的手机才支持ble开发,所以还要声明一个feature。

 <uses-featureandroid:name="android.hardware.bluetooth_le"android:required="true" />
  • required为true时,应用只能在支持BLE的Android设备上安装运行
  • required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE。

  • 注意:还得写上定位权限,要不然有的机型扫描不到ble设备。

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

step2、获取蓝牙适配器

  BluetoothManager  mBluetoothManager =(BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);BluetoothAdapter  mBluetoothAdapter = mBluetoothManager.getAdapter();
  • 如果mBluetoothAdapter为空,是因为手机蓝牙不支持与ble设备通讯,换句话说就是安卓手机系统在4.3以下了。

step3、判断手机蓝牙是否被打开

mBluetoothAdapter.isEnabled()
  • 如果返回true,这个时候就可以扫描了
  • 如果返回false,这时候需要打开手机蓝牙。 可以调用系统方法让用户打开蓝牙。
 Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);startActivity(enable);

2、搜索蓝牙

step1、开始扫描

//10s后停止搜索
new Handler().postDelayed(new Runnable() {@Overridepublic void run() {mBluetoothAdapter.stopLeScan(mLeScanCallback);}}, 1000 * 10);UUID[] serviceUuids = {UUID.fromString(service_uuid)};
mBluetoothAdapter.startLeScan(serviceUuids, mLeScanCallback);
  • startLeScan中,第一个参数是只扫描UUID是同一类的ble设备,第二个参数是扫描到设备后的回调。
  • 因为蓝牙扫描比较耗电,建议设置扫描时间,一定时间后停止扫描。

  • 如果不需要过滤扫描到的蓝牙设备,可用mBluetoothAdapter.startLeScan(mLeScanCallback);进行扫描。

step2、扫描的回调

//蓝牙扫描回调接口
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback(){@Overridepublic void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {if (device.getName() == null) {return;}Log.e("--->搜索到的蓝牙名字:", device.getName());//可以将扫描的设备弄成列表,点击设备连接,也可以根据每个设备不同标识,自动连接。}};

3、连接蓝牙

step1、获取设备的mac地址,然后连接。

  //获取所需地址String mDeviceAddress = device.getAddress();BluetoothGatt mBluetoothGatt = device.connectGatt(context, false, mGattCallback);

step2、onConnectionStateChange()被调用

  • 连接状态改变时,mGattCallback中onConnectionStateChange()方法会被调用,当连接成功时,需要调用 
    mBluetoothGatt.discoverServices();
    去获取服务。

step3、onServicesDiscovered()被调用

  • 调用mBluetoothGatt.discoverServices();方法后,onServicesDiscovered()这个方法会被调用,说明发现当前设备了。然后我们就可以在里面去获取BluetoothGattService和BluetoothGattCharacteristic。

  • 下面就是mGattCallback回调方法。

    // BLE回调操作private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status,int newState){super.onConnectionStateChange(gatt, status, newState);if (newState == BluetoothProfile.STATE_CONNECTED) {// 连接成功mBluetoothGatt.discoverServices();} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {// 连接断开Log.d("TAG","onConnectionStateChange fail-->" + status);}}@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {super.onServicesDiscovered(gatt, status);if (status == BluetoothGatt.GATT_SUCCESS) {//发现设备,遍历服务,初始化特征initBLE(gatt);} else {Log.d("TAG","onServicesDiscovered fail-->" + status);}}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status){super.onCharacteristicRead(gatt, characteristic, status);if (status == BluetoothGatt.GATT_SUCCESS) {// 收到的数据byte[] receiveByte = characteristic.getValue();}else{Log.d("TAG","onCharacteristicRead fail-->" + status);}}@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic){super.onCharacteristicChanged(gatt, characteristic);//当特征中value值发生改变}/*** 收到BLE终端写入数据回调* @param gatt* @param characteristic* @param status*/@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicWrite(gatt, characteristic, status);if (status == BluetoothGatt.GATT_SUCCESS) {// 发送成功} else {// 发送失败}}@Overridepublic void onDescriptorWrite(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {super.onDescriptorWrite(gatt, descriptor, status);if (status == BluetoothGatt.GATT_SUCCESS) {}}@Overridepublic void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {super.onReadRemoteRssi(gatt, rssi, status);if (status == BluetoothGatt.GATT_SUCCESS) {}}@Overridepublic void onDescriptorRead(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {super.onDescriptorRead(gatt, descriptor, status);if (status == BluetoothGatt.GATT_SUCCESS) {}}};

4、获取特征

step1、ble设备相关的UUID

    //写通道uuidprivate static final UUID writeCharactUuid = UUID.fromString("0000fff6-0000-1000-8000-00805f9b34fb");//通知通道 uuidprivate static final UUID notifyCharactUuid =UUID.fromString( "0000fff7-0000-1000-8000-00805f9b34fb");
  • 不同的ble设备的UUID不相同,请根据自己的设备初始化UUID。

step2、获取bluetoothGattCharacteristic(因为有的设备可能存在双服务的情况,所以这里遍历所有服务)

    //初始化特征public void initBLE(BluetoothGatt gatt) {if (gatt == null) {return;}//遍历所有服务for (BluetoothGattService BluetoothGattService : gatt.getServices()) {Log.e(TAG, "--->BluetoothGattService" + BluetoothGattService.getUuid().toString());//遍历所有特征for (BluetoothGattCharacteristic bluetoothGattCharacteristic : BluetoothGattService.getCharacteristics()) {Log.e("---->gattCharacteristic", bluetoothGattCharacteristic.getUuid().toString());String str = bluetoothGattCharacteristic.getUuid().toString();if (str.equals(writeCharactUuid)) {//根据写UUID找到写特征mBluetoothGattCharacteristic = bluetoothGattCharacteristic;} else if (str.equals(notifyCharactUuid)) {//根据通知UUID找到通知特征mBluetoothGattCharacteristicNotify = bluetoothGattCharacteristic;}}}}

step3、开启通知

  • 设置开启之后,才能在onCharacteristicRead()这个方法中收到数据。
    mBluetoothGatt.setCharacteristicNotification(mGattCharacteristicNotify, true);
  • 1

5、发送消息

    mGattCharacteristicWrite .setValue(sData);if (mBluetoothGatt != null) {mBluetoothGatt.setCharacteristicNotification(notifyCharactUuid , true);mBluetoothGatt.writeCharacteristic(mGattCharacteristicWrite );} 

6、接收消息

  • 接收到数据后,mGattCallback 中的onCharacteristicRead()这个方法会被调用。
 @Overridepublic void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status){super.onCharacteristicRead(gatt, characteristic, status);if (status == BluetoothGatt.GATT_SUCCESS) {// 收到的数据byte[] receiveByte = characteristic.getValue();}else{Log.d("TAG","onCharacteristicRead fail-->" + status);}}

7、释放资源

  • 断开连接、关闭资源。
    public boolean disConnect() {if (mBluetoothGatt != null) {mBluetoothGatt.disconnect();mBluetoothGatt.close();mBluetoothGatt = null;return true;}return false;}

五、开发中踩过的坑

  1. 通知开启后,才能读到数据,否则读不到。
  2. 发送数据时,如果一包数据超过20字节,需要分包发送,一次最多发送二十字节。
  3. 接收数据时,一次最多也只接收20字节的数据,需要将接收到的数据拼接起来,在数据的结尾弄一个特定的标识,去判断数据是否接受完毕。
  4. 每次发送数据或者数据分包发送时, 操作间要有至少15ms的间隔。
  5. 最近公司来了个新的蓝牙产品,发现获取不到需要的特征,后来打断点,发现他们蓝牙设备的通知特征根本没有,是他们给错协议了。。。所以建议各位开发的时候,如果一直连接失败,也可以查看一下写特征和通知特征是否为空,是不是卖家搞错了,协议和产品不匹配。(当然,这样马虎的卖家估计是少数)。
  6. 又补充来了!这个蓝牙如果出现扫描不到的情况,那是因为手机没有开启定位权限,清单文件中写上定位权限,代码中在动态获取下就OK了。

六、demo图示

点我下载

 
 

欢迎关注技术公众号,微信号搜索ColorfulCode 代码男人

分享技术文章,投稿分享,不限技术种类,不限技术深度,让更多人因为分享而受益。

Android低功耗蓝牙通讯相关推荐

  1. android 连接蓝牙电子秤_电子秤蓝牙双模通讯Android低功耗蓝牙(蓝牙4.0)BLE开发(上)...

    电子秤蓝牙双模通讯Android低功耗蓝牙(蓝牙4.0)BLE开发(上) 前段时间,公司项目用到了手机APP和蓝牙设备的通讯开发,这里也正好对低功耗蓝牙(蓝牙4.0及以后标准)的开发,做一个总结. 蓝 ...

  2. Android低功耗蓝牙(BLE)使用详解

    代码地址如下: http://www.demodashi.com/demo/13390.html 与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许Android应用程序与具有更严格电源要求的BLE设 ...

  3. 在uniAPP中使用使用低功耗蓝牙通讯

    在uniAPP中使用使用低功耗蓝牙通讯 1.初始化蓝牙监听器 onLoad(){//蓝牙是否在扫描设备uni.onBluetoothAdapterStateChange((res)=>{cons ...

  4. Android低功耗蓝牙(BLE)开发(二)

    在上一篇文章Android低功耗蓝牙(BLE)开发(一)中我们了解了BLE的相关概念,这里我们来实际用代码演示安卓进行BLE连接和通讯的功能.本文代码基于Android5.0以上(API 21) 1. ...

  5. Android 低功耗蓝牙开发简述

    低功耗蓝牙简述 一.什么是低功耗蓝牙? 二.怎么做低功耗蓝牙应用? ① 之前有没有接触Android蓝牙开发? ② 蓝牙设备固件是公司自己的吗? ③ 有没有蓝牙固件和蓝牙应用的文档和Demo? ④ 具 ...

  6. 低功耗蓝牙通讯 C# WinForm

    目录 前言 一.添加引用 二.使用步骤 1.蓝牙通讯类 2.测试界面 3.界面截图 三.注意事项 前言 因为项目需要上位机软件与下位机的蓝牙模块进行通讯,所以上网查阅了很多关于蓝牙通讯的资料.刚开始以 ...

  7. Android 低功耗蓝牙开发(数据交互)

    Android 低功耗蓝牙开发(数据交互) 前言 正文 一.BluetoothGattCallback 1. onPhyUpdate 2. onPhyRead 3. onServicesDiscove ...

  8. 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解

    转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解 ...

  9. Android低功耗蓝牙

    1 传统蓝牙与低功耗蓝牙 传统蓝牙也叫经典蓝牙,经典蓝牙模块泛指支持蓝牙协议4.0以下的模块,有v1.1/1.2/2.0/2.1/3.0.经典蓝牙支持音频(HFP/HSP, A2DP)和数据(SPP, ...

  10. Android 低功耗蓝牙BLE连接通信

    目录 简介 蓝牙 4.0 BLE与蓝牙4.0的区别 BLE的特点 主要特性 技术细节 BLE的应用 BLE的体系结构 BLE设备链路层状态 就绪态 广播态 扫描态 发起态 连接状态 通信基本过程 两种 ...

最新文章

  1. robot framework安装问题排查
  2. F - Monkey Banana Problem
  3. Go gin获取post请求数据
  4. boost::weak_from_raw相关的测试程序
  5. 自定义AlertDialog布局
  6. 响应式web(三):服务当中的三种耦合,流式计算,RXJava2,Flux,Mono
  7. python基础数据类型的相关知识点
  8. maven 安装后变成 mvn 不是内部命令解决方法
  9. 计算机vf知识点总结,计算机等级考试二级VF常用函数总结
  10. php 所有子类,php获取分类以下的全部子类方法
  11. c语言switch编写个人所得税,C语言编写一个计算个人所得税的程序,要求输入收入金额,能够输...
  12. LayUI中的内置模块之 工具集文档 - layui.util
  13. QT5修改windows电脑IP地址
  14. h2o flow初探
  15. 读《Ideal MHD》(1)-磁流体力学方程组推导
  16. 【C语言】C语言中基础操作符详细讲解
  17. 分析师不死心 仍坚信微软终将成功并购雅虎
  18. Spring5基础知识
  19. 农学跨专业考研计算机,跨专业考研依然可以得高分
  20. 3DCNN参数解析:2013-PAMI-3DCNN for Human Action Recognition

热门文章

  1. AndroidStudio中的NDK开发初探
  2. 软件系统怎么做版本管理?
  3. 怎样查看PPT中的字数
  4. Ad hoc queries(即席查询)
  5. ODAC Windows 安装
  6. XJOI恺撒加密术1级19段
  7. C++ VS2017 编译调用 gflags
  8. JS使用递归遍历json对象进行操作
  9. YYLabel 自动布局 不换行 numberOfLines无效
  10. 2021年T电梯修理考试题及T电梯修理模拟考试题