知识点:
经典蓝牙(Classic Bluetooth)& 低功耗蓝牙(Bluetooth Low Energy)
-
经典蓝牙可以用与数据量比较大的传输,如语音,音乐,较高数据量传输等。
-
BLE 特点就如其名,功耗更低的同时,对数据包做出了限制。所以适用于实时性要求比较高,但是数据速率比较低的产品,如鼠标,键盘,传感设备的数据发送等。
蓝牙 4.0 支持单模和双模两种部署方式,其中单模即是我们说的 BLE,而双模指的是 Classic Bluetooth + BLE 。
实际上,BLE 和经典蓝牙的使用等各方面都像是没有关联的两个东西,甚至因为 BLE 的通讯机制不同,所以是不能向下兼容的;经典蓝牙则可以兼容到蓝牙 3.0 / 2.1。
参考 :https://www.jianshu.com/p/634b4f7154bc
(本篇文章很全,也有代码,可以参考)
开发代码:
权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
广播接收者,用于接收蓝牙广播:
class BluetoothReceive(bleListener: BleListener) : BroadcastReceiver() {
private val mBleListener: BleListener = bleListener
override fun onReceive(context: Context?, intent: Intent) {
val action = intent.action
if (action == BluetoothDevice.ACTION_FOUND) {
val device =
intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
val ssi = intent.extras!!.getShort(BluetoothDevice.EXTRA_RSSI)
val deviceClass = device!!.bluetoothClass.majorDeviceClass
mBleListener.onBleScanListener(device, deviceClass, ssi)
} else if (action == BluetoothAdapter.ACTION_DISCOVERY_FINISHED) {
mBleListener.onScanFinish()
}
}
}
回调:
interface BleListener {
/**
* BLE设备回调
* @param bluetoothDevice 蓝牙设备
* @param type 蓝牙类别(手机等)
* @param ssr 蓝牙信号强度
*/
fun onBleScanListener(bluetoothDevice: BluetoothDevice, type: Int, ssr: Short)
/**
* 搜索完成
*/
fun onScanFinish()
}
核心类就是:BluetoothDevice,蓝牙所有的信息都是从这里面取
Activity注册一下:
// 广播注册
mBluetoothReceive = BluetoothReceive(this)
var intentFilter = IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
mContext.registerReceiver(mBluetoothReceive, intentFilter)
intentFilter = IntentFilter(BluetoothDevice.ACTION_FOUND)
mContext.registerReceiver(mBluetoothReceive, intentFilter)
mAdapter = BluetoothAdapter.getDefaultAdapter()
核心方法:
/**
* 打开蓝牙
*/
override fun startBle() {
if (!mAdapter.isEnabled) mAdapter.enable()
}
/**
* 扫描蓝牙设备
*/
override fun scanBleDevice() {
if (!mAdapter.isEnabled) mAdapter.enable()
if (mAdapter.isDiscovering) {
mAdapter.cancelDiscovery()
mAdapter.startDiscovery()
} else {
// SystemClock.sleep(1000)
mAdapter.startDiscovery()
}
mBleList.clear()
}
/**
* 停止扫描
*/
override fun stopScanBleDevice() {
if (mAdapter.isDiscovering) mAdapter.cancelDiscovery()
}
/**
* 连接
*/
override fun connect(bleBean: BleBean) {
// 获取蓝牙设备
val ble = mBleDevices[bleBean.address]
// 直接连接
mGatt = ble?.connectGatt(mContext, false, mBluetoothGattCallback)!!
}
/**
* 断开当前连接
*/
override fun disConnect() {
mGatt.disconnect()
}
/**
* 释放资源
*/
override fun onDestroy() {
mBleList.clear()
mBleUiImplList.clear()
// 注销广播接收者
this.mContext.unregisterReceiver(mBluetoothReceive)
}
以上是基本调用及连接,下面是读写数据的回调。
// BLE的回调
private val mBluetoothGattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
super.onConnectionStateChange(gatt, status, newState)
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 开始搜索服务
gatt?.discoverServices()
}
// 接受到设备断开的状态后,还要手动调用 close(),否则可能出现连接未断开导致的重连失败等问题;
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
gatt?.close()
// 回调连接状态
for (bleUiImpl in mBleUiImplList) bleUiImpl.onDisConnect()
}
if (newState == BluetoothProfile.STATE_CONNECTING) {
// 设备在连接中
}
}
// 成功发现服务的回调
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
super.onServicesDiscovered(gatt, status)
if (gatt == null) {
return
}
if (status == BluetoothGatt.GATT_SUCCESS) { // 发现蓝牙服务成功
val gattServicesList =
gatt.services
for (i in gattServicesList.indices) {
if (gattServicesList[i].uuid == UUID.fromString(SERVICES_UUID)) { // 如果servicesUUID相同,则做如下处理
// 设置写入特征UUID
mWriteCharacteristic =
gattServicesList[i].getCharacteristic(UUID.fromString(WRITE_UUID))
// 设置监听特征UUID
val notifyCharacteristic =
gattServicesList[i].getCharacteristic(UUID.fromString(NOTIFY_UUID))
// 开启监听
gatt.setCharacteristicNotification(notifyCharacteristic, true)
gatt.setCharacteristicNotification(mWriteCharacteristic, true)
break
}
}
}
for (bleUiImpl in mBleUiImplList) bleUiImpl.onServicesDiscovered(status)
}
/**
* 接收到数据
*/
override fun onCharacteristicRead(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?,
status: Int
) {
// if (status == BluetoothGatt.GATT_SUCCESS) {
// Log.d("123", "收到到数据:")
// }
for (bleUiImpl in mBleUiImplList) bleUiImpl.onServicesDiscovered(status)
super.onCharacteristicRead(gatt, characteristic, status)
}
/**
* 写入数据 调用 writeCharacteristic 的回调
*/
override fun onCharacteristicWrite(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?,
status: Int
) {
super.onCharacteristicWrite(gatt, characteristic, status)
val stringBuilder = StringBuilder()
characteristic?.value
?.filter { it > 0 }
?.forEach { stringBuilder.append(String.format("%c", it)) }
if (characteristic != null)
ToastUtils.showToast("成功发送:".plus(stringBuilder.toString()))
}
// 调用 writeDescriptor 的回调
override fun onDescriptorWrite(
gatt: BluetoothGatt?,
descriptor: BluetoothGattDescriptor?,
status: Int
) {
super.onDescriptorWrite(gatt, descriptor, status)
}
/**
* 硬件返回数据
*/
override fun onCharacteristicChanged(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?
) {
super.onCharacteristicChanged(gatt, characteristic)
val stringBuilder = StringBuilder()
if (characteristic != null) {
characteristic.value?.forEach {
val b = it
// hexStringBuilder.append(Integer.toHexString(b.toInt()))
stringBuilder.append(String.format("%c", b))
}
}
for (bleUiImpl in mBleUiImplList) bleUiImpl.onReceive(
null != characteristic,
stringBuilder.toString()
)
}
}
上述回调部分,可以写你的业务逻辑,这里不贴代码了。。。
以上代码粘贴后改成自己的即可,只是基本的使用。
要注意的点:
1.断开最好调用close,否则下次连接会失败(报133)。当然失败再次连接就好。
2.只能连接BLE设备,连接传统蓝牙设备拿不到回调。
3.如果搜不到BLE设备的话,重启下BLE设备。
传统蓝牙可以参考下面文章:
https://blog.csdn.net/huangliniqng/article/details/82187966
写在最后:
BLE直连、自动连接这种的,可以在以上基础用MAC(特定设备)或者NAME(某类产品)连。