Android Ble蓝牙开发总结
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蓝牙开发总结相关推荐
- Android BLE蓝牙开发知识总结
Android BLE蓝牙开发知识总结 1.蓝牙介绍 1.1什么是蓝牙? 蓝牙( Bluetooth® ):是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据交换(使用2 ...
- Android BLE 蓝牙开发指南(三)外围设备端开发详解
Android BLE开发指南(一)入门基础 Android BLE开发指南(二)中心设备端程序开发详解 这篇文章将会详细讲解低功耗蓝牙外围设备端程序开发的主要流程.对于Android开发者而言,或许 ...
- Android Ble蓝牙开发
BLE Android 应用 开发 1.权限设置 2.获取蓝牙设备管理器 3.设备搜索 3.1 停止搜索 4.设备连接 5.设备的重连 6.设备的断开与服务关闭 7.通知的注册与接收 8.数据的主动读 ...
- Android BLE 蓝牙开发-扫码枪集成
一.蓝牙模式HID与BLE 当扫码枪与手机连接时,通常采用的是蓝牙HID(Human Interface Device)模式.本质上是一个把扫码枪作为一个硬件键盘,按照键盘协议把扫码后的结果逐个输入到 ...
- android ble 蓝牙绑定流程,android BLE蓝牙开发
蓝牙BLE设备是目前比较热门的设备.由于BLE有低功耗等特点,被广泛应用到身边的电子产品上.如智能手表.手环.防丢器等各种产品上.最近研究一下android上的ble应用开发.跟大家分享一下相关的内容 ...
- Android 低功耗蓝牙开发
初识低功耗蓝牙 Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)的核心功能并提供了相应的 API, 应用程序通过这些 API 扫 ...
- Android BLE蓝牙4.0开发 实现扫描、连接、通讯、获取通知、特性等 (一、打开蓝牙 进行扫描)
目录 首先说下蓝牙4.0 目前android蓝牙有2种: ble蓝牙开发流程: 1.首先当然是进行权限申请啦: 2.获取蓝牙适配器 BluetoothAdapter 3.打开蓝牙 4.关闭蓝牙 5.在 ...
- 【Android】蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)
目录 目录 前言 一.相关概念介绍 二.实战开发 三.项目演示 四.Demo案例源码地址 五.更新记录 1.2020/12/29 :修改 setupService()中错误 2.2021/05/14 ...
- 【Android】BLE 蓝牙开发流程篇
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 4 天,点击查看活动详情 前言 本文旨在梳理 BLE 蓝牙开发的主要流程,其中涉及到其他的知识,将会单独成文梳理.如有任何疑问, ...
最新文章
- TurboMail邮件系统通过涉密信息系统产品认定
- 数字图像处理技术详解程序_安装地暖施工程序有哪些 安装地暖技术要求是什么【详解】...
- P2014 选课 (树形动规)
- java中if 运算符_[Java]Java基本语法结构(运算符,流程控制语句,if语句)
- javascript 文件的同步加载与异步加载
- 如何安装python3.8.1_python3.8.1 安装
- char赋值字符串常量和数值的区别
- FinSpy 发布 Mac 和 Linux OS 版本攻击埃及组织机构
- CSS基础选择器之标签选择器(CSS、HTML)
- 新手如何使用Docker来搭建PHP开发环境?
- 你所需要的只是注意力
- iOS开发RunLoop学习:三:Runloop相关类(source和Observer)
- Java实现贪吃蛇(汪汪队)游戏,自定义游戏背景音乐,背景图片和游戏图标
- 大厂工作3年,我决定把大学到现在7年所有珍藏的书籍都分享一遍
- 在北京这种城市,周末假期怎么整才算浪......
- ICLR 2020 图神经学习论文汇总
- Adobe证书含金量
- 查看连接网络的WiFi密码
- MATLAB 3D极坐标绘图
- 5G WiFi的信号难题:穿墙性能太差
热门文章
- jaxb java_JAXB xml与javaBean的转换
- 全网最牛12306抢票神器!!!
- 电大计算机应用基础作业3实操,国开电大20秋学期计算机应用基础作业3 模块4 PowerPoint 2010实操题答案...
- Hadoop读书笔记(八)MapReduce 打成jar包demo
- 【新星计划回顾】第一篇学习计划-通过变量定义简单批量模拟数据
- 过椭圆外一点引两条切线方程_过椭圆上任意一点的切线方程引发的思考与结论...
- macvimrc位置_macvim的配置
- 智能建筑市场分析 绿色环保成为主要趋势
- CSS:列表样式(设置列表项的标志图案/位置)
- db2 随机数函数_db2产生随机数