0
点赞
收藏
分享

微信扫一扫

【Android -- 蓝牙】BLE 蓝牙开发入门


文章目录

  • ​​初识低功耗蓝牙​​
  • ​​1. Service​​
  • ​​2. Characteristic​​
  • ​​二、Android BLE API 简介​​
  • ​​三、梳理整体逻辑(思路/步骤)​​
  • ​​四、实战​​
  • ​​1. 权限问题​​
  • ​​2. 搜索蓝牙​​
  • ​​3. 连接蓝牙​​
  • ​​4. 获取特征​​
  • ​​5. 发送消息​​
  • ​​6. 接收消息​​
  • ​​7. 释放资源​​

初识低功耗蓝牙

Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)的核心功能并提供了相应的 API, 应用程序通过这些 API 扫描蓝牙设备、查询 services、读写设备的 characteristics(属性特征)等操作。

Android BLE 使用的蓝牙协议是 GATT 协议,有关该协议的详细内容可以参见蓝牙官方文档。以下我引用一张官网的图来大概说明 Android 开发中我们需要了解的一些 Bluetooth Low Energy 的专业术语。

【Android -- 蓝牙】BLE 蓝牙开发入门_蓝牙

1. Service

一个低功耗蓝牙设备可以定义许多 Service, Service 可以理解为一个功能的集合。设备中每一个不同的 Service 都有一个 128 bit 的 UUID 作为这个 Service 的独立标志。蓝牙核心规范制定了两种不同的UUID,一种是基本的UUID,一种是代替基本UUID的16位UUID。所有的蓝牙技术联盟定义UUID共用了一个基本的UUID:
​​​0x0000xxxx-0000-1000-8000-00805F9B34FB​​​ 为了进一步简化基本UUID,每一个蓝牙技术联盟定义的属性有一个唯一的16位UUID,以代替上面的基本UUID的‘x’部分。例如,心率测量特性使用0X2A37作为它的16位UUID,因此它完整的128位UUID为:
​0x00002A37-0000-1000-8000-00805F9B34FB​

2. Characteristic

在 Service 下面,又包括了许多的独立数据项,我们把这些独立的数据项称作 Characteristic。同样的,每一个 Characteristic 也有一个唯一的 UUID 作为标识符。在 Android 开发中,建立蓝牙连接后,我们说的通过蓝牙发送数据给外围设备就是往这些 Characteristic 中的 Value 字段写入数据;外围设备发送数据给手机就是监听这些 Charateristic 中的 Value 字段有没有变化,如果发生了变化,手机的 BLE API 就会收到一个监听的回调。

更详细的内容可以参见:

  • ​​GATT Services​​
  • ​​GATT specification​​

二、Android BLE API 简介

  • BluetoothAdapter
    BluetoothAdapter 拥有基本的蓝牙操作,例如开启蓝牙扫描,使用已知的 MAC 地址 (BluetoothAdapter#getRemoteDevice)实例化一个 BluetoothDevice 用于连接蓝牙设备的操作等等。
  • BluetoothDevice
    代表一个远程蓝牙设备。这个类可以让你连接所代表的蓝牙设备或者获取一些有关它的信息,例如它的名字,地址和绑定状态等等。
  • BluetoothGatt
    这个类提供了 Bluetooth GATT 的基本功能。例如重新连接蓝牙设备,发现蓝牙设备的 Service 等等。
  • BluetoothGattService
    这一个类通过 BluetoothGatt#getService 获得,如果当前服务不可见那么将返回一个 null。这一个类对应上面说过的 Service。我们可以通过这个类的 getCharacteristic(UUID uuid) 进一步获取 Characteristic 实现蓝牙数据的双向传输。
  • BluetoothGattCharacteristic
    这个类对应上面提到的 Characteristic。通过这个类定义需要往外围设备写入的数据和读取外围设备发送过来的数据。

三、梳理整体逻辑(思路/步骤)

  1. 权限问题:先判断手机是否满足android4.3以上版本,再判断手机是否开启蓝牙。
  2. 搜索蓝牙:搜索蓝牙,回调接口中查看ble设备相关信息,一定时间停止扫描。
  3. 连接蓝牙:首先获取到ble设备的mac地址,然后调用connect()方法进行连接。
  4. 获取特征:蓝牙连接成功后,需要获取蓝牙的服务特征等,然后开启接收设置。
  5. 发送消息:writeCharacteristic()方法,发送数据给ble设备。
  6. 接收消息:通过蓝牙的回调接口中onCharacteristicRead()方法,接收蓝牙收的消息。
  7. 释放资源:断开连接,关闭资源。

四、实战

【Android -- 蓝牙】BLE 蓝牙开发入门_数据_02

【Android -- 蓝牙】BLE 蓝牙开发入门_数据_03

1. 权限问题

  • 在 AndroidManifest.xml 中声明权限

<!-- 蓝牙所需权限 -->
<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" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />

  • 获取蓝牙适配器

BluetoothManager  mBluetoothManager =(BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();

  • 判断手机蓝牙是否被打开

mBluetoothAdapter.isEnabled()

如果返回true,这个时候就可以扫描了
如果返回false,这时候需要打开手机蓝牙。 可以调用系统方法让用户打开蓝牙。

Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
startActivity(enable);

2. 搜索蓝牙

  • 开始扫描

//10s后停止搜索
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, 1000 * 10);

UUID[] serviceUuids = {UUID.fromString(service_uuid)};
mBluetoothAdapter.startLeScan(serviceUuids, mLeScanCallback);

  • 扫描的回调

//蓝牙扫描回调接口
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback(){
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (device.getName() == null) {
return;
}
Log.e("--->搜索到的蓝牙名字:", device.getName());
//可以将扫描的设备弄成列表,点击设备连接,也可以根据每个设备不同标识,自动连接。

}
};

