Android Ble蓝牙开发总结

前言

本文总结了ble的搜索,连接,读写操作。以及在开发过程中可能遇到的坑。

首先我们需要知道,什么是ble。

蓝牙发展至今经历了8个版本的更新。1.1、1.2、2.0、2.1、3.0、4.0、4.1、4.2。那么在1.x~3.0之间的我们称之为传统蓝牙,4.x开始的蓝牙我们称之为低功耗蓝牙也就是蓝牙ble。
蓝牙BLE相对于传统蓝牙的优点:最大化的待机时间、快速连接和低峰值的发送/接收功耗。应用区别:BLE低功耗蓝牙一般多用在蓝牙数据模块,拥有极低的运行和待机功耗,使用一粒纽扣电池可连续工作数年之久;BT经典蓝牙模块多用在蓝牙音频模块,音频需要大码流的数据传输更适合使用。
1、蓝牙BLE的发送和接受任务会以最快的速度完成,完成之后蓝牙BLE会暂停发射无线(但是还是会接受),等待下一次连接再激活;而传统蓝牙是持续保持连接。
2、广播信道(为保证网络不互相干扰而划分)仅有3个,而传统蓝牙是32个。
3、蓝牙低能耗技术“完成”一次连接(即扫描其它设备、建立链路、发送数据、认证和适当地结束)只需3ms。而标准蓝牙技术完成相同的连接周期需要数百毫秒。
4、蓝牙低能耗技术使用非常短的数据包,标准蓝牙技术使用的数据包长度较长。

ble的相关概念

Generic Attribute Profile (GATT)

通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。
Profile可以理解为一种规范,一个标准的通信协议,其存在于手机中,蓝牙组织规定了一些标准的profile:HID OVER GATT ,防丢器等,每个profile中包含了多个service。

Attribute Protocol (ATT)

GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。

Service

可以理解为一个服务,这里要区分的是BluetoothServer,一个是服务,一个是服务器端。在BLE从机中有多个服务,电量信息,系统服务信息等,每一个service中包含了多个characteristic特征值,每一个具体的characteristic特征值才是BLE通信的主题。 Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement”的Characteristic。

Characteristic

Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。通过操作Characteristic可以实现Ble的数据传输。

Descriptor

对Characteristic的描述,例如范围、计量单位等。

UUID(统一标识码)

service和characteristic均需要这个唯一的UUID进行标识。UUID可以双方自定义,例如客户端访问服务器端的写characteristic,那么客户端就需要有服务器端定义的写characteristic UUID

这三部分都用UUID作为唯一标识符。UUID为这种格式:0000ffe1-0000-1000-8000-00805f9b34fb。比如有3个Service,那么就有三个不同的UUID与Service对应。这些UUID都写在硬件里,我们通过BLE提供的API可以读取到,同时也可以自定义Application层的UUID。

他们关系可以总结如下:一个BLE终端可以包含多个Service, 一个Service可以包含多个Characteristic,一个Characteristic包含一个value和多个Descriptor,一个Descriptor包含一个Value。

Characteristic是比较重要的,是手机与BLE终端交换数据的关键,读取设置数据等操作都是操作Characteristic的相关属性。

代码实现

1.权限设置

使用蓝牙必须先获取到相应的权限,因为需要使用BLE,所以Manifest中需要加入以下权限及说明,在6.0上面需要使用BLE蓝牙,我们还需要加上LOCATION权限

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-featureandroid:name="android.hardware.bluetooth_le"android:required="true" />

2.检查设备蓝牙状态

判断当前设备是否支持蓝牙,并且是否开启蓝牙,如果支持且没有打开则需要开启蓝牙,要是不支持蓝牙,那就不用继续看了,直接说做不了就行了。

   mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);mBluetoothAdapter = mBluetoothManager.getAdapter();if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, 0);}

3.搜索蓝牙设备

