藍(lán)牙的基礎(chǔ)知識(shí)
1. 相關(guān)權(quán)限申請(qǐng)
權(quán)限
android:name="android.permission.BLUETOOTH"/>
android:name="android.permission.BLUETOOTH_ADMIN"/>
注意:android6.0后?需要再添加如下權(quán)限定位權(quán)限 (如下一個(gè)就可以了 也可以多個(gè)申請(qǐng))
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
android:name="android.permission.ACCESS_FINE_LOCATION"/>
2. 搜索藍(lán)牙流程
2.1 打開藍(lán)牙(需要在此之前獲取藍(lán)牙適配器BluetoothAdapter 才可以 調(diào)起打開藍(lán)牙)
?2.1.1 獲取藍(lán)牙適配器BluetoothAdapter
BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
??2.1.2 權(quán)限申請(qǐng)成功后 就可以?打開藍(lán)牙 ,如下是藍(lán)牙是
if(mBluetoothAdapter ==null|| !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,REQUEST_ENABLE_BT);
}
2.2 掃描藍(lán)牙設(shè)備
mBluetoothAdapter.startLeScan(mLeScanCallback)
需要注意:搜索是一個(gè)不間斷的搜索過程,需要我們手動(dòng) 停止搜索
所以需要 調(diào)用mBluetoothAdapter. mBluetoothAdapter.stopLeScan(mLeScanCallback);
具體代碼?定時(shí)搜索 如下
private voidscanLeDevice(final booleanenable) {
if(enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(newRunnable() {
@Override
public voidrun() {
mScanning =false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
},SCAN_PERIOD);
mScanning =true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
}else{
mScanning =false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
關(guān)于mLeScanCallback的具體實(shí)現(xiàn)
privateBluetoothAdapter.LeScanCallback mLeScanCallback =
newBluetoothAdapter.LeScanCallback() {
@Override
public voidonLeScan(finalBluetoothDevice device, intrssi,
byte[] scanRecord) {
//搜索到藍(lán)牙 將會(huì)在該方法回調(diào) , device就是搜索到的藍(lán)牙
}
};
注意:藍(lán)牙搜索過程 是沒有幫我們過來重復(fù)搜索到藍(lán)牙 ,如果想要把搜索結(jié)果放在集合返回,有可能一個(gè)設(shè)備會(huì)重復(fù)給搜索到,這個(gè)時(shí)候需要自己做個(gè)過濾,可通過bleDevice 的mac 地址不同進(jìn)行過濾
2. 連接藍(lán)牙流程
2.1 先理清 將會(huì)常操作的幾個(gè) 類的概念?如下是它們的關(guān)系流程圖

BluetoothGatt:手機(jī)與BLE終端設(shè)備建立通信的一個(gè)管道,只有有了這個(gè)管道,之后的所有讀寫通知操作都是通過這個(gè)來操作
BluetoothGattService:藍(lán)牙設(shè)備的服務(wù),每個(gè)BluetoothGatt有多個(gè)BluetoothGattService,在這里我們把BluetoothGattService比喻成班級(jí)。而Bluetoothdevice我們把它比喻成學(xué)校,一個(gè)學(xué)校里面可以有很多班級(jí),也就是說我們每臺(tái)BLE終端設(shè)備擁有多個(gè)服務(wù),班級(jí)(各個(gè)服務(wù))之間通過UUID(唯一標(biāo)識(shí)符)區(qū)別
BluetoothGattCharacteristic:藍(lán)牙所擁有的特征 。每個(gè)BluetoothGattService有多個(gè)BluetoothGattCharacteristic。它是手機(jī)與BLE終端設(shè)備交換數(shù)據(jù)的關(guān)鍵,我們做的所有事情,目的就是為了得到它。在這里我們把它比喻成學(xué)生,一個(gè)班級(jí)里面有很多個(gè)學(xué)生,也就是說我們每個(gè)服務(wù)下?lián)碛卸鄠€(gè)特征,學(xué)生(各個(gè)特征)之間通過UUID(唯一標(biāo)識(shí)符)區(qū)別。
理清了我們開始連接藍(lán)牙
2.2連接藍(lán)牙
搜索到藍(lán)牙后?拿到藍(lán)牙對(duì)象 BluetoothDevice device 調(diào)用如下方法
參數(shù):第一個(gè)參數(shù)是上下文對(duì)象,第二個(gè)參數(shù)是是否自動(dòng)連接,這里設(shè)置為false,第三個(gè)參數(shù)就是上面的回調(diào)方法
mBluetoothGatt = device.connectGatt(this, false,mGattCallback);
mGattCallback的具體實(shí)現(xiàn)
privateBluetoothGattCallbackmGattCallback=newBluetoothGattCallback() {
//連接狀態(tài)改變的回調(diào)
@Override
public voidonConnectionStateChange(BluetoothGatt gatt, intstatus,
intnewState) {
if(newState == BluetoothProfile.STATE_CONNECTED) {
// 連接成功后 必須啟調(diào)用 服務(wù)發(fā)現(xiàn) (discoverServices)
//調(diào)用后 當(dāng)回調(diào) onServicesDiscovered(BluetoothGatt gatt, int status)方法
//才屬于真正的成功連接
mBluetoothGatt.discoverServices();
}
}
//發(fā)現(xiàn)服務(wù)的回調(diào)
public voidonServicesDiscovered(BluetoothGatt gatt, intstatus) {
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"成功發(fā)現(xiàn)服務(wù)");
}else{
Log.e(TAG,"服務(wù)發(fā)現(xiàn)失敗,錯(cuò)誤碼為:"+ status);
}
if(status == BluetoothGatt.GATT_SUCCESS) {
if(mBluetoothGatt !=null&& isServiceConnected) {
BluetoothGattService gattService = mBluetoothGatt.getService(UUID_SERVICE);
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID_NOTIFICATION);
booleanb = mBluetoothGatt.setCharacteristicNotification(characteristic, true);
if(b) {
List descriptors = characteristic.getDescriptors();
for(BluetoothGattDescriptor descriptor : descriptors) {
booleanb1 = descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
if(b1) {
mBluetoothGatt.writeDescriptor(descriptor);
Log.d(TAG,"startRead: "+"監(jiān)聽收數(shù)據(jù)");
}
}
}
}
}
//寫操作的回調(diào)
public voidonCharacteristicWrite (BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic,intstatus){
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"寫入成功"+ characteristic.getValue());
}
}
//讀操作的回調(diào)
public voidonCharacteristicRead (BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic,intstatus){
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"讀取成功"+ characteristic.getValue());
}
}
//數(shù)據(jù)返回的回調(diào)(此處接收BLE設(shè)備返回?cái)?shù)據(jù))
public voidonCharacteristicChanged (BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic){
}
}
}
當(dāng) 回調(diào)? onServicesDiscovered(BluetoothGatt gatt, int status) 方法 后? 就可以拿著? ? gatt(上文有解釋概念) 進(jìn)行 讀寫通知 操作了
3 關(guān)于 讀,寫,通知,操作
?寫數(shù)據(jù)
public void?startSend(View view) {
if?(mBluetoothGatt !=?null?&& isServiceConnected) {
BluetoothGattService gattService = mBluetoothGatt.getService(UUID_SERVICE);
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID_WRITE);
byte[] bytes =?new byte[2];
bytes[0] =?04;
bytes[1] =?01;
characteristic.setValue(bytes);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mBluetoothGatt.writeCharacteristic(characteristic);
}}
寫入成功會(huì)回調(diào)
public void?onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int?status) {
if?(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,?"寫入成功"?+characteristic.getValue());
}
}
讀數(shù)據(jù)
public void?startSend(View view) {
if?(mBluetoothGatt !=?null?&& isServiceConnected) {
BluetoothGattService gattService = mBluetoothGatt.getService(UUID_SERVICE);
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID_WRITE);
byte[] bytes =?new byte[2];
bytes[0] =?04;
bytes[1] =?01;
characteristic.setValue(bytes);
mBluetoothGatt.readCharacteristic(characteristic);
}
}
讀取成功會(huì)回調(diào)
//讀操作的回調(diào)
public voidonCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, intstatus) {
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"讀取成功"+characteristic.getValue());
}
}
注意: 在 讀寫操作過程? 不可以 用for 一次性進(jìn)行操作? 會(huì)出現(xiàn)阻塞? 需要 將讀寫操作 寫入 隊(duì)列中? 一個(gè)一個(gè)寫入? 才是比較好的操作? 也不會(huì)出現(xiàn)堵塞問題
? 藍(lán)牙的操作流程? 就此結(jié)束? ? 在此基礎(chǔ)上? 可以再次封裝一層? 代碼就不出來了,一下是流程圖
