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

1.声明权限

在AndroidManifest.xml文件中添加BLE相关的权限声明。

<!-- 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><!-- 安卓12开始需要下列权限 compileSDK 32+ -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /><!--安卓6.0以及以上版本需要添加定位的权限 (需要在代码中动态申请)-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" /><!--如果你的app只为具有BLE的设备提供,请声明-->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

2.判断设备是否支持BLE以及蓝牙是否打开

/***  判断设备是否支持BLE*/
fun checkSupportBLE(context: Context):Boolean{val packageManager: PackageManager = context.packageManagerreturn packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}/*** 判断蓝牙是否打开*/
fun isBluetoothEnabled(context: Context):Boolean{val bluetoothManager = BluetoothAdapter.getDefaultAdapter()return bluetoothAdapter == null || bluetoothAdapter?.isEnabled == false
}

3.进行扫描

val scanCallback: ScanCallback = object : ScanCallback() {override fun onScanResult(callbackType: Int, result: ScanResult?) {val device= result?.getDevice()// 处理扫描到的设备}
}val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
bluetoothAdapter.bluetoothLeScanner.startScan(scanCallback)

4.建立连接并监听

在BluetoothGattCallback进行监听相关回调

val gattCallback = object : BluetoothGattCallback() {override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {if (newState == BluetoothProfile.STATE_CONNECTED) {// 连接成功,进行服务发现gatt?.discoverServices()} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {// 连接断开,处理断开逻辑}}override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {if (status == BluetoothGatt.GATT_SUCCESS) {// 服务发现成功,处理服务和特征值val services = gatt?.servicesservices?.let {for (service in it) {// 处理服务和特征值}}} else {// 服务发现失败}}override fun onCharacteristicRead(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic,value: ByteArray,status: Int) {if (status == BluetoothGatt.GATT_SUCCESS) {Log.i(TAG, "读取特征值")// 从特征值读取数据// characteristic 是特征值,而特征值是用 16bit 或者 128bit,16bit 是官方认证过的,128bit 是可以自定义的val sucString = characteristic.value}}override fun onCharacteristicWrite(gatt: BluetoothGatt?,characteristic: BluetoothGattCharacteristic?,status: Int) {super.onCharacteristicWrite(gatt, characteristic, status)if (status == BluetoothGatt.GATT_SUCCESS) {Log.i(TAG, "写入特征值")}}override fun onCharacteristicChanged(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic,value: ByteArray) {Log.i(TAG, "特征值${characteristic.uuid.toString()}变化")}override fun onDescriptorRead(gatt: BluetoothGatt,descriptor: BluetoothGattDescriptor,status: Int,value: ByteArray) {Log.i(TAG, "描述符${descriptor.uuid.toString()}读取")Log.i(TAG, "描述符值:${String(descriptor.value)}")}override fun onDescriptorWrite(gatt: BluetoothGatt?,descriptor: BluetoothGattDescriptor?,status: Int) {Log.i(TAG, "描述符${descriptor?.uuid.toString()}写入")}override fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) {super.onReadRemoteRssi(gatt, rssi, status)//rssi值是蓝牙的信号值,离得越远信号越小Log.i(TAG, "蓝牙信号值:$rssi")}
}val gatt: BluetoothGatt = bluetoothDevice.connectGatt(context, false, gattCallback)

5.读取特征值

 /*** 读取特征值,读取成功后将回调在BluetoothGattCallback的onCharacteristicRead方法中*/
fun readCharacteristic(characteristic: BluetoothGattCharacteristic){//设置特征值变化通知,必须设置,否则无法监听特征值变化情况bluetoothGatt?.setCharacteristicNotification(characteristic, true)//读取特征值bluetoothGatt?.readCharacteristic(characteristic)
}

6.写入特征值

/***  写入特征值,完成后将回调在BluetoothGattCallback的onCharacteristicWrite方法中*/
fun writeCharacteristic(characteristic: BluetoothGattCharacteristic){bluetoothGatt?.writeCharacteristic(characteristic)
}

7.断开连接

fun disconnect(){bluetoothGatt?.disconnect()bluetoothGatt?.close()
}

8.分包

在Android BLE通信中,如果要发送的数据大小超过MTU(最大传输单元)的限制,就需要进行数据分包处理。BLE蓝牙一包数据最多为20字节,因此安卓系统下最好不要使用BLE蓝牙传输大量数据。以下是一种常见的方法来实现BLE数据分包发送:

(1)获取MTU大小:首先,通过调用BluetoothGatt对象的requestMtu()方法来请求MTU大小,例如:

val mtu = 20// 设置期望的MTU大小
bluetoothGatt.requestMtu(mtu)

注意:requestMtu设置不一定会成功,每个版本的蓝牙都有不同的最大值,设置时尽量小一点,一般在onConnectionStateChange中判断连接设备成功后调用这个方法,然后再去搜索Service

(2)监听MTU更新:在BluetoothGattCallback中的onMtuChanged()回调方法中处理MTU更新结果:

override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {if (status == BluetoothGatt.GATT_SUCCESS) {// MTU更新成功,可以开始发送数据sendData(bluetoothGatt, data, mtu)} else {// MTU更新失败,处理失败逻辑}
}

(3)数据分包发送:根据MTU大小将要发送的数据拆分成多个分包,并通过BluetoothGattCharacteristicsetValue()writeCharacteristic()方法进行发送。以下是一个简单的示例:

/*** 往指定特征值写数据,分包*/
fun sendData(characteristic: BluetoothGattCharacteristic, data: ByteArray, mtu: Int) {Thread {val packetSize = mtu - 3 // 减去3个字节的包头// 将数据拆分为分包并发送var offset = 0while (offset < data.size) {val packet = data.sliceArray(offset until minOf(offset + packetSize, data.size))characteristic?.value = packetbleClient?.bluetoothGatt?.writeCharacteristic(characteristic)offset += packet.size}Log.d(BleClient.TAG, "发送完毕..")}.start()
}

在这个示例中,我们使用MTU大小减去3个字节(包头),得到每个分包的大小。然后,将要发送的数据按照分包大小拆分成多个分包,并通过setValue()方法设置分包数据,再通过writeCharacteristic()方法发送分包。

需要注意的是,每个分包的大小应该小于或等于MTU减去3个字节。另外,数据的接收端也需要对分包进行合并和处理,以确保正确接收和还原原始数据。

Android低功耗蓝牙(BLE)开发(二)相关推荐

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

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

  2. Android低功耗蓝牙BLE

    低功耗蓝牙BLE与传统的蓝牙相比最大的优势是功耗降低90%,同时传输距离增大(超过100米).安全和稳定性提高(支持AES加密和CRC验证),允许Android应用程序与具有更严格电源要求的BLE设备 ...

  3. 经典蓝牙与低功耗蓝牙BLE开发基础知识:服务、特征、属性、UUID

    经典蓝牙和低功耗蓝牙BLE的区别 蓝牙大致被认为是1.0 2.0 3.0 4.0版本,不过现在已经不再用版本号区分蓝牙了,蓝牙1.0~3.0都是经典蓝牙,在塞班系统就已经开始使用了.而蓝牙4.0开始就 ...

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

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

  5. 微信小程序低功耗蓝牙(BLE)开发总结

    1.准备 低功耗蓝牙模块:(链接)蓝牙模块购买通道 相关参数数据(UUID表): 需要知道服务ID(serviceID) ,响应特征值 ID(notify characteristic UUID),写 ...

  6. Android蓝牙BLE开发

    最近正在研究Android的蓝牙BLE开发学习,以下是自己做的个人总结 1.1何为BLE? 首先得说明什么是低功耗蓝牙BLE,BLE的全称为Bluetooth low energy(或称Blooth ...

  7. 泰凌微ble mesh蓝牙模组天猫精灵学习之旅④如何在Android开发低功耗蓝牙ble控制 TB-02 模块,代码工程全部开源!(附带Demo)

    本<泰凌微ble mesh蓝牙模组天猫精灵学习之旅>系列博客学习由半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1.小白也痴迷,如 ...

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

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

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

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

最新文章

  1. mysql 常用操作
  2. zookeeper平滑升级_zookeeper从3.4.8升级到3.4.14
  3. raft算法动画演示
  4. awk或者sed识别和替换数据中最后一列的缺失值(转载)
  5. 今日头条上传图片时设置封面图报像素低的原因是什么
  6. 小米8青春版超级夜景安排上了 这个样张我是服气的!
  7. c# webform ajax操作,C#-WebForm-AJAX阿贾克斯(一)基本格式
  8. Python绘制带标记和箭头的树结构
  9. VS2013 启动时遇到空白窗口
  10. C# 生成高清缩略图
  11. 浏览器tab切换最小化,当前页面无操作刷新页面
  12. 微波工程基础_军工央企丨上海微波设备研究所
  13. Linux驱动开发-编写DS18B20驱动
  14. mysql创建唯一非聚集索引_创建聚集索引、非聚集索引、唯一索引、唯一键约束...
  15. 虚幻4英雄联盟模型分享——荆棘之刺婕拉
  16. 今日头条 ANR 优化实践系列 - Barrier 导致主线程假死
  17. cesium 贴地+空间+面积测量
  18. MobileNext:打破常规,依图逆向改造inverted residual block | ECCV 2020
  19. tornado源码分析(四)之future、gen.coroutine
  20. IT30: IT人创业项目路演!!!

热门文章

  1. 甜甜花酿鸡(自学研究代码实现)
  2. ncp1342替代料65w氮化镓充电器芯片PN8213
  3. Qt Quick 3D学习:使用鼠标键盘控制节点位置和方向
  4. 西门子PLC1215C与KTP700HMI创建配方设置实例
  5. CSDN日报20170420 ——《开发和产品之间的恩怨从何来?》
  6. 60岁大爷开甜品店,成功解决甜品店的客流和营业额下滑的问题!
  7. SMTP协议解析及C/C++代码实现
  8. 远程服务器器获取session 信息失败,该如何应对
  9. 数据预处理之标准化(Standardization)、归一化(Normalization)、中心化/零均值化(Zero-centered)
  10. 三维后处理与重建PACS源码,大容量图像存储 报告单多种模式及自定义样式