相關(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è)備間的配對(duì)滥嘴,數(shù)據(jù)傳輸通過WIFI射頻來完成以達(dá)到高速率木蹬。
假如設(shè)備某一方?jīng)]有內(nèi)建WIFI模塊,速率將降至 EDR 速率若皱。BLE
Bluetooth Low Energy镊叁,低耗藍(lán)牙技術(shù),V4.0版本的新規(guī)范走触,通過三個(gè)方式實(shí)現(xiàn)超低功耗:
1.大幅度削減掃描信道
2.極短的鏈路連接時(shí)間
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ù)定義兩個(gè)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í)例 需要的一個(gè)或多個(gè)服務(wù)組成柔纵。-
服務(wù)(Service):
服務(wù) 由 特征 和 其他服務(wù)的引用 組成缔杉,擁有固定的 UUID 作為標(biāo)記值。
設(shè)備的功能主要體現(xiàn)在服務(wù)上搁料,每種服務(wù)都對(duì)應(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通信的主體拣宏,是一個(gè)服務(wù)端和客戶端共享的讀寫空間沈贝。
主機(jī)在從機(jī)上獲取所需的信息,實(shí)際就是通過獲取對(duì)應(yīng)的特征的內(nèi)容進(jìn)行的勋乾。特征由屬性值和描述符組成:
- 屬性值
屬性值包括聲明(Declaration)宋下,值(Value),一個(gè)屬性值最少包括一個(gè)聲明和一個(gè)值辑莫,即是屬性值是特征必選的條目学歧。 - 描述符
特征可以包括零到若干個(gè)描述符,可選條目各吨。
特征信息列表可以查看官方文檔 GATT Characteristics枝笨。
- 屬性值
-
描述符(Descriptors)
用于表達(dá) 特征 的其他附加信息,如特征值的有效范圍揭蜒,可讀性描述等信息横浑。其中包含了特殊的 CCCD(Client Characteristic Configuration Descriptor, Assigned Number : 0x2902):
CCCD 可以設(shè)置 服務(wù)端 在對(duì)應(yīng)特征值發(fā)生變化時(shí),是否對(duì) 客戶端 進(jìn)行信息 推送(直接發(fā)送信息) 或 提示(發(fā)送一個(gè)提示并等待回復(fù))屉更。
當(dāng)特征包含通知能力時(shí)徙融,CCCD為必選項(xiàng)。描述符列表可以查看官方文檔 GATT Descriptors瑰谜。
2:Android BLE 相關(guān) API
-
BluetoothAdapter
藍(lán)牙適配器:本地設(shè)備藍(lán)牙適配器欺冀,提供基本藍(lán)牙功能的工具树绩,例如開啟藍(lán)牙發(fā)現(xiàn),查詢配對(duì)設(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ì)上只是對(duì)藍(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é)果都會(huì)通過該類實(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è)備 和 停止掃描 的操作颜启,都需要用到該類的實(shí)例偷俭。
-
BluetoothGattService
GATT服務(wù),根據(jù)服務(wù)的 UUID缰盏,嘗試獲取服務(wù)實(shí)例涌萤。/* 如果對(duì)應(yīng)的設(shè)備支持該服務(wù)淹遵,則返回一個(gè)服務(wù)的實(shí)例,否則返回空 */ BluetoothGatt.getService(uuid);
-
BluetoothGattCharacteristic
GATT特征负溪,實(shí)際通信中的數(shù)據(jù)信息主體透揣。通過以下方法獲取:/* 獲取對(duì)應(yīng)UUID的特征 */ BluetoothGattService.getCharacteristic(uuid); /* 獲取服務(wù)的特征列表 */ BluetoothGattService.getCharacteristics();
3:Android BLE 開發(fā)示例
-
聲明權(quán)限
一個(gè)聲明和兩個(gè)基本權(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è)備的時(shí)候川抡,需要使用定位權(quán)限辐真。
而在5.0及以上的版本,需要手動(dòng)聲明GPS硬件模塊功能的權(quán)限:<uses-feature android:name="android.hardware.location.gps"/>
而在6.0及以上版本崖堤,掃描設(shè)備還需要 動(dòng)態(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); }
-
啟動(dòng)設(shè)備掃描
創(chuàng)建LeScanCallback實(shí)例:
首先需要實(shí)現(xiàn)一個(gè) LeScanCallback 實(shí)例,掃描結(jié)果會(huì)通過實(shí)例的 onLeScan 方法返回:LeScanCallback mCallBack = new LeScanCallback (){ @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {} }
啟動(dòng)掃描與停止掃描:
··· static int SCAN_TIME = 5_000; ··· Handler mHandler = new Handler(); /* 開始掃描: 由于掃描消耗電量胯甩,所以不能一直處于掃描狀態(tài)昧廷, 設(shè)置掃描一段時(shí)間后關(guān)閉掃描 */ mAdapter.startLeScan(mCallBack); mHandler.postDelay(()->{ /* 關(guān)閉掃描: * 注意需要傳入啟動(dòng)掃描時(shí)的 callback對(duì)象,否則無效 */ mAdapter.stopLeScan(mCallBack); }, SCAN_TIME);
在 API 21 及以上時(shí)偎箫,掃描操作應(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: 識(shí)別到的遠(yuǎn)程設(shè)備 * * @param rssi: 信號(hào)強(qiáng)度指示木柬,計(jì)數(shù)為dB⊙桶欤可以通過: d = 10^((abs(RSSI) - A) / (10 * n)) 計(jì)算出距離眉枕。A和n根據(jù)環(huán)境改變,需經(jīng)實(shí)驗(yàn)測出娇唯, 給出兩個(gè)網(wǎng)上的經(jīng)驗(yàn)值: <1> A: 50 n: 2.5 <2> A: 59 n: 2.0 * * @param scanRecord:廣播數(shù)據(jù)和掃描應(yīng)答數(shù)據(jù)數(shù)據(jù) BLE設(shè)備在對(duì)外廣播中齐遵,廣播中會(huì)攜帶一些有用的信息。 其中包含了 廣播數(shù)據(jù) 和 掃描應(yīng)答數(shù)據(jù)塔插, 兩者有效荷載最大都為 31字節(jié)(藍(lán)牙4)梗摇, 以十六進(jìn)制格式存儲(chǔ),可通過 bytesToHex 轉(zhuǎn)換成可用的字符串想许。 */ void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {}
注意相同的 BluetoothDevice 會(huì)重復(fù)出現(xiàn)在回調(diào)中伶授,所以如果要記錄藍(lán)牙列表,需要自行 過濾 重復(fù)出現(xiàn)的設(shè)備流纹,或更新對(duì)應(yīng)重復(fù)出現(xiàn)的設(shè)備的信息糜烹。
bytesToHex 參考 -
連接外圍設(shè)備
通過 BluetoothDevice 的 connectGatt 方法獲取一個(gè) BluetoothGatt 實(shí)例。
connectGatt 有多個(gè)重載方法漱凝,這里介紹其中最復(fù)雜的重載方法:/** * 以客戶端的身份連接到該設(shè)備托管的GATT服務(wù)器 * * @param autoConnect:自動(dòng)連接疮蹦,設(shè)備不可用時(shí)會(huì)不斷嘗試重連。 * * @param callback: BluetoothGattCallback實(shí)例茸炒,用于接收異步回調(diào) * * @param transport: GATT連接到雙模設(shè)備的首選傳輸模式: * 1:TRANSPORT_AUTO 自動(dòng)選擇 (默認(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)制要求支持的模式阵苇, * 符號(hào)速率為1M/s,未編碼感论。 * 2:PHY_LE_2M_MASK: * 符號(hào)速率為2M/s绅项,未編碼, * 用于 藍(lán)牙5 的 "2x speed" 2倍速率比肄。 * 3:PHY_LE_CODED_MASK: * 在數(shù)據(jù)包中增加糾錯(cuò)編碼以實(shí)現(xiàn)更遠(yuǎn)的傳輸范圍快耿, * 以實(shí)現(xiàn) 藍(lán)牙5 的 "4x range" 4倍范圍。 * 使用FEC編碼芳绩,根據(jù)方案又分為: * LE Coded S=2:2個(gè)編碼位代替原來一個(gè)數(shù)據(jù)位掀亥, * 速率降為 500K/s,傳輸范圍增大2倍妥色; * LE Coded S=8:8個(gè)編碼位代替原來一個(gè)數(shù)據(jù)位铺浇, * 速率降為 125K/s,傳輸范圍增大4倍垛膝; * 設(shè)置 autoConnect 自動(dòng)連接時(shí),該項(xiàng)無效 * * @param handler: 傳入一個(gè)Handler丁稀,以指定回調(diào)發(fā)生的線程吼拥, * 傳入null時(shí),回調(diào)將會(huì)在一個(gè)未指定的后臺(tái)線程上進(jìn)行线衫。 */ BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler) { ··· }
一般情況下使用默認(rèn)值既可凿可,
注意必須傳入非空的callback,否則會(huì)拋出 IllegalArgumentException:BluetoothDevice.connectGatt(content, autoConnect, callback);
當(dāng)連接成功時(shí)授账,會(huì)回調(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 時(shí)白热,newState才是有效值敛助。
注意一臺(tái)安卓設(shè)備最多同時(shí)連接6個(gè)左右的藍(lán)牙設(shè)備,超出時(shí)可能出現(xiàn):
status == 133 連接錯(cuò)誤屋确,
所以需要注意調(diào)用 BluetoothGatt.close() 方法進(jìn)行資源釋放纳击。
可參考:Android中BLE連接出現(xiàn)“BluetoothGatt status 133”的解決方法當(dāng) status == GATT_SUCCESS,且 newState == STATE_CONNECTED 時(shí)攻臀,表示已成功連接設(shè)備焕数,可以進(jìn)行下一步操作。
-
發(fā)現(xiàn)服務(wù)
在建立連接之后刨啸,就可以通過 BluetoothGatt實(shí)例 進(jìn)行發(fā)現(xiàn)服務(wù)操作堡赔,查找設(shè)備支持的服務(wù)。/** * 異步操作设联,發(fā)現(xiàn)服務(wù)完成時(shí)善已,會(huì)回調(diào)onServicesDiscovered()方法灼捂。 * 假如發(fā)現(xiàn)服務(wù)已在啟動(dòng)狀態(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ù)衰絮,會(huì)返回一個(gè)空列表 */ mGatt.getServices(); /* 通過服務(wù)的UUID,獲取指定的服務(wù)磷醋, * 如果遠(yuǎn)程設(shè)備不支持給定UUID的服務(wù)猫牡,返回null, * 如果遠(yuǎn)程設(shè)備存在多個(gè)給定UUID的服務(wù)實(shí)例邓线,則返回第一個(gè)實(shí)例 */ mGatt.getService(UUID);
獲取到 BluetoothGattService 之后淌友,就可以通過獲取服務(wù)的特征進(jìn)行讀寫。
-
特征的讀寫數(shù)據(jù)
前面介紹了骇陈,通信主體實(shí)際上是 特征震庭,要進(jìn)行讀寫操作,其實(shí)就是在操作特征里的屬性詞條你雌,所以要先通過 服務(wù) 獲取 特征:/* 假設(shè) service 是從上一步獲取到的一個(gè) BluetoothGattService 實(shí)例*/ ··· BluetoothGattService service; /* 獲取該服務(wù)的特征列表 */ service.getCharacteristics(); /* 通過特征的UUID器联,獲取指定的特征, * 如果沒有找到給定UUID的特征婿崭,返回null拨拓, * 如果服務(wù)中存在多個(gè)給定UUID的特征,則返回第一個(gè)實(shí)例 */ service.getCharacteristic(UUID);
獲取到了特征之后氓栈,就可以通過上面獲取到的 mGatt 讀寫信息:
/* 上一步獲取的 BluetoothGattCharacteristic 實(shí)例 */ ··· BluetoothGattCharacteristic characteristic; /* 從關(guān)聯(lián)的遠(yuǎn)程設(shè)備讀取請求的特征渣磷, * 異步操作,請求發(fā)起成功則返回true授瘦,讀取完成會(huì)回調(diào): * BluetoothGattCallback.onCharacteristicRead() */ mGatt.readCharacteristic(characteristic); /* 將給定的特征及其值寫入關(guān)聯(lián)的遠(yuǎn)程設(shè)備幸海, * 異步操作,請求發(fā)起成功則返回true奥务,寫入完成會(huì)回調(diào): * BluetoothGattCallback.onCharacteristicWrite() */ mGatt.writeCharacteristic(characteristic);
讀寫操作都是異步操作物独,方法返回的是請求是否成功,請求結(jié)果都會(huì)回調(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)對(duì)比該特征的內(nèi)容是否符合期望值, * 如果與期望值不同官研,應(yīng)該選擇重發(fā)或終止寫入秽澳。 * * @param status: 寫入結(jié)果,成功為 GATT_SUCCESS */ void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { ··· }
寫數(shù)據(jù)的時(shí)候要注意戏羽,需要對(duì)比返回的特征和寫入的特征担神,判斷是否寫入成功或者產(chǎn)生了異常,選擇繼續(xù)寫入或者重寫始花,或者放棄操作妄讯。
-
描述符的讀寫數(shù)據(jù)
讀寫方式與 特征 的 讀寫方式基本一致,不再過多描述 :/* 獲取描述符 */ ··· BluetoothGattCharacteristic characteristic; characteristic.getDescriptors(); characteristic.getDescriptor(UUID); /* 通過 mGatt 讀寫數(shù)據(jù) * 同樣酷宵,寫操作需要做寫入結(jié)果校驗(yàn) */ ··· 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í)候亥贸,無論是 特征 或者 描述符,一般來說最大只能設(shè)置 20個(gè)字節(jié) 的數(shù)據(jù)浇垦。
這是因?yàn)锳TT協(xié)議中炕置,最大傳輸單元MTU的默認(rèn)大小為23字節(jié),其中3字節(jié)用于ATT協(xié)議的控制數(shù)據(jù)男韧,所以GATT可用的數(shù)據(jù)大小默認(rèn)為剩余的20字節(jié)朴摊。ATT的MTU最大值為512,在API 21及以上的安卓平臺(tái)此虑,可以通過以下方法嘗試改變MTU的大腥耘:
··· int mMtu; /* 請求變更MTU的大小 */ BluetoothGatt.requestMtu(mMtu); /* 請求結(jié)果通過 BluetoothGattCallback 回調(diào) * 當(dāng)statue返回為 GATT_SUCCESS 時(shí),表示變更成功 * 變更成功后寡壮,可以使用(mMtu - 3)的大小傳輸數(shù)據(jù)*/ public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {}
無法改變的時(shí)候,超過20字節(jié)的數(shù)據(jù)讹弯,進(jìn)行分包發(fā)送(BLE服務(wù)端需要支持)况既。
讀寫間隔:
讀寫操作都是隊(duì)列操作,需要等待操作結(jié)果返回后组民,才能進(jìn)行下次操作棒仍,若當(dāng)次操作未完成,下次操作調(diào)用時(shí)臭胜,將直接返回操作啟用失敗莫其。寫入操作時(shí),需等待服務(wù)器的確認(rèn)信息耸三,即寫入回調(diào)乱陡,再進(jìn)行下次寫入操作。
當(dāng)寫入類型設(shè)置為 不需要接收服務(wù)器確認(rèn)信息(PROPERTY_WRITE_NO_RESPONSE)以加快傳輸速度時(shí)仪壮,兩次操作之間應(yīng)保留 80ms ~ 100ms 或以上的延時(shí)憨颠。 -
數(shù)據(jù)變更通知
前面說到ATT支持通知,一些特征在值發(fā)生變化時(shí),可以主動(dòng)向申請了監(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:
雖然開啟了特征的信息推送,但假如特征本身禁用了通知和指示适篙,則不會(huì)有更新推送往核。
前面提到了一個(gè)特殊的標(biāo)識(shí)符CCCD,用于控制特征的消息推送嚷节。需要對(duì)特征的CCCD描述符進(jìn)行操作聂儒,將其值置為 1 / 2,才能開啟對(duì)應(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);
以上操作完成后,即開啟對(duì)應(yīng)特征的更新推送了碍论。
接收推送:
更新推送會(huì)回調(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)閉客戶端釋放資源蠢挡。
安卓同時(shí)連接遠(yuǎn)程設(shè)備的資源極其有限弧岳,在所以任何情況不再需要連接遠(yuǎn)程設(shè)備時(shí),都要使用BluetoothGatt 的 close() 方法釋放資源业踏。
參考文章:
藍(lán)牙技術(shù)基礎(chǔ)知識(shí)學(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)注,會(huì)持續(xù)更新 安卓開發(fā) 中遇到的問題和技術(shù)上的一些自我總結(jié)勤家。
如有錯(cuò)誤腹尖,歡迎指出。