** 安卓開發(fā)中或多或少會接觸到藍牙部分旧困,像一些智能家居丐一,藍牙手環(huán)藻糖,還有一些串口數(shù)據(jù)傳輸?shù)脑O(shè)備都和藍牙相關(guān),面試的時候有的公司也會問到一些藍牙相關(guān)的問題库车,這里我來說說關(guān)于低功耗藍牙的一些相關(guān)知識巨柒,這些知識也是我在網(wǎng)上查閱總結(jié)的。在百度上一搜低功耗藍牙的帖子很多,但都講的不是很全面洋满,讓人知其然不知其所以然晶乔。這里我就從簡單的開始先分析一些谷歌的demo的代碼,看看BLE藍牙是怎么建立通信的牺勾,只要掌握了BLE藍牙通信那么再將發(fā)送接收的數(shù)據(jù)處理一下就ok了正罢,當(dāng)然光看這一篇帖子不一定會完全把低功耗藍牙弄懂,興許會遇到一些坑驻民,但是堅持下去始終會弄懂的翻具;**
這是網(wǎng)上提供的Android 藍牙4.0 ble 官方 demo
- App的界面圖
App的界面很簡單就兩個界面
代碼主要包含四個類
DeviceScanActivity類(展示手機掃描到的BLE藍牙);
DeviceControlActivity類(BLE操作控制臺)回还;
BluetoothLeService類(通過服務(wù)來管理藍牙裆泳,其中通過廣播來于DeviceControlActivity類通信)
SampleGattAttributes類(不同種類的UUID)
DeviceScanActivity類的功能:
這個類之間繼承ListActivity,顧名思義柠硕,它可能是一個展示列表工禾,細看代碼,它切實是一個列表展示類蝗柔,這個類的主要作用就是展示手機掃描到的可用藍牙闻葵;點擊選擇的BLE后將BLE的屬性(名稱和ID)傳遞到DeviceControlActivity類;
該類的主要流程就是 在onCreate方法中判斷手機是否支持BLE癣丧,然后初始化藍牙適配器槽畔,最后就是手機的權(quán)限適配(藍牙需要定位的權(quán)限)
在onResume方法中檢測藍牙是否開啟,沒有開啟那就開啟藍牙胁编,不開啟的話那么就觸發(fā)onActivityResult方法則finish()關(guān)閉app竟痰,開啟藍牙的話則
開啟掃描 scanLeDevice(true); true為開啟掃描 false為關(guān)閉掃描;在掃描的方法scanLeDevice中可以看到通過handler計時掃描十秒鐘掏呼;
開啟掃描后將會回調(diào) mLeScanCallback 對象;在這個對象中重寫了onLeScan方法铅檩,這個方法中的參數(shù)onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)中device則為藍牙設(shè)備屬性憎夷;將藍牙設(shè)備屬性展示到列表中,通listview監(jiān)聽選中 的藍牙跳轉(zhuǎn)到DeviceControlActivity類昧旨;
DeviceControlActivity類中要功能:
開啟服務(wù)BluetoothLeService拾给,接收服務(wù)傳過來的藍牙數(shù)據(jù);里面有幾個重要的類部類:
ServiceConnection(BinderService的返回數(shù)據(jù)接收類)兔沃;BluetoothGattCallback(廣播蒋得,接收服務(wù)發(fā)送過來的消息); ExpandableListView.OnChildClickListener(這是一個list二級列表的監(jiān)聽類)乒疏;里面還有一個重要的方法就displayGattServices(listview的適配器)额衙;
該類的主要流程:注冊廣播并接收,在onCreate中對一些控件的初始化,通過intent傳值獲取到藍牙的名稱和ID窍侧,然后啟動服務(wù)县踢;在ServiceConnection內(nèi)部類中得到服務(wù)的對象 mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();在 onResume方法中通過服務(wù)的對象建立藍牙的連接,注意 藍牙連接后還并不能通信伟件,建立通信使用通過UUID的硼啤;藍牙建立連接后會觸發(fā)廣播action為BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED方法,在這個方法中通過調(diào)用displayGattServices方法展示藍牙的UUID的數(shù)據(jù)斧账,可以看到藍牙有很多UUID谴返,其實UUID是分可讀的,可寫的咧织,和可讀可寫的嗓袱,這應(yīng)該是藍牙廠家寫好的固件;在app上我們可以挨個的點擊不同的UUID將會建立不同的連接拯爽,其中就有一種連接可以信索抓;點擊UUID將會OnChildClickListener()方法,里面的邏輯主要就是開啟藍牙的讀取功能和開啟藍牙的的通知功能
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
mBluetoothLeService.readCharacteristic(characteristic);
BluetoothLeService類主要功能:
就是通過UUID建立藍牙通訊毯炮,readCharacteristic()開啟藍牙讀的功能逼肯,setCharacteristicNotification()開啟藍牙或禁用通知的功能;getSupportedGattServices()只有在成功完成之后才會調(diào)用此函數(shù)桃煎。在連接的設(shè)備上檢索受支持的有關(guān)協(xié)定服務(wù)列表篮幢,里面沒有藍牙寫數(shù)據(jù)的方法,要自己寫为迈;
該類的主要流程就是通過DeviceControlActivity類傳過來的藍牙ID建立藍牙連接
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
其中里面有一個非常重要的類mGattCallback回調(diào)三椿,這里面重寫了幾個方法
onConnectionStateChange()藍牙連接狀態(tài)改變的回調(diào);
onServicesDiscovered()服務(wù)發(fā)現(xiàn)的回調(diào)在這個方法中可以建立藍牙的連接
onCharacteristicRead()藍牙的特征葫辐;
onCharacteristicChanged()Characteristic狀態(tài)改變的回調(diào)
onCharacteristicWrite)()Characteristic寫操作的結(jié)果回調(diào):
這里說一下重點:通過上面的解釋還是會知其然不知其所以然搜锰。
藍牙讀數(shù)據(jù)有兩種方法:
一種是調(diào)用readCharacteristic()方法 開啟讀 ,一種是通過通知來讀 setCharacteristicNotification方法耿战;
通過uuid 讀某個Characteristic
開啟讀
mBluetoothLeService.readCharacteristic(characteristic);
public void readCharacteristic(BluetoothGattCharacteristiccharacteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
如果成功蛋叼,數(shù)據(jù)會在下面的方法回調(diào)中傳進來
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
還可以通過通知的回調(diào)方法讀取數(shù)據(jù) 這種方式不用手機去輪詢地讀設(shè)備上的數(shù)據(jù)。
//設(shè)置true為啟用通知,false反之
setCharacteristicNotification(mNotifyCharacteristic, true);
有消息來后會回調(diào)方法
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
寫數(shù)據(jù)就更簡單了
通過UUID獲取到BluetoothGattCharacteristic
BluetoothGattCharacteristic alertLevel =linkLossService.getCharacteristic(UUID.fromString("49535343-8841-43f4-a8d4-ecbe34729bb3"));
alertLevel.setValue(values_on);
status = mBluetoothGatt.writeCharacteristic(alertLevel);
status如果為true剂陡,表示寫操作已經(jīng)成功執(zhí)行狈涮,BluetoothGattCallback抽象類的一個方法會被執(zhí)行,如果剛好你又重寫了這個方法鸭栖,就可以打印一些消息了
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristiccharacteristic, int status){
}
官方的demo沒有用發(fā)送數(shù)據(jù)的代碼歌馍,接收數(shù)據(jù)也是16進制,這個需要自己按實際情況修改代碼或是在網(wǎng)上找一些demo有收發(fā)功能的晕鹊,開放項目復(fù)雜多變松却,這里很難以偏概全暴浦,就不一一展示了;
總結(jié):藍牙收發(fā)數(shù)據(jù)每次最多20個字節(jié)玻褪,這就要對接收的數(shù)據(jù)進行拼接肉渴,截取了;發(fā)送數(shù)據(jù)也是以20個字節(jié)為單位带射,一段一段發(fā)送同规;藍牙對于有些人來說也許會很難, 但是琢磨久了就會看懂的窟社;