3. 连接蓝牙

  • 获取设备的mac地址,然后连接。

//获取所需地址
String mDeviceAddress = device.getAddress();
BluetoothGatt mBluetoothGatt = device.connectGatt(context, false, mGattCallback);

  • onConnectionStateChange()被调用
    连接状态改变时,mGattCallback中onConnectionStateChange()方法会被调用,当连接成功时,需要调用
    mBluetoothGatt.discoverServices();去获取服务。
  • onServicesDiscovered()被调用
    调用mBluetoothGatt.discoverServices();方法后,onServicesDiscovered()这个方法会被调用,说明发现当前设备了。然后我们就可以在里面去获取BluetoothGattService和BluetoothGattCharacteristic。

// BLE回调操作
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,int newState){
super.onConnectionStateChange(gatt, status, newState);

if (newState == BluetoothProfile.STATE_CONNECTED) {
// 连接成功

mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// 连接断开
Log.d("TAG","onConnectionStateChange fail-->" + status);
}
}

@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
//发现设备,遍历服务,初始化特征
initBLE(gatt);
} else {
Log.d("TAG","onServicesDiscovered fail-->" + status);
}
}

@Override
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status){
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// 收到的数据
byte[] receiveByte = characteristic.getValue();

}else{
Log.d("TAG","onCharacteristicRead fail-->" + status);
}
}

@Override
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic){
super.onCharacteristicChanged(gatt, characteristic);
//当特征中value值发生改变
}

/**
* 收到BLE终端写入数据回调
* @param gatt
* @param characteristic
* @param status
*/
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// 发送成功

} else {
// 发送失败
}
}

@Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {

}
}

@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
if (status == BluetoothGatt.GATT_SUCCESS) {

}
}

@Override
public void onDescriptorRead(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {

}
}
};

4. 获取特征

  • ble设备相关的UUID

//写通道uuid
private static final UUID writeCharactUuid = UUID.fromString("0000fff6-0000-1000-8000-00805f9b34fb");
//通知通道 uuid
private static final UUID notifyCharactUuid =UUID.fromString( "0000fff7-0000-1000-8000-00805f9b34fb");

  • 获取bluetoothGattCharacteristic(因为有的设备可能存在双服务的情况,所以这里遍历所有服务)

//初始化特征
public void initBLE(BluetoothGatt gatt) {
if (gatt == null) {
return;
}
//遍历所有服务
for (BluetoothGattService BluetoothGattService : gatt.getServices()) {
Log.e(TAG, "--->BluetoothGattService" + BluetoothGattService.getUuid().toString());

//遍历所有特征
for (BluetoothGattCharacteristic bluetoothGattCharacteristic : BluetoothGattService.getCharacteristics()) {
Log.e("---->gattCharacteristic", bluetoothGattCharacteristic.getUuid().toString());

String str = bluetoothGattCharacteristic.getUuid().toString();
if (str.equals(writeCharactUuid)) {
//根据写UUID找到写特征
mBluetoothGattCharacteristic = bluetoothGattCharacteristic;
} else if (str.equals(notifyCharactUuid)) {
//根据通知UUID找到通知特征
mBluetoothGattCharacteristicNotify = bluetoothGattCharacteristic;
}
}
}
}

  • 开启通知

.setCharacteristicNotification(mGattCharacteristicNotify, true);

5. 发送消息

.setValue(sData);
if (mBluetoothGatt != null) {
mBluetoothGatt.setCharacteristicNotification(notifyCharactUuid , true);
mBluetoothGatt.writeCharacteristic(mGattCharacteristicWrite );
}

6. 接收消息

@Override
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status){
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
// 收到的数据
byte[] receiveByte = characteristic.getValue();

}else{
Log.d("TAG","onCharacteristicRead fail-->" + status);
}
}

7. 释放资源

public boolean disConnect() {
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
return true;
}
return false;
}


举报

相关推荐

0 条评论