Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android BLE學習筆記

Android BLE學習筆記

編輯:關於Android編程

前言:

本文主要描述Android BLE的一些基礎知識及相關操作流程,不牽扯具體的業務實現,其中提供了針對廣播包及響應包的解析思路,希望對正在或即將面臨Android BLE開發的伙伴們有所引導。
注:其中的單模、雙模、BR、BT、BLE、藍牙3.0、藍牙4.0等概念混在一起可能比較難理解,不知下文描述是否清晰,如果有不理解的地方,歡迎留言交流!

一、相關介紹

1、概述

藍牙無線技術是一種全球通用的短距離無線技術,通過藍牙技術能夠實現多種電子設備間的相互連接,特別是在小型無線電、耗電量低、成本低、安全性、穩定性、易用性以及特別的聯網能力等固有的優勢上,藍牙無線技術發展迅速。

2、分類

藍牙分為三種:Bluetooth Smart Ready、Bluetooth Smart(Smart是低功耗藍牙的標識)、以及標准 Bluetooth。根據 Bluetooth SIG的說法,這樣是為了要分辨裝置間的相容性以及標識各版本的傳輸頻率。基本上來說,Bluetooth Smart Ready適用於任何雙模藍牙4.0的電子產品,而Bluetooth Smart是應用在心率監視器或計步器等使用扭扣式電池並傳輸單一的裝置。Bluetooth Smart Ready的相容性最高,可與Bluetooth Smart及標准藍牙相通。標准藍牙則無法與Bluetooth Smart相通。
\

3、BLE介紹

BLE是Bluetooth Low Energy的縮寫,又叫藍牙4.0,區別於藍牙3.0和之前的技術。BLE前身是NOKIA開發的Wibree技術,主要用於實現移動智能終端與周邊配件之間的持續連接,是功耗極低的短距離無線通信技術,並且有效傳輸距離被提升到了100米以上,同時只需要一顆紐扣電池就可以工作數年之久。BLE是在藍牙技術的基礎上發展起來的,既同於藍牙,又區別於傳統藍牙。BLE設備分單模和雙模兩種,雙模簡稱BR,商標為Bluetooth Smart Ready,單模簡稱BLE或者LE,商標為Bluetooth Smart。Android是在4.3後才支持BLE,這說明不是所有藍牙手機都支持BLE,而且支持BLE的藍牙手機一般是雙模的。雙模兼容傳統藍牙,可以和傳統藍牙通信,也可以和BLE通信,常用在手機上,android4.3和IOS4.0之後版本都支持BR,也就是雙模設備。單模只能和BR和單模的設備通信,不能和傳統藍牙通信,由於功耗低,待機長,所以常用在手環的智能設備上。

二、基本概念

1、Generic Access Profile(GAP)

用來控制設備連接和廣播,GAP使你的設備被其他設備可見,並決定了你的設備是否可以或者怎樣與合同設備進行交互。

2、Generic Attribute Profile(GATT)

通過BLE連接,讀寫屬性類數據的Profile通用規范,現在所有的BLE應用Profile都是基於GATT的。

3、Attribute Protocol (ATT)

GATT是基於ATTProtocol的,ATT針對BLE設備做了專門的優化,具體就是在傳輸過程中使用盡量少的數據,每個屬性都有一個唯一的UUID,屬性將以characteristics and services的形式傳輸。

4、Characteristic

Characteristic可以理解為一個數據類型,它包括一個value和0至多個對次value的描述(Descriptor)。

5、Descriptor

對Characteristic的描述,例如范圍、計量單位等。

6、Service

Characteristic的集合。例如一個service叫做“Heart Rate Monitor”,它可能包含多個Characteristics,其中可能包含一個叫做“heart ratemeasurement”的Characteristic。

7、UUID

唯一標示符,每個Service,Characteristic,Descriptor,都是由一個UUID定義。

三、Android BLE API

1、BluetoothGatt

繼承BluetoothProfile,通過BluetoothGatt可以連接設備(connect),發現服務(discoverServices),並把相應地屬性返回到BluetoothGattCallback,可以看成藍牙設備從連接到斷開的生命周期。

2、BluetoothGattCharacteristic

相當於一個數據類型,可以看成一個特征或能力,它包括一個value和0~n個value的描述(BluetoothGattDescriptor)。

3、BluetoothGattDescriptor

描述符,對Characteristic的描述,包括范圍、計量單位等。

4、BluetoothGattService

服務,Characteristic的集合。

5、BluetoothProfile

一個通用的規范,按照這個規范來收發數據。

6、BluetoothManager

通過BluetoothManager來獲取BluetoothAdapter。
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

7、BluetoothAdapter

