在上一篇文章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.packageManager
return 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?.services
services?.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大小将要发送的数据拆分成多个分包,并通过BluetoothGattCharacteristic
的setValue()
和writeCharacteristic()
方法进行发送。以下是一个简单的示例:
/**
* 往指定特征值写数据,分包
*/
fun sendData(characteristic: BluetoothGattCharacteristic, data: ByteArray, mtu: Int) {
Thread {
val packetSize = mtu - 3 // 减去3个字节的包头
// 将数据拆分为分包并发送
var offset = 0
while (offset < data.size) {
val packet = data.sliceArray(offset until minOf(offset + packetSize, data.size))
characteristic?.value = packet
bleClient?.bluetoothGatt?.writeCharacteristic(characteristic)
offset += packet.size
}
Log.d(BleClient.TAG, "发送完毕..")
}.start()
}
在这个示例中,我们使用MTU大小减去3个字节(包头),得到每个分包的大小。然后,将要发送的数据按照分包大小拆分成多个分包,并通过setValue()
方法设置分包数据,再通过writeCharacteristic()
方法发送分包。文章来源:https://www.toymoban.com/news/detail-486715.html
需要注意的是,每个分包的大小应该小于或等于MTU减去3个字节。另外,数据的接收端也需要对分包进行合并和处理,以确保正确接收和还原原始数据。文章来源地址https://www.toymoban.com/news/detail-486715.html
到了这里,关于Android低功耗蓝牙(BLE)开发(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!