相關(guān)概念
BR
Basic Rate,早期的傳統(tǒng)藍(lán)牙技術(shù) V1.1, V1.2 版本,傳輸速率為748~810kb/s。EDR
Enhanced Data Rate,傳統(tǒng)藍(lán)牙技術(shù) V2.0, V2.1 版本,優(yōu)化傳輸速率,減少耗電,速率為1.8M/s~2.1M/s。AMP
GenericAlternate MAC/PHY,高速藍(lán)牙技術(shù),V3.0版本。
采用交替射頻技術(shù),藍(lán)牙模塊僅創(chuàng)建設(shè)備間的配對,數(shù)據(jù)傳輸通過WIFI射頻來完成以達(dá)到高速率。
假如設(shè)備某一方?jīng)]有內(nèi)建WIFI模塊,速率將降至 EDR 速率。BLE
Bluetooth Low Energy,低耗藍(lán)牙技術(shù),V4.0版本的新規(guī)范,通過三個方式實(shí)現(xiàn)超低功耗:
1.大幅度削減掃描信道
2.極短的鏈路連接時間
3.采用長度很短的數(shù)據(jù)包
低耗藍(lán)牙的芯片有單模和雙模,前者只支持LE技術(shù),后者兼容BR/EDR技術(shù)。
1:GATT 協(xié)議
GATT概述
GATT(Generic Attributes,通用屬性協(xié)議),定義了一種面向 BLE設(shè)備 的分層數(shù)據(jù)結(jié)構(gòu)。
GATT建立在ATT( Attribute Protocol,通用訪問協(xié)議)之上,ATT使用GATT數(shù)據(jù)定義兩個BLE設(shè)備間收發(fā)標(biāo)準(zhǔn)消息的方式。
由于 GATT 是面向 LE 技術(shù)的協(xié)議,所以在只支持 BR/EDR 技術(shù)的設(shè)備上無法使用。-
GATT分層數(shù)據(jù)結(jié)構(gòu)的層次
GATT定義了用于BLE設(shè)備傳輸數(shù)據(jù)的標(biāo)準(zhǔn)數(shù)據(jù)結(jié)構(gòu),結(jié)構(gòu)主要包括了如上圖所示的:
1.服務(wù)(Service)
2.特征(Characteristic)
3.描述符(Descriptor)。 配置文件(Profile):
配置文件,GATT頂層,該由滿足 配置實(shí)例 需要的一個或多個服務(wù)組成。-
服務(wù)(Service):
服務(wù) 由 特征 和 其他服務(wù)的引用 組成,擁有固定的 UUID 作為標(biāo)記值。
設(shè)備的功能主要體現(xiàn)在服務(wù)上,每種服務(wù)都對應(yīng)著某一種功能。可以到官網(wǎng)上查看服務(wù)列表 GATT Services。
通過服務(wù)列表中的 Assigned Numbers 可以獲取服務(wù)的UUID。Assigned Numbers轉(zhuǎn)換成可用的服務(wù)UUID 的方法于文檔 Service Discovery。
簡單來說,就是:"服務(wù)的Assigned Numbers"-0000-1000-8000-00805F9B34FB
-
特征(Characteristic):
特征是BLE通信的主體,是一個服務(wù)端和客戶端共享的讀寫空間。
主機(jī)在從機(jī)上獲取所需的信息,實(shí)際就是通過獲取對應(yīng)的特征的內(nèi)容進(jìn)行的。特征由屬性值和描述符組成:
- 屬性值
屬性值包括聲明(Declaration),值(Value),一個屬性值最少包括一個聲明和一個值,即是屬性值是特征必選的條目。 - 描述符
特征可以包括零到若干個描述符,可選條目。
特征信息列表可以查看官方文檔 GATT Characteristics。
- 屬性值
-
描述符(Descriptors)
用于表達(dá) 特征 的其他附加信息,如特征值的有效范圍,可讀性描述等信息。其中包含了特殊的 CCCD(Client Characteristic Configuration Descriptor, Assigned Number : 0x2902):
CCCD 可以設(shè)置 服務(wù)端 在對應(yīng)特征值發(fā)生變化時,是否對 客戶端 進(jìn)行信息 推送(直接發(fā)送信息) 或 提示(發(fā)送一個提示并等待回復(fù))。
當(dāng)特征包含通知能力時,CCCD為必選項。描述符列表可以查看官方文檔 GATT Descriptors。
2:Android BLE 相關(guān) API
-
BluetoothAdapter
藍(lán)牙適配器:本地設(shè)備藍(lán)牙適配器,提供基本藍(lán)牙功能的工具,例如開啟藍(lán)牙發(fā)現(xiàn),查詢配對設(shè)備,實(shí)例化藍(lán)牙設(shè)備鏈接,監(jiān)聽連接請求,掃描設(shè)備等。
基本上說,藍(lán)牙適配器是進(jìn)行藍(lán)牙操作的起點(diǎn)。獲取BluetoothAdapter實(shí)例,在 API 18 及以上的設(shè)備,使用:
BluetoothManager.getAdapter
在API18以下設(shè)備使用以下API獲取:
BluetoothAdapter.getDefaultAdapte
本類線程安全。涉及到的權(quán)限為:
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
-
BluetoothDevice
遠(yuǎn)程藍(lán)牙設(shè)備:提供了遠(yuǎn)程藍(lán)牙設(shè)備的基本信息,如名稱,地址,類別,綁定狀態(tài)等。
本質(zhì)上只是對藍(lán)牙硬件地址的簡單包裝。該類的實(shí)例不可修改。一般來說,通過掃描設(shè)備的掃描結(jié)果回調(diào)中獲取。
也可以直接通過以下方式獲取:/* 使用已知的物理地址作為參數(shù)進(jìn)行連接 */ BluetoothAdapter.getRemoteDevice(address); /* 獲取已適配的藍(lán)牙記錄列表 */ BluetoothAdapter.getBondedDevices();
-
BluetoothGatt
GATT客戶端,GATT協(xié)議的公共API,提供了GATT的基本功能,如實(shí)現(xiàn)藍(lán)牙設(shè)備的通信。
通過掃描支持LE技術(shù)的藍(lán)牙設(shè)備,獲取到 BluetoothDevice,然后通過:/* GATT連接操作的回調(diào) */ BluetoothGattCallback mCallback; BluetoothDevice.connectGatt(content, autoConnect, mCallback);
通過設(shè)置 BluetoothGattCallback 回調(diào),可以從回調(diào)中得到 BluetoothGatt 實(shí)例。
-
BluetoothGattCallback
GATT狀態(tài)回調(diào),大部分GATT操作的結(jié)果都會通過該類實(shí)例回調(diào),包括:/* 連接狀態(tài)回調(diào),包括連接到服務(wù)器 / 從服務(wù)器斷開連接 */ onConnectionStateChange(); /* 遠(yuǎn)程設(shè)備發(fā)現(xiàn)新服務(wù) */ onServicesDiscovered(); /* 特征相關(guān)操作的回調(diào) */ onCharacteristicRead(); onCharacteristicWrite(); onCharacteristicChanged();
同時,掃描設(shè)備 和 停止掃描 的操作,都需要用到該類的實(shí)例。
-
BluetoothGattService
GATT服務(wù),根據(jù)服務(wù)的 UUID,嘗試獲取服務(wù)實(shí)例。/* 如果對應(yīng)的設(shè)備支持該服務(wù),則返回一個服務(wù)的實(shí)例,否則返回空 */ BluetoothGatt.getService(uuid);
-
BluetoothGattCharacteristic
GATT特征,實(shí)際通信中的數(shù)據(jù)信息主體。通過以下方法獲取:/* 獲取對應(yīng)UUID的特征 */ BluetoothGattService.getCharacteristic(uuid); /* 獲取服務(wù)的特征列表 */ BluetoothGattService.getCharacteristics();
3:Android BLE 開發(fā)示例
-
聲明權(quán)限
一個聲明和兩個基本權(quán)限:
<uses-feature android:name"android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
執(zhí)行搜索BLE設(shè)備的時候,需要使用定位權(quán)限。
而在5.0及以上的版本,需要手動聲明GPS硬件模塊功能的權(quán)限:<uses-feature android:name="android.hardware.location.gps"/>
而在6.0及以上版本,掃描設(shè)備還需要 動態(tài)申請 以下權(quán)限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-
檢查設(shè)備支持性
如果設(shè)備不支持BLE,可以跳過BLE相關(guān)操作了。boolean checkSupport() { return getPackageManager() .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE); }
-
初始化BluetoothAdapter
private BluetoothAdapter mAdapter; BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mAdapter = bluetoothManager.getAdapter();
然后檢查藍(lán)牙的支持性,及是否已打開藍(lán)牙。
if (mAdapter == null) { return; } ... private final static int REQUEST_ENABLE_BT = 1; if (!mAdapter.isEnabled()) { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent, REQUEST_ENABLE_BT); }
-
啟動設(shè)備掃描
創(chuàng)建LeScanCallback實(shí)例:
首先需要實(shí)現(xiàn)一個 LeScanCallback 實(shí)例,掃描結(jié)果會通過實(shí)例的 onLeScan 方法返回:LeScanCallback mCallBack = new LeScanCallback (){ @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {} }
啟動掃描與停止掃描:
··· static int SCAN_TIME = 5_000; ··· Handler mHandler = new Handler(); /* 開始掃描: 由于掃描消耗電量,所以不能一直處于掃描狀態(tài), 設(shè)置掃描一段時間后關(guān)閉掃描 */ mAdapter.startLeScan(mCallBack); mHandler.postDelay(()->{ /* 關(guān)閉掃描: * 注意需要傳入啟動掃描時的 callback對象,否則無效 */ mAdapter.stopLeScan(mCallBack); }, SCAN_TIME);
在 API 21 及以上時,掃描操作應(yīng)使用 BluetoothLeScanner:
final ScanCallback callback = new ScanCallback() {}; final BluetoothLeScanner scanner = mAdapter.getBluetoothLeScanner(); scanner.startScan(new ScanCallback(){}); mHandler.postDelay(()->{ scanner.stopScan(scanCallback); }, SCAN_TIME);
-
獲取掃描結(jié)果
以 LeScanCallback 的回調(diào)方法 onLeScan 分析:/** * @param device: 識別到的遠(yuǎn)程設(shè)備 * * @param rssi: 信號強(qiáng)度指示,計數(shù)為dB。可以通過: d = 10^((abs(RSSI) - A) / (10 * n)) 計算出距離。A和n根據(jù)環(huán)境改變,需經(jīng)實(shí)驗測出, 給出兩個網(wǎng)上的經(jīng)驗值: <1> A: 50 n: 2.5 <2> A: 59 n: 2.0 * * @param scanRecord:廣播數(shù)據(jù)和掃描應(yīng)答數(shù)據(jù)數(shù)據(jù) BLE設(shè)備在對外廣播中,廣播中會攜帶一些有用的信息。 其中包含了 廣播數(shù)據(jù) 和 掃描應(yīng)答數(shù)據(jù), 兩者有效荷載最大都為 31字節(jié)(藍(lán)牙4), 以十六進(jìn)制格式存儲,可通過 bytesToHex 轉(zhuǎn)換成可用的字符串。 */ void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {}
注意相同的 BluetoothDevice 會重復(fù)出現(xiàn)在回調(diào)中,所以如果要記錄藍(lán)牙列表,需要自行 過濾 重復(fù)出現(xiàn)的設(shè)備,或更新對應(yīng)重復(fù)出現(xiàn)的設(shè)備的信息。
bytesToHex 參考 -
連接外圍設(shè)備
通過 BluetoothDevice 的 connectGatt 方法獲取一個 BluetoothGatt 實(shí)例。
connectGatt 有多個重載方法,這里介紹其中最復(fù)雜的重載方法:/** * 以客戶端的身份連接到該設(shè)備托管的GATT服務(wù)器 * * @param autoConnect:自動連接,設(shè)備不可用時會不斷嘗試重連。 * * @param callback: BluetoothGattCallback實(shí)例,用于接收異步回調(diào) * * @param transport: GATT連接到雙模設(shè)備的首選傳輸模式: * 1:TRANSPORT_AUTO 自動選擇 (默認(rèn)值) * 2:TRANSPORT_BREDR BR/EDR 傳統(tǒng)藍(lán)牙 * 3:TRANSPORT_LE LE 低耗藍(lán)牙 * * @param phy: PHY物理層的模式選擇: * 1:PHY_LE_1M_MASK: * 默認(rèn)值,LE設(shè)備強(qiáng)制要求支持的模式, * 符號速率為1M/s,未編碼。 * 2:PHY_LE_2M_MASK: * 符號速率為2M/s,未編碼, * 用于 藍(lán)牙5 的 "2x speed" 2倍速率。 * 3:PHY_LE_CODED_MASK: * 在數(shù)據(jù)包中增加糾錯編碼以實(shí)現(xiàn)更遠(yuǎn)的傳輸范圍, * 以實(shí)現(xiàn) 藍(lán)牙5 的 "4x range" 4倍范圍。 * 使用FEC編碼,根據(jù)方案又分為: * LE Coded S=2:2個編碼位代替原來一個數(shù)據(jù)位, * 速率降為 500K/s,傳輸范圍增大2倍; * LE Coded S=8:8個編碼位代替原來一個數(shù)據(jù)位, * 速率降為 125K/s,傳輸范圍增大4倍; * 設(shè)置 autoConnect 自動連接時,該項無效 * * @param handler: 傳入一個Handler,以指定回調(diào)發(fā)生的線程, * 傳入null時,回調(diào)將會在一個未指定的后臺線程上進(jìn)行。 */ BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler) { ··· }
一般情況下使用默認(rèn)值既可,
注意必須傳入非空的callback,否則會拋出 IllegalArgumentException:BluetoothDevice.connectGatt(content, autoConnect, callback);
當(dāng)連接成功時,會回調(diào) callback 的 onConnectionStateChange 方法
/** * GATT客戶端的連接狀態(tài)回調(diào) * * @param gatt: GATT客戶端。 * @param status: 連接或斷開操作的執(zhí)行結(jié)果, 成功返回 GATT_SUCCESS * @param newState:當(dāng)前的連接狀態(tài):STATE_CONNECTED / STATE_DISCONNECTED */ void onConnectionStateChange(BluetoothGatt gatt, int status, int newState);
status 表示連接操作的結(jié)果,只有status為 GATT_SUCCESS 時,newState才是有效值。
注意一臺安卓設(shè)備最多同時連接6個左右的藍(lán)牙設(shè)備,超出時可能出現(xiàn):
status == 133 連接錯誤,
所以需要注意調(diào)用 BluetoothGatt.close() 方法進(jìn)行資源釋放。
可參考:Android中BLE連接出現(xiàn)“BluetoothGatt status 133”的解決方法當(dāng) status == GATT_SUCCESS,且 newState == STATE_CONNECTED 時,表示已成功連接設(shè)備,可以進(jìn)行下一步操作。
-
發(fā)現(xiàn)服務(wù)
在建立連接之后,就可以通過 BluetoothGatt實(shí)例 進(jìn)行發(fā)現(xiàn)服務(wù)操作,查找設(shè)備支持的服務(wù)。/** * 異步操作,發(fā)現(xiàn)服務(wù)完成時,會回調(diào)onServicesDiscovered()方法。 * 假如發(fā)現(xiàn)服務(wù)已在啟動狀態(tài)中,則返回true */ boolean discoverService();
等待 BluetoothGattCallback 的 onServicesDiscovered() 被回調(diào):
/** * @param gatt: 執(zhí)行發(fā)現(xiàn)服務(wù)后的GATT客戶端。 * @param status: 發(fā)現(xiàn)服務(wù)的執(zhí)行結(jié)果, 成功返回 GATT_SUCCESS */ void onServicesDiscovered(BluetoothGatt gatt, int status) ;
當(dāng) status 返回GATT_SUCCESS,表示與外部設(shè)備成功建立 可通信連接,
意味著可以執(zhí)行如:寫入數(shù)據(jù),讀取藍(lán)牙設(shè)備的數(shù)據(jù)等 藍(lán)牙通信操作了。
先把獲取到的 BluetoothGatt實(shí)例 記錄為 mGatt:··· BluetoothGatt mGatt; void onServicesDiscovered(BluetoothGatt gatt, int status) { mGatt = gatt; }
-
獲取服務(wù)
發(fā)現(xiàn)服務(wù)成功之后,可以通過以下的方法嘗試獲取 BluetoothGattService 實(shí)例:/* 獲取遠(yuǎn)程設(shè)備提供的服務(wù)列表, * 如果未執(zhí)行發(fā)現(xiàn)服務(wù),會返回一個空列表 */ mGatt.getServices(); /* 通過服務(wù)的UUID,獲取指定的服務(wù), * 如果遠(yuǎn)程設(shè)備不支持給定UUID的服務(wù),返回null, * 如果遠(yuǎn)程設(shè)備存在多個給定UUID的服務(wù)實(shí)例,則返回第一個實(shí)例 */ mGatt.getService(UUID);
獲取到 BluetoothGattService 之后,就可以通過獲取服務(wù)的特征進(jìn)行讀寫。
-
特征的讀寫數(shù)據(jù)
前面介紹了,通信主體實(shí)際上是 特征,要進(jìn)行讀寫操作,其實(shí)就是在操作特征里的屬性詞條,所以要先通過 服務(wù) 獲取 特征:/* 假設(shè) service 是從上一步獲取到的一個 BluetoothGattService 實(shí)例*/ ··· BluetoothGattService service; /* 獲取該服務(wù)的特征列表 */ service.getCharacteristics(); /* 通過特征的UUID,獲取指定的特征, * 如果沒有找到給定UUID的特征,返回null, * 如果服務(wù)中存在多個給定UUID的特征,則返回第一個實(shí)例 */ service.getCharacteristic(UUID);
獲取到了特征之后,就可以通過上面獲取到的 mGatt 讀寫信息:
/* 上一步獲取的 BluetoothGattCharacteristic 實(shí)例 */ ··· BluetoothGattCharacteristic characteristic; /* 從關(guān)聯(lián)的遠(yuǎn)程設(shè)備讀取請求的特征, * 異步操作,請求發(fā)起成功則返回true,讀取完成會回調(diào): * BluetoothGattCallback.onCharacteristicRead() */ mGatt.readCharacteristic(characteristic); /* 將給定的特征及其值寫入關(guān)聯(lián)的遠(yuǎn)程設(shè)備, * 異步操作,請求發(fā)起成功則返回true,寫入完成會回調(diào): * BluetoothGattCallback.onCharacteristicWrite() */ mGatt.writeCharacteristic(characteristic);
讀寫操作都是異步操作,方法返回的是請求是否成功,請求結(jié)果都會回調(diào) BluetoothGattCallback 的方法:
/** * 讀操作的回調(diào) * @param characteristic: 讀取后的特征 * @param status: 讀取結(jié)果,成功為 GATT_SUCCESS */ void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { ··· } /** * 寫操作的回調(diào) * @param characteristic: 寫入后的特征 * 注意:這里返回的特征,為設(shè)備當(dāng)前的特征, * 應(yīng)該在該回調(diào)中,應(yīng)對比該特征的內(nèi)容是否符合期望值, * 如果與期望值不同,應(yīng)該選擇重發(fā)或終止寫入。 * * @param status: 寫入結(jié)果,成功為 GATT_SUCCESS */ void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { ··· }
寫數(shù)據(jù)的時候要注意,需要對比返回的特征和寫入的特征,判斷是否寫入成功或者產(chǎn)生了異常,選擇繼續(xù)寫入或者重寫,或者放棄操作。
-
描述符的讀寫數(shù)據(jù)
讀寫方式與 特征 的 讀寫方式基本一致,不再過多描述 :/* 獲取描述符 */ ··· BluetoothGattCharacteristic characteristic; characteristic.getDescriptors(); characteristic.getDescriptor(UUID); /* 通過 mGatt 讀寫數(shù)據(jù) * 同樣,寫操作需要做寫入結(jié)果校驗 */ ··· BluetoothGattDescriptor descriptor; mGatt.readDescriptor(descriptor); mGatt.writeDescriptor(descriptor); /* 結(jié)果回調(diào) */ void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { ··· } void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { ··· }
-
讀寫數(shù)據(jù)需要注意的問題
寫入數(shù)據(jù)量:
每次寫操作的時候,無論是 特征 或者 描述符,一般來說最大只能設(shè)置 20個字節(jié) 的數(shù)據(jù)。
這是因為ATT協(xié)議中,最大傳輸單元MTU的默認(rèn)大小為23字節(jié),其中3字節(jié)用于ATT協(xié)議的控制數(shù)據(jù),所以GATT可用的數(shù)據(jù)大小默認(rèn)為剩余的20字節(jié)。ATT的MTU最大值為512,在API 21及以上的安卓平臺,可以通過以下方法嘗試改變MTU的大小:
··· int mMtu; /* 請求變更MTU的大小 */ BluetoothGatt.requestMtu(mMtu); /* 請求結(jié)果通過 BluetoothGattCallback 回調(diào) * 當(dāng)statue返回為 GATT_SUCCESS 時,表示變更成功 * 變更成功后,可以使用(mMtu - 3)的大小傳輸數(shù)據(jù)*/ public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {}
無法改變的時候,超過20字節(jié)的數(shù)據(jù),進(jìn)行分包發(fā)送(BLE服務(wù)端需要支持)。
讀寫間隔:
讀寫操作都是隊列操作,需要等待操作結(jié)果返回后,才能進(jìn)行下次操作,若當(dāng)次操作未完成,下次操作調(diào)用時,將直接返回操作啟用失敗。寫入操作時,需等待服務(wù)器的確認(rèn)信息,即寫入回調(diào),再進(jìn)行下次寫入操作。
當(dāng)寫入類型設(shè)置為 不需要接收服務(wù)器確認(rèn)信息(PROPERTY_WRITE_NO_RESPONSE)以加快傳輸速度時,兩次操作之間應(yīng)保留 80ms ~ 100ms 或以上的延時。 -
數(shù)據(jù)變更通知
前面說到ATT支持通知,一些特征在值發(fā)生變化時,可以主動向申請了監(jiān)聽數(shù)據(jù)變化的客戶端推送通知或指示(不帶數(shù)據(jù))。
開啟特征的監(jiān)聽,需要進(jìn)行兩步操作:設(shè)置特征信息推送:
/** * 啟用或禁用給定特征的通知或指示 * @param characteristic: 需要進(jìn)行操作的特征 * @param enable : 開啟或關(guān)閉 */ BluetoothGatt.setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enable);
寫入CCCD:
雖然開啟了特征的信息推送,但假如特征本身禁用了通知和指示,則不會有更新推送。
前面提到了一個特殊的標(biāo)識符CCCD,用于控制特征的消息推送。需要對特征的CCCD描述符進(jìn)行操作,將其值置為 1 / 2,才能開啟對應(yīng)的 通知 / 指示 功能。/* 設(shè)置特征信息推送 */ ··· BluetoothGattCharacteristic characteristic; mGatt.setCharacteristicNotification(characteristic,true); /* CCCD 的UUID */ private UUID ID_CCCD = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); /* 獲取CCCD */ BluetoothGattDescriptor cccd = characteristic.getDescriptor(ID_CCCD); /* 設(shè)置推送通知,參考值為: * BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE: 通知 * BluetoothGattDescriptor.ENABLE_INDICATION_VALUE: 指示 * BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE: 關(guān)閉 */ cccd.setValue(參考值); /* 寫入CCCD */ mGatt.writeDescriptor(descriptor);
以上操作完成后,即開啟對應(yīng)特征的更新推送了。
接收推送:
更新推送會回調(diào)BluetoothGattCallback的onCharacteristicChanged()方法:/** * 特征變更推送觸發(fā)的回調(diào) * @param gatt: 特征 關(guān)聯(lián)的 BluetoothGatt 實(shí)例 * @param characteristic: 更新后的 特征 */ void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
-
關(guān)閉客戶端
用完的東西總是要收拾好。斷開連接:
/* 斷開當(dāng)前連接,如果正在連接中,則取消連接操作 */ BluetoothGatt.disconnect();
斷開連接操作后,結(jié)果回調(diào) onConnectionStateChange() 方法,應(yīng)該通過回調(diào)返回的結(jié)果 status 和 newState 判斷是否成功斷開。
關(guān)閉Gatt客戶端:
成功斷開連接之后(甚至是斷開失敗),應(yīng)該調(diào)用 BluetoothGatt 的close() 方法關(guān)閉客戶端釋放資源。
安卓同時連接遠(yuǎn)程設(shè)備的資源極其有限,在所以任何情況不再需要連接遠(yuǎn)程設(shè)備時,都要使用BluetoothGatt 的 close() 方法釋放資源。
參考文章:
藍(lán)牙技術(shù)基礎(chǔ)知識學(xué)習(xí)
藍(lán)牙核心技術(shù)概述
GATT協(xié)議及藍(lán)牙核心系統(tǒng)結(jié)構(gòu)
Android BLE的總結(jié)
Android BLE 藍(lán)牙開發(fā)入門
更具體的藍(lán)牙技術(shù)說明請查看官方網(wǎng)站
Bluetooth Technology Website
歡迎留言,歡迎關(guān)注,會持續(xù)更新 安卓開發(fā) 中遇到的問題和技術(shù)上的一些自我總結(jié)。
如有錯誤,歡迎指出。