蓝牙开发心得

-by 李泽君 2019-11-19


核心类:

BluetoothAdapter.getDefaultAdapter();

可以判断手机是否支持蓝牙.

一,蓝牙扫描:

区分Android版本:

1
2
3
4
5
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
bluetoothAdapter.getBluetoothLeScanner().startScan(bluetoothScanCall);
} else {
bluetoothAdapter.startLeScan(bluetoothLeScanCall);
}


执行扫描之后可以设置回调方法:
bluetoothScanCallbluetoothLeScanCall的扫描结果里,可以自己封装类一个统一的接口去返回给应用层处理扫描出来的设备:


1
2
3
4
5
6
7
8
9
10
11
 @Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
final BluetoothDevice device = result.getDevice();
final ScanRecord scanRecord = result.getScanRecord();
// String sss = TransformUtil.getInstance().bytesToHex(scanRecord.getBytes());
// Log.e(TAG, "广播数据包:" + sss + "\t长度:" + sss.length());
if (weakReference.get() != null && device != null) {
weakReference.get().addBluetoothDevice(device, scanRecord.getBytes());
}
}

二,连接蓝牙

拿到上一步中的蓝牙mac地址执行:

1
bluetoothAdapter.getRemoteDevice(mac).connectGatt(context, false, bluetoothGattCallback);

bluetoothGattCallbackonServicesDiscovered方法里可以获得服务列表:
服务列表就是用来与蓝牙进行通讯的服务:
补充几个知识点:

关于BLE数据传输:

  • a.profile可以理解为一种规范,一个标准的通信协议,其存在于手机中,蓝牙组织规定了一些标准的profile:HID OVER GATT ,防丢器等,每个profile中包含了多个service。

  • b.service 可以理解为一个服务,在BLE从机中有多个服务,电量信息,系统服务信息等,每一个service中包含了多个characteristic特征值,每一个具体的characteristic特征值才是BLE通信的主题。

  • c.characteristic特征值:BLE主机从机通信均是通过characteristic进行,可以将其理解为一个标签,通过该标签可以读取或写入相关信息。

  • d. UUID(统一标识码):service和characteristic均需要这个唯一的UUID进行标识。

  • e. 我们app也可以通过写入一些信息到这个对象(characteristic)发送给设备,设备收到之后就会执行我们的要它做的动作了。其实也就和平常我们的对象赋值一样(setValue(“fuzhi”)),只是方法不同而已,一个是set一个是write。

最后来举个例子简答说明一下:其实说白了characteristic特征值就好比一支球队的各个球员,service好比这个球队的名称,profile就当国家吧,假如我们要找到某一个球员,世界这么多国家第一需要知道是哪个国家的,第二需要知道是哪个球队的,最后才知道是那个球员,只有这样最后才能了解这个球员的一些信息(类似从ble设备获取信息),相反也只有这样找到球员后告诉这个球员应该怎么打球的(类似对ble设备设置信息)

一般来讲文档上会写:

三, 发送数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//发送byte[]  对信令进行转义
byte[] ff6206FD0100FD01012C05FES = TransformUtil.getInstance().hexStringToByteArray("FF6206FD0100FD01012C05FE");
//根据上一步获得的service和characteristic的uuid进行通信:
UUID characterUuid = UUID.fromString("0000ff01-0000-1000-8000-00805f9b34fb");
UUID serviceUuid = UUID.fromString("0000ff12-0000-1000-8000-00805f9b34fb");
if (characterUuid != null && serviceUuid != null) {
for (BluetoothGattCharacteristic characteristic2 : bluetoothGatt.getService(serviceUuid).getCharacteristics()) {
if ((characteristic2.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
//注册监听之后 会在bluetoothGattCallback的onCharacteristicChanged()方法中获取蓝牙设备的发送de数据
bluetoothGatt.setCharacteristicNotification(characteristic2, true);
}
}
BluetoothGattCharacteristic characteristic = bluetoothGatt.getService(serviceUuid).getCharacteristic(characterUuid);
characteristic.setValue(bytes);
bluetoothGatt.writeCharacteristic(characteristic);
Log.e(TAG, "发送数据...");
}

写入成功会回调bluetoothGattCallbackonCharacteristicWrite, 在该监听中查看发发送指令.

四, 自动连接:

首先能够自动连接的前提条件是必须有一次蓝牙连接而且连接的配对信息不能删除;
想要在app中自动连接上次连接的设备,我们必须在app关闭之前保存登录的蓝牙设备信息,这里我们用SharedPreferences来帮助我们保存文件;在下次打开app时我们必须先从文件中得到上次蓝牙的信息并且找到设备,配对。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public  void autoConnect(){
SharedPreferences pref=getSharedPreferences( "device",MODE_PRIVATE);
String deviceAddress=pref.getString("address","");
if (deviceAddress!=null){
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
.getBondedDevices();// 获取本机已配对设备
if (pairedDevices.size() > 0) {
for (BluetoothDevice device1 : pairedDevices) {
if (device1.getAddress().equals(deviceAddress))
device=device1;
break;
}
}
}
}

private void getDeviceAndConnect(){
final Intent intent = this.getIntent();
device =intent.getParcelableExtra("device");
if (device==null){
autoConnect();
}
if (device!=null){
progressDialog.show();
new ConnectThread(device).start();}
}