因爲之前有做與藍牙有關的項目,所以這裏寫個博客總結一下。
附帶了一個項目以供參考:https://github.com/979451341/BleStudy
一.藍牙操作流程
1.獲取藍牙服務
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
2.開啓藍牙
mBluetoothAdapter.enable();
3.搜索藍牙設備
var mScanCallback = object :ScanCallback(){
override fun onScanResult(callbackType: Int, result: ScanResult?) {
}
}
mBluetoothLeScanner.startScan(mScanCallback)
4.連接藍牙設備
//首先獲取設備
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
//建立連接獲取BluetoothGatt對象,並設置監聽
gatts = device.connectGatt(instance, false, mGattCallback);
首先說說BluetoothGatt對象,他是藍牙通信的協議,連接藍牙設備,發現服務,向藍牙設備傳數據和接收藍牙設備的數據,都需經過他。
然後我們通過BluetoothGattCallback的,來監聽這些過程。
private static BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (BluetoothGatt.GATT_SUCCESS == status) {
//開啓監聽成功,可以像設備寫入命令了
}
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
//連接成功
Log.e(TAG, "設備連接上 開始掃描服務");
boolean discoverServices = gatt.discoverServices();
if (discoverServices) {
}
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//發現服務
String address = gatt.getDevice().getAddress();
//綁定特徵
bindCharas(address, getSupportedGattServices(address));
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//characteristic.getValue()爲設備發送的數據,根據數據協議進行解析,對應onCharacteristicRead
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// characteristic.getValue()爲設備發送的數據,根據數據協議進行解析,對應onCharacteristicChanged
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.e(TAG, "發送成功");
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
}
};
其中綁定特徵需要詳細說說,一個藍牙設備有多個BluetoothGattService服務,一個服務有多個BluetoothGattCharacteristic特徵,一個特徵有多個BluetoothGattDescriptor描述。
其中我們是通過UUID來區別特徵,這個由硬件工程師提供。
我們剛連接藍牙,需要獲取藍牙設備傳過來的數據。首先獲取 read的特徵,然後獲取 通知描述,並給 mBluetoothGatt,使其知道我們需要接受通知
//獲取服務
mBluetoothGatt.getServices()
//獲取read特徵
private static void bindCharas(String address, List<BluetoothGattService> gattServices) {
for (BluetoothGattService gattService : gattServices) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
String uuid_str = gattCharacteristic.getUuid().toString();
if (uuid_str.equalsIgnoreCase(Constant.SMART_TAG_READ_UUID)) {
BluetoothGattCharacteristic mReadCharacteristic = gattCharacteristic;
setCharacteristicNotification(address, mReadCharacteristic, true);
}
}
}
}
5.手機傳送命令
首先獲取write特徵
for (BluetoothGattService gattService : mBluetoothGatt.getServices()) {
uuid = gattService.getUuid().toString();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
// Loops through available Characteristics.
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
uuid = gattCharacteristic.getUuid().toString();
if (uuid.equalsIgnoreCase(Constant.SMART_TAG_WRITE_UUID)) {
return gattCharacteristic;
}
}
}
然後給特徵賦值,給gatt發出命令
boolean write = characteristic.setValue(cmd);
mBluetoothGatt.writeCharacteristic(characteristic);
6.斷開藍牙
在我們退出應用時,需斷開連接
gatts.disconnect();
gatts.close();
二.藍牙通信如何寫入項目
1.藍牙通信模塊放哪
我們需要將藍牙通信模塊放在一個生命週期和應用相當的對象裏,比如Application,不過這個類承擔了很多sdk初始化的任務,所以我認爲應該交給Service。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, BleService::class.java))
} else {
startService(Intent(this, BleService::class.java))
}
2.數據分發
在Service裏初始化藍牙服務,在BluetoothGattCallback裏監聽藍牙連接的狀況,並通過EventBus發送出去,也可以通過廣播發送出去,我認爲EventBus寫的代碼少一些好用一些。
3.藍牙重連和心跳包
在service的onCeate函數裏,使用Handler或TimerTask完成這個任務
4.使用FastBle框架
https://www.jianshu.com/p/795bb0a08beb
參考文獻
https://juejin.im/post/599b8388f265da249600bbfd