代表了移動設備的本地的藍牙適配器, 通過該藍牙適配器可以對藍牙進行基本操作,一個Android系統只有一個BluetoothAdapter,通過BluetoothManager獲取。
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();

8、BluetoothDevice

掃描後發現可連接的設備,獲取已經連接的設備。
BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);

9、BluetoothGattCallback

已經連接上設備,對設備的某些操作後返回的結果。

BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback(){
    //實現回調方法,根據業務做相應處理
};
BluetoothGatt bluetoothGatt = bluetoothDevice.connectGatt(this, false, bluetoothGattCallback);

三、操作流程

1、藍牙開啟

在使用藍牙BLE之前,需要確認Android設備是否支持BLE feature(required為false時),另外要需要確認藍牙是否打開。如果發現不支持BLE,則不能使用BLE相關的功能;如果支持BLE,但是藍牙沒打開,則需要打開藍牙。代碼示例如下:

//是否支持藍牙模塊
@TargetApi(18)
public static boolean isSupportBle(Context context) {
    if(context != null && context.getPackageManager().hasSystemFeature("android.hardware.bluetooth_le")) {
        BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth");
        return manager.getAdapter() != null;
    } else {
        return false;
    }
}
//是否開啟藍牙
@TargetApi(18)
public static boolean isBleEnable(Context context) {
    if(!isSupportBle(context)) {
        return false;
    } else {
        BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth");
        return manager.getAdapter().isEnabled();
    }
}
//開啟藍牙
public static void enableBle(Activity act, int requestCode) {
    Intent mIntent = new Intent("android.bluetooth.adapter.action.REQUEST_ENABLE");
    act.startActivityForResult(mIntent, requestCode);
}
//藍牙開啟過程
if(isSupportBle(mContext)){
    //支持藍牙模塊
    if(!isBleEnable(mContext)){
        //沒開啟藍牙則開啟
        enableBle(mSelfActivity, 1);
    }
} else{
    //不支持藍牙模塊處理
}
//藍牙開啟回調
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //判斷requestCode是否為開啟藍牙時傳進去的值,再做相應處理
    if(requestCode == 1){
        //藍牙開啟成功後的處理
    }
    super.onActivityResult(requestCode, resultCode, data);
}
2、設備搜索

BluetoothAdapter.startDiscovery在大多數手機上是可以同時發現經典藍牙和Ble的,但是startDiscovery的回調無法返回Ble的廣播,所以無法通過廣播識別設備,且startDiscovery掃描Ble的效率比StartLeScan低很多。所以在實際應用中,還是StartDiscovery和StartLeScan分開掃,前者掃傳統藍牙,後者掃低功耗藍牙。

由於搜索需要盡量減少功耗,因此在實際使用時需要注意:當找到對應的設備後,立即停止掃描;不要循環搜索設備,為每次搜索設置適合的時間限制,避免設備不在可用范圍的時候持續不停掃描,消耗電量。

通過調用BluetoothAdapter的 startLeScan() 搜索BLE設備。調用此方法時需要傳入 BluetoothAdapter.LeScanCallback 參數。具體代碼示例如下:

BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
        //對掃描到的設備進行處理,可以依據BluetoothDevice中的信息、信號強度rssi以及廣播包和響應包組成的scanRecord字節數組進行分析
    }
});
3、設備通信

兩個設備通過BLE通信,首先需要建立GATT連接,這裡我們講的是Android設備作為client端,連接GATT Server。連接GATT Server,需要調用BluetoothDevice的connectGatt()方法,此函數帶三個參數:Context、autoConnect(boolean)和 BluetoothGattCallback 對象。調用後返回BluetoothGatt對象,它是GATT profile的封裝,通過這個對象,我們就能進行GATT Client端的相關操作。如斷開連接bluetoothGatt.disconnect(),發現服務bluetoothGatt.discoverServices()等等。示例代碼如下:

BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback(){
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicRead(gatt, characteristic, status);
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
    }

    @Override
    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorRead(gatt, descriptor, status);
    }

    @Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorWrite(gatt, descriptor, status);
    }

    @Override
    public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
        super.onReliableWriteCompleted(gatt, status);
    }

    @Override
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        super.onReadRemoteRssi(gatt, rssi, status);
    }

    @Override
    public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
        super.onMtuChanged(gatt, mtu, status);
    }
};
BluetoothGatt bluetoothGatt = bluetoothDevice.connectGatt(this, false, bluetoothGattCallback);

//以下為獲得Gatt後的相關操作對應的響應方法
//notification to onCharacteristicChanged;
bluetoothGatt.setCharacteristicNotification(characteristic, true);

//readCharacteristic to onCharacteristicRead;
bluetoothGatt.readCharacteristic(characteristic);

