背景
公司硬件模塊升級犹褒,由原本的單模式藍牙熙侍,換成現(xiàn)在的雙模藍牙搁廓。單模藍牙就是通過BlueTooth 2.0傳統(tǒng)藍牙進行音頻或者數(shù)據(jù)傳輸甸饱,雙模藍牙兼容傳統(tǒng)藍牙,可以和傳統(tǒng)藍牙通信撑碴,也可以和BLE通信撑教,谷歌在Android 4.3后開始支持BLE低功耗藍牙。
由來
公司使用的藍牙模塊醉拓,供應商那邊提供了相應的sdk驮履,在代碼測試和開發(fā)工程中,發(fā)現(xiàn)連接速度的穩(wěn)定性存在問題廉嚼,和其他公司的技術人員聯(lián)系,協(xié)商問題倒戏,應該是工作中費時費力的一件事怠噪,最后還不一定能夠得到解決。詢問過sdk那邊相關人員杜跷,說可以自己用系統(tǒng)的方法進行調(diào)試傍念。
BLE相關概念
UUID
Universally Unique Identifier ,唯一標示符葛闷,一般開發(fā)中會用到SERVICE憋槐、WRITE、NOTIFICATION等的UUID淑趾,需固件端配合修改阳仔。
Generic Attribute Profile (GATT)
GATT是用于發(fā)送和接收的通用規(guī)范,不同于傳統(tǒng)藍牙使用socket扣泊, BLE之間的文件數(shù)據(jù)傳輸基于GATT近范。GATT連接是一對一的,也就說一個BLE設備智能連接一個設備延蟹。一旦連接成功评矩,只有當連接斷開,否則其它設備無法連接當前設備的的阱飘。
Attribute Protocol (ATT)
GATT是建立在ATT的基礎上斥杜,ATT針對BLE設備進行了優(yōu)化虱颗,在傳輸中使用盡量少的數(shù)據(jù),每個屬性都有一個唯一的UUID蔗喂,屬性間的傳輸會以characteristics 和services的形式來進行傳輸忘渔。
Characteristic
Characteristic特征值,包含一個或者多個value,可以通過characteristic進行文件的讀寫操作弱恒。
Descriptor
用于描述特征值的屬性
Service
特征值得集合
開發(fā)
權限
進行藍牙相關操作辨萍,需要使用到藍牙權限,在AndroidManifest.xml清單文件中添加相應權限
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
在android6.0以后返弹,藍牙BLE還需要需要獲得位置權限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
初始化藍牙Adapter
使用藍牙進行相關操作之前锈玉,需要先獲取藍牙適配器
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) {
mBluetoothAdapter = bluetoothManager.getAdapter();
}
判斷藍牙是否可用或者是否開啟,如果藍牙關閉义起,那么開啟藍牙
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
掃描
掃描過程中拉背,需要對掃描結果進行回調(diào),在onLeScan()方法中對掃描的結果進行相關處理
private BluetoothDevice mDevice;
final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
Log.d("haha", "onLeScan: " + device.getName() + " : " + rssi);
String name = device.getName();
if (name != null) {
deviceName.setText(name);
if (name.equals("test_ble")) {
mDevice = device;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
}
};
由于藍牙掃描耗時耗電默终,所以在進行掃描的時候椅棺,注意自定義一個合適的掃描時間,在實際的開發(fā)和項目應用過程中齐蔽,自己選擇合適的時間两疚。定義好藍牙掃描回調(diào),開始掃描藍牙含滴,掃描到想要的藍牙诱渤,就可以停止掃描
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
// 預先定義停止藍牙掃描的時間(因為藍牙掃描需要消耗較多的電量)
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, 30000);
mScanning = true;
// 定義一個回調(diào)接口供掃描結束處理
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
通過獲取的mBluetoothAdapter調(diào)用startLeScan()傳入mLeScanCallback參數(shù),即可進行藍牙掃描谈况。
BluetoothGattCallback實現(xiàn)
GATT是用于發(fā)送和接收的通用規(guī)范勺美, BLE之間的文件數(shù)據(jù)傳輸基于GATT,因此在進行連接之前碑韵,需要進行Gatt接口回調(diào)赡茸。
private String TAG = "haha";
private boolean isServiceConnected;
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.d("haha", "onConnectionStateChange: " + newState);
if (status != BluetoothGatt.GATT_SUCCESS) {
String err = "Cannot connect device with error status: " + status;
// 當嘗試連接失敗的時候調(diào)用 disconnect 方法是不會引起這個方法回調(diào)的,所以這里
// 直接回調(diào)就可以了祝闻。
gatt.close();
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
}
if (mDevice != null) {
mBluetoothGatt = mDevice.connectGatt(MainActivity.this, false, mGattCallback);
}
Log.e(TAG, err);
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
//當藍牙設備已經(jīng)接
Toast.makeText(MainActivity.this, "連接成功", Toast.LENGTH_SHORT).show();
Log.i("haha", "Attempting to start service discovery:" +
Log.d("haha", "onConnectionStateChange: " + "連接成功");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//當設備無法連接
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
}
gatt.close();
if (mDevice != null) {
mBluetoothGatt = mDevice.connectGatt(MainActivity.this, false, mGattCallback);
}
}
};
通過status對當前連接進行判斷占卧,當status != BluetoothGatt.GATT_SUCCESS時,可以進行Gatt的重置操作治筒,嘗試重連屉栓。當newState == BluetoothProfile.STATE_CONNECTED時,此時連接成功耸袜。
連接
當實現(xiàn)了Gatt連接回到之后友多,即可對Ble藍牙進行連接操作
public void startConnect(View view) {
if (mDevice != null) {
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
}
mBluetoothGatt = mDevice.connectGatt(MainActivity.this, false, mGattCallback);
}
}
注意事項
BLE實現(xiàn)android 4.3以后google才提供了支持,所以Ble項目只可運行在API 18以上的手機堤框;Android 6.0以上域滥,Ble服務還需要定位權限纵柿,否則使用不了。不使用時启绰,還應注意對藍牙進行關閉或斷開操作昂儒,由于Ble連接屬于獨占操作,有設備連接上了委可,其它設備是無法進行任何操作的渊跋。
Github
喜歡或對你有幫助,可以關注或者點贊BleDemo
下一篇Android BLE低功耗藍牙開發(fā)極簡系列(二)之讀寫操作