BLE Android 应用 开发

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

1.权限设置

    <uses-feature android:name="android.hardware.location.gps" /><uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

这里有人可能疑惑,使用蓝牙为啥要定位权限,其实蓝牙技术是可以实现定位的,要使用蓝牙必须要申请定位权限,android 9 之后动态权限申请

private void checkPermission() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {int fine_location = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION);int cross_location = checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION);if (fine_location != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 1);} else {finish();return;}if (cross_location != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);} else {finish();return;}}}

动态申请,提示的是申请定位权限,这点个不要奇怪。

2.获取蓝牙设备管理器

private void getBleAdapter() {if (mAdapter != null) {return;}BluetoothManager bluetoothManager =(BluetoothManager) context.getSystemService (Context.BLUETOOTH_SERVICE);mAdapter = bluetoothManager.getAdapter ();}

这里获取到的是一个蓝牙适配器BluetoothAdapter ,后续通过适配器调用蓝牙适配器。

3.设备搜索

mAdapter.startLeScan (leScanCallback);
BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback () {@Overridepublic void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {//device.getName()  设备名称//device.getAddress()  mac地址}};

这个搜索方法在21 已经过期了后续使用

 mAdapter.getBluetoothLeScanner ().startScan (new ScanCallback () {@Overridepublic void onScanResult(int callbackType, ScanResult result) {super.onScanResult (callbackType, result);//    BluetoothDevice device= result.getDevice ();  获取设备对象//   result.getRssi ()  信号强度,根据这个可以计算出距离服务端蓝牙的距离}});

3.1 停止搜索

mAdapter.stopLeScan (leScanCallback);

同样这个方法21后过期了,可以使用新的api

mAdapter.getBluetoothLeScanner ().stopScan(// 搜索接口实例);

在搜到合适设备或者想停止设备搜索时可以调用这个api停止搜索。

  • 注意:如果去连接设备时,同时还在搜索设备,建议先调用stopScan 停止搜索,然后再连接,这样可以提高效率。

4.设备连接

一般情况下,根据业务不同有可能我们会将搜索到的BluetoothDevice 保存下来。
再次使用时可以用

BluetoothDevice device = mAdapter.getRemoteDevice (deviceInfo.getAddress ());

如果device 是空的,说明设备可能已经关闭了,后边就没必要链接了。
如果是直接搜索到连接可以直接用搜到的BluetoothDevice 直接连接。

BluetoothGatt  currentBindGatt = device.connectGatt (context, true, bluetoothGattCallback);
public BluetoothGatt connectGatt(Context context, boolean autoConnect,BluetoothGattCallback callback) {return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));}
  • autoConnect 是否重连,如果true 异常断开后下次还会重新连接。
  • bluetoothGattCallback 连接回掉状态
   BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback () {@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {// 这个是发现服务,在这里可以注册蓝牙的通知LogS.d (TAG, "onServicesDiscovered()");if (gatt == null || gatt.getDevice () == null) {LogS.d (TAG, "Android GATT invalid!");return;}UUID uuid = BeanBleUtil.parseUUID (BeanCSConstant.PROFILE_FORMAT_SERVER_UUID);if (status == BluetoothGatt.GATT_SUCCESS) {//查询支持的Server uuidList<BluetoothGattService> services = gatt.getServices ();if (services != null) {for (BluetoothGattService service : services) {LogS.d (TAG, "onServicesDiscovered:" + service.getUuid ());}}//查询支持的Characteristic uuidBluetoothGattService service = gatt.getService (uuid);if (service == null) {LogS.d (TAG, "BluetoothGattService == null");return;}List<BluetoothGattCharacteristic> list = service.getCharacteristics ();if (list != null) {for (BluetoothGattCharacteristic bluetoothGattCharacteristic : list) {//这里将需要监听的通知进行注册,如果不需要监听,可以不用管这里List<UUID> listUUids = NoticeUUidList ();if (bluetoothGattCharacteristic != null && listUUids.contains (bluetoothGattCharacteristic.getUuid ())) {LogS.d (TAG, "readData support uuid:" + bluetoothGattCharacteristic.getUuid ().toString ());enableNotification (true, gatt, bluetoothGattCharacteristic);}}}}}@Overridepublic void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {LogS.d (TAG, "onConnectionStateChange " + status + " ===> " + newState);if (gatt == null) {LogS.d (TAG, "gatt handler null");return;}BaseDeviceInfo cInfo = deviceHashMap.get (gatt.getDevice ().getAddress ());if (cInfo != null) {LogS.d (TAG, "onConnectionStateChange 链接成功,开始赋值对象:" + gatt.getDevice ().getAddress ());}if (status != BluetoothGatt.GATT_SUCCESS) {gatt.disconnect ();gatt.close ();LogS.d (TAG, "--GATT_SUCCESS");currentBindGatt = null;      LogS.d (TAG, "GATT_SUCCESS 连接失败操作");return;}}if (newState == BluetoothGatt.STATE_CONNECTED) {//连接成功} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {//链接失败}}//读取@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {//数据的读取结果或者通知会通过这个函数返回LogS.d (TAG, "onCharacteristicRead:" + gatt.getDevice ().getName () + " address:" + gatt.getDevice ().getAddress () + " status:" + status + "characteristic.getUuid ():" + characteristic.getUuid ());if (status == BluetoothGatt.GATT_SUCCESS) {byte[] value = characteristic.getValue ();if (value != null) {StringBuilder builder = new StringBuilder ();for (byte data : value) {//以十六进制的形式输出LogS.d (TAG, "---------" + String.format ("%02X ", data));builder.append (data);}LogS.d (TAG, "onCharacteristicRead:(uuid, value)= " + characteristic.getUuid ()+ "," + builder.toString () + ")");UUID uuid = characteristic.getUuid ();if (uuid == null) {return;}//解析 收到的value 值}}}//写入@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {LogS.d (TAG, "onCharacteristicWrite:" + gatt.getDevice ().getName () + " address:" + gatt.getDevice ().getAddress () + " status:" + status);if (status == BluetoothGatt.GATT_SUCCESS) {byte[] value = characteristic.getValue ();if (value != null) {StringBuilder builder = new StringBuilder ();for (byte data : value) {builder.append (data);}LogS.d (TAG, "onCharacteristicWrite:" + builder.toString ());}} else if (status == BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH) {LogS.d (TAG, "写入操作超出了属性的最大长度");}}@Overridepublic void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {super.onMtuChanged (gatt, mtu, status);LogS.d (TAG, "----onMtuChanged");}//数据变化通知 接收通知消息@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {LogS.d (TAG, "通知回调 onCharacteristicChanged:" + gatt.getDevice ().getName () + " address:" + gatt.getDevice ().getAddress () + "通知uuid:" + characteristic.getUuid ().toString ());byte[] value = characteristic.getValue ();if (value != null) {StringBuilder builder = new StringBuilder ();for (byte data : value) {builder.append (data);}LogS.d (TAG, "接收通知消息:" + builder.toString ());//处理通知消息}}};

5.设备的重连

在很多时候,如果设备已经连接过了,但是中间断开,再次需要链接的时候是不需要再次调用connectGatt 连接方法的。只要调用重连方法就可以了。
重连的前提是之前已经连接过,获取到了BluetoothGatt 实例对象。

 if (currentBindGatt.connect ()) {//调用重连成功,即使设备不在范围内,等设备在范围内可自动连接成功}

6.设备的断开与服务关闭

在需要断开设备时可以调用

currentBindGatt.disconnect ();

调用断开后,后续需要链接时,只需重新调用重连方法即可。
如果需要关闭Gatt 服务可以调用

 currentBindGatt.close ();

调用close 方法后就不能再调用重连方法了,必须重新调用connectGatt ,

  • 在实际的项目中可能会出现重连失败等操作,或者连接失败,这时需要调用下close方法,然后重新connectGatt 。

7.通知的注册与接收

ble支持通知类型的事件,当然,想要收到通知必须提前注册通知的uuid,有些uuid 是蓝牙的标准uuid ,有些则是厂商自定义的uuid .这个要适情况而定。

在Gatt 监听器的 onServicesDiscovered(BluetoothGatt gatt, int status)回掉函数中来注册。

  • 查询支持的Server uuid
    List services = gatt.getServices ();
    这里获取到设备所有的uuid 特服务
  • 查询支持的Characteristic uuid
    BluetoothGattService service = gatt.getService (uuid);
    这里的uuid 用的是181c 一般厂商都会给的,是服务端的uuid 。注意这个uuid 是UUID 类
    需要通过:
    String code = “0000” + 181c+ “-0000-1000-8000-00805f9b34fb”;
    UUID uuid=UUID.fromString(code);
    转为标准的UUID 类。
  • 获取这个服务下的所有特征列表
    List list = service.getCharacteristics ();
    然后比对下是否是我们需要注册的那个uuid 的特征值。
 if (list != null) {for (BluetoothGattCharacteristic bluetoothGattCharacteristic : list) {List<UUID> listUUids =NoticeUUidList ();if (bluetoothGattCharacteristic != null && listUUids.contains (bluetoothGattCharacteristic.getUuid ())) {LogS.d (TAG, "readData support uuid:" + bluetoothGattCharacteristic.getUuid ().toString ());enableNotification (true, gatt, bluetoothGattCharacteristic);}}}

NoticeUUidList 是一个UUID 的list 是我想要监听的通知的uuid ,然后通过BluetoothGattCharacteristic
特征值来注册通知

 /*** 设置是否开启通知*/private boolean enableNotification(boolean enable, BluetoothGattgatt, BluetoothGattCharacteristic characteristic) {if (gatt == null || characteristic == null) return false; boolean setNotification = false;try {String uuid =“2902”;BluetoothGattDescriptor characteristicDescriptor = characteristic.getDescriptor (BeanBleUtil.parseUUID (uuid));if (characteristicDescriptor != null) {byte[] value = enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;characteristicDescriptor.setValue (value);gatt.writeDescriptor (characteristicDescriptor);}setNotification = gatt.setCharacteristicNotification (characteristic, enable);LogS.d (TAG, "设置通知" + characteristic.getUuid ().toString () + "结果:" + setNotification);} catch (Exception e) {LogS.d (TAG, "enableNotification 统一设置通知 失败" + e.getMessage () + "--uuid:" + characteristic.getUuid ().toString ());e.printStackTrace ();}return setNotification;}

2902 是蓝牙特征值的配置uuid ,如果没有配置这个uuid ,设置通知是没有效果的。
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE 是用于启动通知的描述符,必须配置。
然后就是通过 gatt.setCharacteristicNotification 来设置通知的特征值,设置成功后,服务端数据变化发起的通知,客户端就可以收到通知了,通知的接收是 onCharacteristicChanged函数

public static UUID parseUUID(String name) {if (TextUtils.isEmpty(name)) {return null;}String code = "0000" + name + "-0000-1000-8000-00805f9b34fb";if (!TextUtils.isEmpty(code)) {return UUID.fromString(code);}return null;}

8.数据的主动读取

通过蓝牙可以读取设备服务端的值,但是必须通过uuid 来完成。

public boolean readDataByUuid(String uuid) {LogS.d (TAG, "开始读取数据:readData() uuid: " + uuid);boolean ret = false;LogS.d (TAG, "readData:" + BeanBleUtil.parseUUID (uuid).toString ());if (currentBindGatt != null) {BluetoothGattService bleService = currentBindGatt.getService (BeanBleUtil.parseUUID (“181c));if (bleService == null) {Log.e (TAG, "readDataByUuid:  BluetoothGattService==null");return false;}BluetoothGattCharacteristic characteristic = bleService.getCharacteristic (BeanBleUtil.parseUUID (uuid));if (characteristic != null) {ret = currentBindGatt.readCharacteristic (characteristic);}LogS.d (TAG, "readData(" + uuid + ") ret: " + ret);} else {LogS.d (TAG, "readData currentBindGatt == null!");}return ret;}

读取完成后,数据是通过onCharacteristicRead 函数回掉回来。

9.数据的写入

写入和读取类似,都是先获取gatt服务,然后通过服务和uuid 获取特征值,然后写入数据。

public boolean writeByte(byte[] sendValue, String uuid1) {UUID uuid = BeanBleUtil.parseUUID (uuid1);boolean su = false;LogS.d (TAG, "writeByte() sendValue: " + sendValue.toString () + ", uuid: " + uuid);if (currentBindGatt != null) {BluetoothGattService bleService = currentBindGatt.getService (BeanBleUtil.parseUUID (”181c"));BluetoothGattCharacteristic characteristic = bleService.getCharacteristic (uuid);if (characteristic != null) {characteristic.setValue (sendValue);su = currentBindGatt.writeCharacteristic (characteristic);}}return su;}

如果写入成功onCharacteristicWrite 回掉函数会执行。

9.关于UUID

UUID 本身指的是一个类UUID ,他包含uuid ,我们所说的特征值id。
uuid 是一串十六进制组成的数字,提示唯一识别码,就像身份证一样,只不过ble中它代表服务,特征的号码,uuid 是128bit 的,因为太长所有SIG将uuid 进行预设,预设过后uuid 的一些部分就变成了固定部分,就比如我们本次服务的uuid 是: “0000” + 181c+ “-0000-1000-8000-00805f9b34fb”;
除了181c ,其他部分都是固定的。

最后:对于很对没有开发过蓝牙的同学来说需要搞明白,ble 是不需要去配对的,需要配对的是传统蓝牙,这点不要傻傻分不清楚,其次,ble 蓝牙只需要搜索到设备,可以直接连接了,过程相对简单,但是任何设备在连接的过程中都可能发生异常,所以我建议在连接的时候设置超时机制,可以有效减少程序故障。

Android Ble蓝牙开发相关推荐

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

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

  2. Android Ble蓝牙开发总结

    Android Ble蓝牙开发总结 前言 本文总结了ble的搜索,连接,读写操作.以及在开发过程中可能遇到的坑. 首先我们需要知道,什么是ble. 蓝牙发展至今经历了8个版本的更新.1.1.1.2.2 ...

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

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

  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. 我的百度研发面经整合版(智能云,核心搜索) | 掘金技术征文
  2. 【Linux】rpm常用命令及rpm参数介绍
  3. oracle fuser lk,oracle错误集锦
  4. bzoj3959(LCT)
  5. Kettle使用_7 数据校验组件应用
  6. EmberJS路由详解
  7. 高性能mysql 聚簇索引,高性能MySQL笔记-第5章Indexing for High Performance-005聚集索引...
  8. linux 页描述符,Python描述符(descriptor)解密
  9. 前端性能优化方面的知识
  10. centos6.5 mysql登陆_centos6.5下mysql无法登陆的问题
  11. YUV420 总结 (YU12、YV12、NV12 和 NV21)
  12. 微商加人方法,感动你我的加人故事
  13. SHFileOperation 用法
  14. 抖音小程序模板全行业整理合集,抖音小程序制作平台分享
  15. 上次送女神死亡芭比粉口红后,我痛定思痛
  16. 银行数字化转型导师坚鹏:农商行数字化转型案例研究
  17. 海康摄像头浏览器访问不了
  18. Windows定期删除过期文件
  19. UWB定位实验 - 客户端模式(被动式)TDOA定位精度测试
  20. 苹果6手机服务器停止响应,iphone6被停用怎么办?苹果6被停用解决方法汇总

热门文章

  1. blp模型 上读下写_读写模型整理笔记
  2. 腾讯-信鸽实现消息推送
  3. springboot,tkmybatis的逆向工程
  4. k8s拉取镜像失败处理 ImagePullBackOff ErrImageNeverPull
  5. 流程图怎么做,教你制作流程图
  6. 喂,你是在学习还是在逃避?
  7. Windows Server R2 2008 服务器总是自动关机
  8. Findbugs 缺陷详解与英文代号的对照表
  9. 【蓝桥杯Web】大一小白参与蓝桥杯模拟赛二期web组体会
  10. vs qt 无法打开包括文件: “QtCore/qconfig.h”