//writeCharacteristic to onCharacteristicWrite;
bluetoothGatt.wirteCharacteristic(mCurrentcharacteristic);

//connect and disconnect to onConnectionStateChange;
bluetoothGatt.connect();
bluetoothGatt.disconnect();

//readDescriptor to onDescriptorRead;
bluetoothGatt.readDescriptor(descriptor);

//writeDescriptor to onDescriptorWrite;
bluetoothGatt.writeDescriptor(descriptor);

//readRemoteRssi to onReadRemoteRssi;
bluetoothGatt.readRemoteRssi();

//executeReliableWrite to onReliableWriteCompleted;
bluetoothGatt.executeReliableWrite();

//discoverServices to onServicesDiscovered;
bluetoothGatt.discoverServices();

四、數據解析

BLE中有兩種角色Central和Peripheral,也就是中心設備和外圍設備,中心設備可以主動連接外圍設備,外圍設備發送廣播或者被中心設備連接,外圍通過廣播被中心設備發現,廣播中帶有外圍設備自身的相關信息。

數據包有兩種:廣播包(Advertising Data)和響應包(Scan Response),其中廣播包是每個設備必須廣播的,而響應包是可選的。數據包的格式如下圖所示(圖片來自官方 Spec):
\
每個包都是 31 字節,數據包中分為有效數據(significant)和無效數據(non-significant)兩部分。

有效數據部分:包含若干個廣播數據單元,稱為AD Structure。如圖中所示,AD Structure的組成是:第一個字節是長度值Len,表示接下來的Len個字節是數據部分。數據部分的第一個字節表示數據的類型AD Type,剩下的Len - 1個字節是真正的數據AD data。其中AD type非常關鍵,決定了AD Data的數據代表的是什麼和怎麼解析,這個在後面會詳細講;<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPs7e0KfK/b7dsr+31qO60vLOqrnjsqWw/LXEs6S2yLHY0OvKxzMx19a92qOsyOe5+9PQ0KfK/b7dsr+31rK7tb0zMdfWvdqjrMqjz8K1xL7N08MwsrnG66Os1eKyv7fWtcTK/b7dysfO3tCntcSjrL3izva1xMqxuvKjrNaxvdO69sLUvLS/yaGjPC9wPg0KPHA+sum/tE5vcmRpY7XEU0RL1tC1xLao0uWjrEFEIHR5cGW1xLao0uXU2rPM0PK1xCZsZHF1bztibGVfZ2FwLmgmcmRxdW87zbfOxLz+1tCho7ao0uXI58/Co7o8L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;"> #define BLE_GAP_AD_TYPE_FLAGS 0x01 //< Flags for discoverability. #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 //< Partial list of 16 bit service UUIDs. #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 //< Complete list of 16 bit service UUIDs. #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 //< Partial list of 32 bit service UUIDs. #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 //< Complete list of 32 bit service UUIDs. #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 //< Partial list of 128 bit service UUIDs. #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 //< Complete list of 128 bit service UUIDs. #define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 //< Short local device name. #define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 //< Complete local device name. #define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A //< Transmit power level. #define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D //< Class of device. #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E //< Simple Pairing Hash C. #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F //< Simple Pairing Randomizer R. #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 //< Security Manager TK Value. #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 //< Security Manager Out Of Band Flags. #define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 //< Slave Connection Interval Range. #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 //< List of 16-bit Service Solicitation UUIDs. #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 //< List of 128-bit Service Solicitation UUIDs. #define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 //< Service Data - 16-bit UUID. #define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 //< Public Target Address. #define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 //< Random Target Address. #define BLE_GAP_AD_TYPE_APPEARANCE 0x19 //< Appearance. #define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A //< Advertising Interval. #define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B //< LE Bluetooth Device Address. #define BLE_GAP_AD_TYPE_LE_ROLE 0x1C //< LE Role. #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D //< Simple Pairing Hash C-256. #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E //< Simple Pairing Randomizer R-256. #define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 //< Service Data - 32-bit UUID. #define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 //< Service Data - 128-bit UUID. #define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D //< 3D Information Data. #define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF //< Manufacturer Specific Data. 所有的 AD Type 的定義在文檔Core Specification Supplement中。根據上面頭文件中的定義,AD Type包括如下類型:

1、TYPE = 0x01:標識設備LE物理連接的功能,占一個字節,各bit為1時定義如下:

bit 0: LE有限發現模式
bit 1: LE普通發現模式
bit 2: 不支持BR/EDR
bit 3: 對Same Device Capable(Controller)同時支持BLE和BR/EDR
bit 4: 對Same Device Capable(Host)同時支持BLE和BR/EDR
bit 5..7: 預留

