安卓蓝牙开发(1)BLE蓝牙基础知识和一般开发流程
一、BLE(Bluetooth Low Energy)低功耗藍牙基本知識
Android 4.3(API級別18)引入了以低功耗藍牙(BLE)為中心角色的內置平臺支持,并提供應用程序可用于發現設備,查詢服務和傳輸信息的API
常見用例包括以下內容:
- 在附近的設備之間傳輸少量的數據
- 與Google Beacons等接近傳感器進行互動,為用戶提供基于當前位置的定制體驗。
傳統藍牙可以用于數據量比較大的傳輸,如語音,音樂,較高數據量傳輸等,但是比較耗電,低功耗藍牙這樣應用于實時性要求比較高,功耗比較低,但是數據速率比較低的產品,如遙控類的,如鼠標,鍵盤,遙控鼠標(Air Mouse),傳感設備的數據發送,如心跳帶,血壓計,溫度傳感器等。
1. GATT 和 ATT
GATT協議
(1)通用屬性配置文件 Generic Attribute Profile(GATT):GATT配置文件是通過BLE鏈接發送和接收被稱為“屬性”的短小數據的通用規范。目前所有的低能耗應用程序都基于GATT。
- 藍牙SIG為低能耗設備定義了許多配置文件。 配置文件是設備如何在特定應用程序中工作的規范。 請注意,設備可以實現多個配置文件。 例如,一個設備可以包含一個心率監測器和一個電池電量檢測器。
-
可以把他看成xml來理解:
- 每個GATT由完成不同功能的Service組成;
- 每個Service由不同的Characteristic組成;
-
每個Characteristic由一個value和一個或者多個Descriptor組成;
Service、Characteristic相當于標簽(Service相當于他的類別,Characteristic相當于它的名字),而value才真正的包含數據,Descriptor是對這個value進行的說明和描述,當然我們可以從不同角度來描述和說明,因此可以有多個Descriptor.
1. Service? 的UUID: 設備中每一個不同的 Service 都有一個 128 bit 的 UUID 作為這個 Service 的獨立標志。藍牙核心規范制定了兩種不同的UUID,一種是基本的UUID,一種是代替基本UUID的16位UUID。所有的藍牙技術聯盟定義UUID共用了一個基本的UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB
2.?每一個 Characteristic 也有一個唯一的 UUID 作為標識符
舉一個簡單的例子進行說明:
常見的小米手環是一個BLE設備,(假設)它包含三個Service,分別是提供設備信息的Service、提供步數的Service、檢測心率的Service;
設備信息的service中包含的characteristic包括廠商信息、硬件信息、版本信息等;
心率Service則包括心率characteristic等,心率characteristic中的value則真正的包含心率的數據,而descriptor則是對該value的描述說明,比如value的單位啊,描述啊,權限啊等。
?
(2)屬性協議 Attribute Protocol(ATT):GATT建立在屬性協議(ATT)之上。 這也被稱為GATT / ATT。 ATT經過優化,可在BLE設備上運行。 為此,它使用盡可能少的字節。 每個屬性由一個通用唯一標識符(UUID)唯一標識,該標識符是用于唯一標識信息的字符串ID的標準化128位格式。 ATT傳輸的屬性被格式化為特征和服務。
- 特性 Characteristic: 特性包含描述特性值的單個值和0-n個描述符。一個特征可以被認為是一個類,類似于一個階級,是最小的數據邏輯單元。
- 描述符 Descriptor: 描述符是描述特征值的定義屬性。 例如,一個描述符可以指定一個可讀的描述,一個特征值的可接受范圍,或者一個特征值特有的度量單位。value、descriptor中存儲數據的解析由Server的工程師決定,并無規范,雙發按照約定開發。
- 服務 Service: 服務是一個特征的集合。 例如,您可以擁有一個名為“心率監測器”的服務,其中包含“心率測量”等特性。 您可以在bluetooth.org上找到現有基于GATT的配置文件和服務的列表。Service/Characteristic均有一個唯一的UUID標識,UUID既有16位的也有128位的,我們需要了解的是16位的UUID是經過藍牙組織認證的,是需要購買的,當然也有一些通用的16位UUID。例如Heart Rate服務的UUID就是0X180D,代碼中表示為0X00001800-0000-1000-8000-00805f9b34fb,其他位為固定的。而128位的UUID則可以自定義。
在 Android 開發中,建立藍牙連接后,我們說的通過藍牙發送數據給外圍設備就是往這些 Characteristic 中的 Value 字段寫入數據;外圍設備發送數據給手機就是監聽這些 Charateristic 中的 Value 字段有沒有變化,如果發生了變化,手機的 BLE API 就會收到一個監聽的回調。?
2.?角色(Roles)和責任(Responsibilities)
Android設備與BLE設備交互時適用的角色和職責:
- 中央(Central)?與?周邊(Peripheral)。這適用于BLE連接本身。處于中心角色的設備掃描,尋找廣告,并且在外圍角色中的設備進行廣告。
- GATT服務器?與?GATT客戶端。這決定了兩臺設備在建立連接后如何相互通話。
?
為了理解這個區別,假設你有一個Android手機和一個BLE設備的活動追蹤器。 手機支持中心角色; 活動跟蹤器支持外設角色(建立一個BLE連接,你需要每兩個事物中只有一個支持外圍設備的人不能彼此交談,也不能只支持兩個事物)。
一旦手機和活動追蹤器建立了連接,他們就開始將GATT元數據轉移到另一個。根據他們傳輸的數據的種類,其中一個或另一個可能充當服務器。例如,如果活動跟蹤器想要將傳感器數據報告給電話,則活動跟蹤器可以充當服務器。如果活動跟蹤器想要從手機接收更新,那么手機作為服務器可能是有意義的。
在本文檔中使用的示例中,Android應用程序(在Android設備上運行)是GATT客戶端。該應用程序從GATT服務器獲取數據,GATT服務器是支持心率檔案的BLE心率監測器。但你也可以設計你的Android應用程序來扮演GATT服務器的角色。
二、安卓BLE開發流程
首先要判斷當前的Android設備是否支持藍牙,如果支持則再判斷當前藍牙是否處于開啟狀態,如果未開啟則發送廣播通知系統開啟藍牙,藍牙開啟后開始搜索周圍的藍牙設備,注意搜索一定要設置超時處理,搜索到指定藍牙設備后停止搜索任務。
此時可以以列表的形式供用戶選擇需要連接的設備,或者內部自動連接特定的設備,連接成功后,搜索此藍牙設備提供的服務(特性、描述符的集合),搜索完成后設置一些對應的參數,即可與藍牙設備進行通信了
1. 相關的API
我們在開發過程中需要用到的一些API:
- 1.BluetoothAdapter
本地藍牙適配器,用于一些藍牙的基本操作,比如判斷藍牙是否開啟、搜索藍牙設備等。
- 2.BluetoothDevice
藍牙設備對象,包含一些藍牙設備的屬性,比如設備名稱、mac地址等。
- 3.BluetoothProfile
一個通用的藍牙規范,設備之間按照這個規范來收發數據。
- 4.BluetoothGatt
藍牙通用屬性協議,定義了BLE通訊的基本規則,是BluetoothProfile的實現類,Gatt是Generic Attribute Profile的縮寫,用于連接設備、搜索服務等操作。
- 5.BluetoothGattCallback
藍牙設備連接成功后,用于回調一些操作的結果,必須連接成功后才會回調。
- 6.BluetoothGattService
藍牙設備提供的服務,是藍牙設備特征的集合。
- 7.BluetoothGattCharacteristic
藍牙設備特征,是構建GATT服務的基本數據單元。
- 8.BluetoothGattDescriptor
藍牙設備特征描述符,是對特征的額外描述。
我們可以將上述幾個類的關系比喻為:BluetoothDevice為學校,BluetoothGatt為學校到達某一個班級的通道,BluetoothCattService為學校的某一個班級,BluetoothCattCharacteristic為班級中的某一個學生。那么藍牙連接通信的過程就是這樣,BluetoothAdapter先找到學校(就是連接目的設備),再通過通道找到目標班級,最后從班級中找到目標學生,這個學生就是我們設備之間通信的中介,很重要,學校有唯一的MAC地址,班級有唯一的serviceUUID,學生有唯一的charactersticUUID(相當于學號),所以就是在一所學校找一個學生的問題。
2. 操作流程
(1)打開所需要的權限
在 Android 6.0 及以上,還需要打開位置權限。如果應用沒有位置權限,藍牙掃描功能不可用,即掃描不到BLE設備,但其它藍牙操作例如連接藍牙設備和寫入數據不受影響。
<!-- 通用藍牙權限 --> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/><!-- 位置權限 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>(2)獲取 BluetoothAdapter
BluetoothAdapter是任何和所有的藍牙活動所必需的。 BluetoothAdapter代表設備自己的藍牙適配器(藍牙無線電)。整個系統有一個藍牙適配器,您的應用程序可以使用這個對象與它進行交互。下面的代碼展示了如何獲取適配器。請注意,此方法使用getSystemService()返回 BluetoothManager 的實例,然后用于獲取適配器。 Android 4.3(API Level 18)介紹了BluetoothManager:
private BluetoothAdapter mBluetoothAdapter; ... // Initializes Bluetooth adapter. final BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();(3)啟動藍牙
調用isEnabled()來檢查當前是否啟用了藍牙。如果此方法返回false,則藍牙被禁用。
以下片段檢查是否啟用了藍牙。如果不是,該片段會顯示一個錯誤,提示用戶轉到設置以啟用藍牙:
// Ensures Bluetooth is available on the device and it is enabled. If not, // displays a dialog requesting user permission to enable Bluetooth. if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }注意:
傳遞給 startActivityForResult(android.content.Intent,int)的REQUEST_ENABLE_BT常量是系統在onActivityResult(int,int,android.content)中返回給您的本地定義的整數(它必須大于0))實現作為requestCode參數。
(4)查找藍牙設備
要查找BLE設備,請使用startLeScan()方法。 此方法將BluetoothAdapter.LeScanCallback作為參數。 您必須實現此BluetoothAdapter.LeScanCallback,因為這是如何返回掃描結果。 由于掃描耗電量大,您應遵守以下準則:
- 一旦找到所需的設備,請停止掃描
- 切勿掃描循環,并在掃描上設置時間限制。以前可用的設備可能已移出范圍,并繼續掃描電池電量。
以下片段顯示了如何啟動和停止掃描:
/*** Activity for scanning and displaying available BLE devices.*/ public class DeviceScanActivity extends ListActivity {private BluetoothAdapter mBluetoothAdapter;private boolean mScanning;private Handler mHandler;// Stops scanning after 10 seconds.private static final long SCAN_PERIOD = 10000;...private void scanLeDevice(final boolean enable) {if (enable) {// Stops scanning after a pre-defined scan period.mHandler.postDelayed(new Runnable() {@Overridepublic void run() {mScanning = false;mBluetoothAdapter.stopLeScan(mLeScanCallback);}}, SCAN_PERIOD);mScanning = true;mBluetoothAdapter.startLeScan(mLeScanCallback);} else {mScanning = false;mBluetoothAdapter.stopLeScan(mLeScanCallback);}...} ... }如果只想掃描特定類型的外設,則改為調用startLeScan(UUID [],BluetoothAdapter.LeScanCallback),提供指定您的應用程序支持的GATT服務的UUID對象數組。
以下是BluetoothAdapter.LeScanCallback的一個實現,它是用于傳遞BLE掃描結果的接口:
private LeDeviceListAdapter mLeDeviceListAdapter; ... // Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback =new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(final BluetoothDevice device, int rssi,byte[] scanRecord) {runOnUiThread(new Runnable() {@Overridepublic void run() {mLeDeviceListAdapter.addDevice(device);mLeDeviceListAdapter.notifyDataSetChanged();}});} };(5)讀取設備BLE信息
一旦你的Android應用程序連接到GATT服務器并發現服務,它就可以在支持的地方讀取和寫入屬性。例如,這個代碼片段遍歷服務器的服務和特性,并在UI中顯示它們:
public class DeviceControlActivity extends Activity {...// (演示)Demonstrates how to (遍歷)iterate through the supported GATT// Services/Characteristics.// In this sample, we (填充)populate the data structure that is bound to the// ExpandableListView on the UI.private void displayGattServices(List<BluetoothGattService> gattServices) {if (gattServices == null) return;String uuid = null;String unknownServiceString = getResources().getString(R.string.unknown_service);String unknownCharaString = getResources().getString(R.string.unknown_characteristic);ArrayList<HashMap<String, String>> gattServiceData =new ArrayList<HashMap<String, String>>();ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData= new ArrayList<ArrayList<HashMap<String, String>>>();mGattCharacteristics =new ArrayList<ArrayList<BluetoothGattCharacteristic>>();// Loops through available GATT Services.for (BluetoothGattService gattService : gattServices) {HashMap<String, String> currentServiceData =new HashMap<String, String>();uuid = gattService.getUuid().toString();currentServiceData.put(LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString));currentServiceData.put(LIST_UUID, uuid);gattServiceData.add(currentServiceData);ArrayList<HashMap<String, String>> gattCharacteristicGroupData =new ArrayList<HashMap<String, String>>();List<BluetoothGattCharacteristic> gattCharacteristics =gattService.getCharacteristics();ArrayList<BluetoothGattCharacteristic> charas =new ArrayList<BluetoothGattCharacteristic>();// Loops through available Characteristics.for (BluetoothGattCharacteristic gattCharacteristic :gattCharacteristics) {charas.add(gattCharacteristic);HashMap<String, String> currentCharaData =new HashMap<String, String>();uuid = gattCharacteristic.getUuid().toString();currentCharaData.put(LIST_NAME, SampleGattAttributes.lookup(uuid,unknownCharaString));currentCharaData.put(LIST_UUID, uuid);gattCharacteristicGroupData.add(currentCharaData);}mGattCharacteristics.add(charas);gattCharacteristicData.add(gattCharacteristicGroupData);}...} ... }(6)接受GATT通知
BLE應用程序在設備上發生特定特征變化時要求收到通知是很常見的。這段代碼展示了如何使用setCharacteristicNotification()方法為特性設置通知
private BluetoothGatt mBluetoothGatt; BluetoothGattCharacteristic characteristic; boolean enabled; ... mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); ... BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor);一旦為特征啟用了通知,如果特性在遠程設備上發生變化,則會觸發onCharacteristicChanged()回調:
@Override // Characteristic notification public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); }(7)關閉藍牙
一旦您的應用程序使用BLE設備,應該調用close(),以便系統可以正確釋放資源:
public void close() {if (mBluetoothGatt == null) {return;}mBluetoothGatt.close();mBluetoothGatt = null; }?
項目推薦:
2000多G的計算機各行業電子資源分享(持續更新)
2020年微信小程序全棧項目之喵喵交友【附課件和源碼】
Spring Boot開發小而美的個人博客【附課件和源碼】
Java微服務實戰296集大型視頻-谷粒商城【附代碼和課件】
Java開發微服務暢購商城實戰【全357集大項目】-附代碼和課件
最全最詳細數據結構與算法視頻-【附課件和源碼】
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的安卓蓝牙开发(1)BLE蓝牙基础知识和一般开发流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTML5的数据存储和数据处理的功能有,
- 下一篇: 粒子群算法组卷_概率表示的二进制粒子群算