0x00 低功耗藍(lán)牙(BLE)
上一篇簡(jiǎn)單介紹了傳統(tǒng)藍(lán)牙設(shè)備的使用,當(dāng)你沿著上一篇的思路去連接某些藍(lán)牙設(shè)備的時(shí)候判族,你會(huì)發(fā)現(xiàn)總是不成功臀稚。沒(méi)錯(cuò)疫粥,我們還有另外一種藍(lán)牙沒(méi)有講:低功耗藍(lán)牙(BLE: Bluetooth Low Energy)蟆湖。
這并不是一種新的東西故爵,它只是藍(lán)牙協(xié)議中的一個(gè)新的版本。之前提到的多是藍(lán)牙2.0/2.1隅津,這里的低功耗藍(lán)牙(BLE)主要是指藍(lán)牙4.0/4.1/4.2。在我們的日常生活中這種藍(lán)牙越來(lái)越常見(jiàn),比如各種手環(huán)里逆、體脂秤、智能設(shè)備荠列、便攜藍(lán)牙設(shè)備等等。
更多關(guān)于藍(lán)牙的介紹可以參考這里
0x01 藍(lán)牙協(xié)議棧
和學(xué)習(xí) TCP/IP 一樣,如果了解BLE的議棧對(duì)我們掌握藍(lán)牙會(huì)有很大的幫助。
-
物理 (PHY) 層
通過(guò)藍(lán)牙通信信道控制 2.4Ghz 射頻的傳輸/接收喉磁。BR/EDR 提供的信道較多但帶寬較窄,而 LE 使用的信道較少但帶寬較寬悠垛。
-
鏈路層
定義數(shù)據(jù)包結(jié)構(gòu)/信道、發(fā)現(xiàn)/連接程序以及發(fā)送/接收數(shù)據(jù)娜谊。
-
直接測(cè)試模式
允許測(cè)試人員向 PHY 層發(fā)出指令以傳輸或接收給定數(shù)據(jù)包序列确买,通過(guò) HCI 或 2 線 UART 接口提交命令。
-
主機(jī)控制器接口 (HCI)
藍(lán)牙控制器子系統(tǒng)(底部三層)和藍(lán)牙主機(jī)之間的可選標(biāo)準(zhǔn)接口纱皆。
-
邏輯鏈路控制和適配協(xié)議 (L2CAP) 層
基于數(shù)據(jù)包的協(xié)議湾趾,可將數(shù)據(jù)包傳輸至 HCI 或直接傳輸?shù)綗o(wú)主機(jī)系統(tǒng)中的鏈路管理器。支持更高級(jí)別的協(xié)議多路復(fù)用派草、數(shù)據(jù)包分割和重組搀缠,以及將服務(wù)質(zhì)量信息傳輸?shù)礁邔印?/p>
-
屬性協(xié)議 (ATT)
在建立連接之后定義數(shù)據(jù)交換客戶(hù)端/服務(wù)器協(xié)議。使用通用屬性配置文件 (GATT) 將屬性分類(lèi)為有意義的服務(wù)近迁。ATT 主要用于 LE 部署艺普,偶爾也會(huì)用于 BR/EDR 部署。
-
安全管理器
定義管理藍(lán)牙設(shè)備之間配對(duì)完整性鉴竭、身份驗(yàn)證以及加密的協(xié)議和操作歧譬,提供安全功能工具箱,其他組件可利用該工具箱支持不同應(yīng)用所需的各種安全級(jí)別搏存。
-
通用屬性配置文件 (GATT)
使用屬性協(xié)議瑰步,GATT 對(duì)封裝設(shè)備組件性能的服務(wù)進(jìn)行分組,并描述基于 GATT 功能的用例璧眠、角色和一般性能缩焦。其服務(wù)框架定義服務(wù)規(guī)程和格式及其特性,其中包括發(fā)現(xiàn)责静、讀取袁滥、寫(xiě)入、通知以及指示特性以及配置特性廣播灾螃。GATT 僅用于藍(lán)牙 LE 部署呻拌。 詳細(xì)了解 GATT 信息。
通用訪問(wèn)配置文件(GAP)
可與藍(lán)牙 LE 部署中的 GATT 配合使用睦焕,以定義與發(fā)現(xiàn)藍(lán)牙設(shè)備和共享信息相關(guān)的規(guī)程和角色藐握,以及連接藍(lán)牙設(shè)備的鏈路管理內(nèi)容靴拱。
0x02 Android系統(tǒng)中的BLE
Android系統(tǒng)中對(duì)于低功耗藍(lán)牙我們需要關(guān)心以下幾點(diǎn):
- Android 4.3(18)開(kāi)始支持BLE
- Android 5.0(21)之前手機(jī)只可以作為中心設(shè)備(Central mode)使用,5.0之后可以作為外設(shè)(Peripheral mode)使用
除了以上信息猾普,我們?cè)趯?duì)協(xié)議中的幾個(gè)概念做個(gè)介紹袜炕,這涉及到之后的開(kāi)發(fā):
-
Attribute Protocol (ATT)
屬性協(xié)議,對(duì)應(yīng)
BluetoothGattService
-
Generic Attribute Profile (GATT)
通用屬性配置文件初家,對(duì)應(yīng)Android中的
BluetoothGatt
-
Characteristic
BluetoothGattCharacteristic
-
Descriptor
BluetoothGattDescriptor
-
Service
BluetoothGattService
0x03 Android系統(tǒng)中的BLE操作流程
和之前的普通藍(lán)牙相同偎窘,我們需要先檢測(cè)設(shè)備的藍(lán)牙是否可用,然后掃描周?chē)乃{(lán)牙設(shè)備溜在,然后連接陌知。這里可以看到,BLE的操作并不需要配對(duì)掖肋。如需要在設(shè)備必須支持低功耗藍(lán)牙仆葡,則還需要加上這句:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
-
藍(lán)牙掃描
private boolean mScanning; private void scanLeDevice(final boolean enable) { if (enable) { mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } } // Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { String format = "Name:%s, Mac:%s, Type:%s"; String msg = String.format(format, device.getName(), device.getAddress(), device.getType()); print(msg); } };
掃描完成之后,我們會(huì)拿到藍(lán)牙的設(shè)備信息志笼,然后就可以進(jìn)行連接了沿盅。
-
連接藍(lán)牙
@Override public int onStartCommand(Intent intent, int flags, int startId) { if (null != intent) { mMAC = intent.getStringExtra(KEY_MAC); } if (TextUtils.isEmpty(mMAC)) { mMAC = MAC_BIKE; } mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = mBluetoothManager.getAdapter(); if (null == mBluetoothAdapter) { stopSelf(); return START_NOT_STICKY; } BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mMAC); if (null == device) { stopSelf(); return START_NOT_STICKY; } closeConnect(); mBluetoothGatt = device.connectGatt(this, false, mCallBack); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //5.0設(shè)置的傳輸最大空間 mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH); mBluetoothGatt.requestMtu(84); } print("Gatt connect"); return START_STICKY; }
-
連接藍(lán)牙
在連接的CallBack中如果我們檢測(cè)到連接成功,才可以請(qǐng)求藍(lán)牙提供的服務(wù)纫溃,這里先檢測(cè)連接的狀態(tài):
private final BluetoothGattCallback mCallBack = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); print(String.format("status:%d, newState:%d", status, newState)); if (status != BluetoothGatt.GATT_SUCCESS) { closeConnect(); } switch (newState) { case BluetoothProfile.STATE_CONNECTED: print("連接GATT服務(wù)成功腰涧,開(kāi)始發(fā)現(xiàn)服務(wù)..."); gatt.discoverServices(); break; case BluetoothProfile.STATE_DISCONNECTED: print("斷開(kāi)GATT服務(wù),Bye"); closeConnect(); break; default: break; } } ... };
-
發(fā)現(xiàn)服務(wù)
private final BluetoothGattCallback mCallBack = new BluetoothGattCallback() { @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); print("發(fā)現(xiàn)服務(wù):" + status); if (BluetoothGatt.GATT_SUCCESS == status) { List<BluetoothGattService> gattServices = gatt.getServices(); if (null == gattServices || gattServices.size() == 0) { return; } for (BluetoothGattService gattService : gattServices) { String serviceUUID = gattService.getUuid().toString(); print("UUID GATT:" + serviceUUID); List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics(); for (BluetoothGattCharacteristic characteristic : characteristics) { String uuid = characteristic.getUuid().toString(); print("UUID Cha:" + uuid); print("UUID Status:" + getProperties(characteristic)); if (UUID_RECEIVE.toString().equalsIgnoreCase(uuid)) { mBluetoothGatt.setCharacteristicNotification(characteristic, true); print("開(kāi)始監(jiān)聽(tīng):" + uuid); } } } } } ... }
-
使用服務(wù)
...
0x04 還需要了解的一些細(xì)節(jié)
- UUID
- 判斷服務(wù)的屬性
0x05 可能會(huì)遇到的坑
手上的兩臺(tái)魅族設(shè)備紊浩,連接一個(gè)客戶(hù)提供的藍(lán)牙模塊窖铡,死活連不上,其他手機(jī)連接正常坊谁。這兩部設(shè)備連接淘寶上買(mǎi)的一個(gè)藍(lán)牙模塊正常万伤。
0xFF 參考
- https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
- https://www.bluetooth.com/zh-cn/specifications/bluetooth-core-specification
- https://zh.wikipedia.org/wiki/%E8%97%8D%E7%89%99#.E8.97.8D.E7.89.994.0
- https://race604.com/android-ble-in-action/
- http://blog.csdn.net/qinxiandiqi/article/details/40741269
- http://www.reibang.com/p/8690dbafe849
- https://www.bluetooth.com/zh-cn/specifications/adopted-specifications
- https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439