mBluetoothAdapter.startLeScan(scanCallback);
BluetoothAdapter.LeScanCallback scanCallback = new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {Log.e(TAG, "run: scanning..." + device.getName());if (device.getName() != null && !device.getName().equals("null") && !mDatas.contains(device)) {//展示当前搜索到的蓝牙设备}}};

4.获取蓝牙设备特征值

private void initServiceAndChara() {List<BluetoothGattService> bluetoothGattServices = mBluetoothGatt.getServices();for (BluetoothGattService bluetoothGattService : bluetoothGattServices) {List<BluetoothGattCharacteristic> characteristics = bluetoothGattService.getCharacteristics();for (BluetoothGattCharacteristic characteristic : characteristics) {int charaProp = characteristic.getProperties();if ((charaProp & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {read_UUID_chara = characteristic.getUuid();read_UUID_service = bluetoothGattService.getUuid();Log.e(TAG, "read_chara=" + read_UUID_chara + "----read_service=" + read_UUID_service);}if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) {write_UUID_chara = characteristic.getUuid();write_UUID_service = bluetoothGattService.getUuid();Log.e(TAG, "write_chara=" + write_UUID_chara + "----write_service=" + write_UUID_service);}
//                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {//                    write_UUID_chara = characteristic.getUuid();
//                    write_UUID_service = bluetoothGattService.getUuid();
//                    Log.e(TAG, "write_chara=" + write_UUID_chara + "----write_service=" + write_UUID_service);
//
//                }if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {notify_UUID_chara = characteristic.getUuid();notify_UUID_service = bluetoothGattService.getUuid();Log.e(TAG, "notify_chara=" + notify_UUID_chara + "----notify_service=" + notify_UUID_service);}if ((charaProp & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {indicate_UUID_chara = characteristic.getUuid();indicate_UUID_service = bluetoothGattService.getUuid();Log.e(TAG, "indicate_chara=" + indicate_UUID_chara + "----indicate_service=" + indicate_UUID_service);}}}}

5.连接蓝牙设备

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this,true, gattCallback, TRANSPORT_LE);} else {mBluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this,true, gattCallback);}
private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {/*** 断开或连接 状态发生变化时调用* */@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {super.onConnectionStateChange(gatt, status, newState);Log.e(TAG, "onConnectionStateChange()");if (status == BluetoothGatt.GATT_SUCCESS) {//连接成功if (newState == BluetoothGatt.STATE_CONNECTED) {Log.e(TAG, "连接成功");isScaning = false;//发现服务gatt.discoverServices();}} else {//连接失败Log.e(TAG, "失败==" + status);mBluetoothGatt.close();isConnecting = false;}}/*** 发现设备(真正建立连接)* */@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {super.onServicesDiscovered(gatt, status);//直到这里才是真正建立了可通信的连接isConnecting = false;Log.e(TAG, "onServicesDiscovered()---建立连接");//获取初始化服务和特征值initServiceAndChara();//订阅通知mHandler.post(new Runnable() {@Overridepublic void run() {setCharacteristicNotification(mBluetoothGatt.getService(indicate_UUID_service).getCharacteristic(indicate_UUID_chara), true);}});}/*** 读操作的回调* */@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicRead(gatt, characteristic, status);runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "当前读取值:" + HexUtil.encodeHexStr(characteristic.getValue()), Toast.LENGTH_SHORT).show();}});Log.e(TAG, "onCharacteristicRead()" + HexUtil.encodeHexStr(characteristic.getValue()));}/*** 写操作的回调* */@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicWrite(gatt, characteristic, status);final byte[] value = characteristic.getValue();Log.e(TAG, "onCharacteristicWrite()  status=" + status + ",value=" + bytesToHex(value));   }/*** 接收到硬件返回的数据* */@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {super.onCharacteristicChanged(gatt, characteristic);final byte[] data = characteristic.getValue();Log.e(TAG, "onCharacteristicChanged()" + bytesToHex(data));}};

6.蓝牙读写数据

  private void writeData() {BluetoothGattService service = mBluetoothGatt.getService(write_UUID_service);BluetoothGattCharacteristic charaWrite = service.getCharacteristic(write_UUID_chara);String content = etWriteContent.getText().toString();if (TextUtils.isEmpty(content)) {return;}byte[] body = content.getBytes();if (body.length > 20) {//数据大于个字节 分批次写入Log.e(TAG, "writeData: length=" + body.length);int num = 0;if (body.length % 20!= 0) {num = body.length / 20+ 1;} else {num = body.length / 20;}Log.e(TAG, "writeData: 需要" + num + "次");for (int i = 0; i < num; i++) {byte[] tempArr;if (i == num - 1) {tempArr = new byte[body.length - i * 20];System.arraycopy(body, i * 20, tempArr, 0, body.length - i * 20);} else {tempArr = new byte[20];System.arraycopy(body, i * 20, tempArr, 0,2017);}charaWrite.setValue(tempArr);mBluetoothGatt.writeCharacteristic(charaWrite);}} else {charaWrite.setValue(body);mBluetoothGatt.writeCharacteristic(charaWrite);}}
private void readData() {BluetoothGattCharacteristic characteristic = mBluetoothGatt.getService(read_UUID_service).getCharacteristic(read_UUID_chara);mBluetoothGatt.readCharacteristic(characteristic);}

开发过程中可能遇到的坑

1.onCharacteristicChanged死活不回调
onServicesDiscovered回调后需要对相应的通道进行订阅。

setCharacteristicNotification(mBluetoothGatt.getService(indicate_UUID_service).getCharacteristic(indicate_UUID_chara), true);public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,boolean enabled) {if (mBluetoothAdapter == null || mBluetoothGatt == null) {return;}boolean notification = mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);//这里可以加入判断对指定的UUID值进行订阅List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();for (BluetoothGattDescriptor descriptor : descriptors) {if (descriptor != null) {if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {boolean b = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);} else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {boolean b = descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);}mBluetoothGatt.writeDescriptor(descriptor);}}}

工具类

//合并byte[ ] public static byte[] byteMerger(byte[] bt1, byte[] bt2) {byte[] bt3 = new byte[bt1.length + bt2.length];System.arraycopy(bt1, 0, bt3, 0, bt1.length);System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);return bt3;}//byte[ ] -->16进制字符串public static String byte2hex(byte[] buffer) {String h = "";for (int i = 0; i < buffer.length; i++) {String temp = Integer.toHexString(buffer[i] & 0xFF);if (temp.length() == 1) {temp = "0" + temp;}h = h + temp;}return h;}// 16进制字符串 -->byte[ ]public static byte[] hexStringToByte(String hex) {int len = (hex.length() / 2);byte[] result = new byte[len];char[] achar = hex.toCharArray();for (int i = 0; i < len; i++) {int pos = i * 2;result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));}return result;}

结论

项目还在进行,以后继续填坑,结束!

Android Ble蓝牙开发总结相关推荐

  1. Android BLE蓝牙开发知识总结

    Android BLE蓝牙开发知识总结 1.蓝牙介绍 1.1什么是蓝牙?    蓝牙( Bluetooth® ):是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据交换(使用2 ...

  2. Android BLE 蓝牙开发指南(三)外围设备端开发详解

    Android BLE开发指南(一)入门基础 Android BLE开发指南(二)中心设备端程序开发详解 这篇文章将会详细讲解低功耗蓝牙外围设备端程序开发的主要流程.对于Android开发者而言,或许 ...

  3. Android Ble蓝牙开发

    BLE Android 应用 开发 1.权限设置 2.获取蓝牙设备管理器 3.设备搜索 3.1 停止搜索 4.设备连接 5.设备的重连 6.设备的断开与服务关闭 7.通知的注册与接收 8.数据的主动读 ...

  4. Android BLE 蓝牙开发-扫码枪集成

    一.蓝牙模式HID与BLE 当扫码枪与手机连接时,通常采用的是蓝牙HID(Human Interface Device)模式.本质上是一个把扫码枪作为一个硬件键盘,按照键盘协议把扫码后的结果逐个输入到 ...

  5. android ble 蓝牙绑定流程,android BLE蓝牙开发

    蓝牙BLE设备是目前比较热门的设备.由于BLE有低功耗等特点,被广泛应用到身边的电子产品上.如智能手表.手环.防丢器等各种产品上.最近研究一下android上的ble应用开发.跟大家分享一下相关的内容 ...

  6. Android 低功耗蓝牙开发

    初识低功耗蓝牙 Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)的核心功能并提供了相应的 API, 应用程序通过这些 API 扫 ...

  7. Android BLE蓝牙4.0开发 实现扫描、连接、通讯、获取通知、特性等 (一、打开蓝牙 进行扫描)

    目录 首先说下蓝牙4.0 目前android蓝牙有2种: ble蓝牙开发流程: 1.首先当然是进行权限申请啦: 2.获取蓝牙适配器 BluetoothAdapter 3.打开蓝牙 4.关闭蓝牙 5.在 ...

  8. 【Android】蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)

    目录 目录 前言 一.相关概念介绍 二.实战开发 三.项目演示 四.Demo案例源码地址 五.更新记录 1.2020/12/29 :修改 setupService()中错误 2.2021/05/14 ...

  9. 【Android】BLE 蓝牙开发流程篇

    携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 4 天,点击查看活动详情 前言 本文旨在梳理 BLE 蓝牙开发的主要流程,其中涉及到其他的知识,将会单独成文梳理.如有任何疑问, ...

最新文章

  1. TurboMail邮件系统通过涉密信息系统产品认定
  2. 数字图像处理技术详解程序_安装地暖施工程序有哪些 安装地暖技术要求是什么【详解】...
  3. P2014 选课 (树形动规)
  4. java中if 运算符_[Java]Java基本语法结构(运算符,流程控制语句,if语句)
  5. javascript 文件的同步加载与异步加载
  6. 如何安装python3.8.1_python3.8.1 安装
  7. char赋值字符串常量和数值的区别
  8. FinSpy 发布 Mac 和 Linux OS 版本攻击埃及组织机构
  9. CSS基础选择器之标签选择器(CSS、HTML)
  10. 新手如何使用Docker来搭建PHP开发环境?
  11. 你所需要的只是注意力
  12. iOS开发RunLoop学习:三:Runloop相关类(source和Observer)
  13. Java实现贪吃蛇(汪汪队)游戏,自定义游戏背景音乐,背景图片和游戏图标
  14. 大厂工作3年,我决定把大学到现在7年所有珍藏的书籍都分享一遍
  15. 在北京这种城市,周末假期怎么整才算浪......
  16. ICLR 2020 图神经学习论文汇总
  17. Adobe证书含金量
  18. 查看连接网络的WiFi密码
  19. MATLAB 3D极坐标绘图
  20. 5G WiFi的信号难题:穿墙性能太差

热门文章

  1. jaxb java_JAXB xml与javaBean的转换
  2. 全网最牛12306抢票神器!!!
  3. 电大计算机应用基础作业3实操,国开电大20秋学期计算机应用基础作业3 模块4 PowerPoint 2010实操题答案...
  4. Hadoop读书笔记(八)MapReduce 打成jar包demo
  5. 【新星计划回顾】第一篇学习计划-通过变量定义简单批量模拟数据
  6. 过椭圆外一点引两条切线方程_过椭圆上任意一点的切线方程引发的思考与结论...
  7. macvimrc位置_macvim的配置
  8. 智能建筑市场分析 绿色环保成为主要趋势
  9. CSS:列表样式(设置列表项的标志图案/位置)
  10. db2 随机数函数_db2产生随机数