2、TYPE = 0x02:非完整的16 bit UUID列表
3、TYPE = 0x03:完整的16 bit UUID列表
4、TYPE = 0x04:非完整的32 bit UUID列表
5、TYPE = 0x05:完整的32 bit UUID列表
6、TYPE = 0x06:非完整的128 bit UUID列表
7、TYPE = 0x07:完整的128 bit UUID列表
8、TYPE = 0x08:設備簡稱
9、TYPE = 0x09:設備全名
10、TYPE = 0x0A:表示設備發送廣播包的信號強度
11、TYPE = 0x0D:設備類別
12、TYPE = 0x0E:設備配對的Hash值
13、TYPE = 0x0F:設備配對的隨機值
14、TYPE = 0x10:TK安全管理(Security Manager TK Value)
15、TYPE = 0x11:帶外安全管理(Security Manager Out of Band),各bit定義如下:

bit 0: OOB Flag,0-表示沒有OOB數據,1-表示有
bit 1: 支持LE
bit 2: 對Same Device Capable(Host)同時支持BLE和BR/EDR
bit 3: 地址類型,0-表示公開地址,1-表示隨機地址

16、TYPE = 0x12:外設(Slave)連接間隔范圍,數據中定義了Slave最大和最小連接間隔,數據包含4個字節:前兩字節定義最小連接間隔,取值范圍:0x0006 ~ 0x0C80,而0xFFFF表示未定義;後兩字節,定義最大連接間隔,取值范圍同上,不過需要保證最大連接間隔大於或者等於最小連接間隔。
17、TYPE = 0x14:服務搜尋16 bit UUID列表
18、TYPE = 0x15:服務搜尋128 bit UUID列表
19、TYPE = 0x16:16 bit UUID Service,前兩個字節是UUID,後面是Service的數據
20、TYPE = 0x17:公開目標地址,表示希望這個廣播包被指定的目標設備處理,此設備綁定了公開地址
21、TYPE = 0x18:隨機目標地址,表示希望這個廣播包被指定的目標設備處理,此設備綁定了隨機地址
22、TYPE = 0x19:表示設備的外觀
23、TYPE = 0x1A:廣播區間
24、TYPE = 0x1B:LE設備地址
25、TYPE = 0x1C:LE設備角色
26、TYPE = 0x1D:256位設備配對的Hash值
27、TYPE = 0x1E:256位設備配對的隨機值
28、TYPE = 0x20:32 bit UUID Service,前4個字節是UUID,後面是Service的數據
29、TYPE = 0x21:128 bit UUID Service,前16個字節是UUID,後面是Service的數據
30、TYPE = 0x3D:3D信息數據
31、TYPE = 0xFF:廠商自定義數據,廠商自定義的數據中,前兩個字節表示廠商ID,剩下的是廠商自己按照需求添加,裡面的數據內容自己定義。

根據如下數據包,舉例說明解析的思路
搜索設備獲取的數據包如下:
02 01 06 14 FF 11 22 00 00 00 01 00 1F 09 01 00 00 00 CE DD 5E 5A 5D 23 06 08 48 45 54 2D 35 09 03 E7 FE 12 FF 0F 18 0A 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

根據解析規則,可分成如下部分:
1、廣播數據

02 01 06 14 FF 11 22 00 00 00 01 00 1F 09 01 00 00 00 CE DD 5E 5A 5D 23 06 08 48 45 54 2D 35 

2、響應數據

09 03 E7 FE 12 FF 0F 18 0A 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

3、有效數據

02 01 06 14 FF 11 22 00 00 00 01 00 1F 09 01 00 00 00 CE DD 5E 5A 5D 23 06 08 48 45 54 2D 35 09 03 E7 FE 12 FF 0F 18 0A 18

4、無效數據

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

其中的有效數據又可分為如下幾個數據單元:
02 01 06
14 FF 11 22 00 00 00 01 00 1F 09 01 00 00 00 CE DD 5E 5A 5D 23
06 08 48 45 54 2D 35
09 03 E7 FE 12 FF 0F 18 0A 18
根據上面定義的AD Type分別解析如下:
第一組數據告訴我們該設備屬於LE普通發現模式,不支持BR/EDR;
第二組數據告訴我們該數據為廠商自定義數據,一般是必須解析的,可根據協議規則進行解析獲取對應的所需信息;
第三組數據告訴我們該設備的簡稱為HET-5,其中對應的字符是查找ASSIC表得出的;
第四組數據告訴我們UUID為E7FE-12FF-0F18-0A18(此處有疑,類型03表示的是16位的UUID,對應的兩個字節,而此處有8個字節,估計是設備燒錄時把字節位數理解為了字符位數導致的問題).

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved