Android BLE低功耗蓝牙开发
啦啦啦在上一個項目中有用到BLE低功耗藍牙開發(fā),當時baidu google了很多資料,但大多數(shù)都是千篇一律,英文文檔我這種渣渣又看不懂。。。總之剛開始查的很痛苦。所以要把自己的踩坑之路寫下來記錄下,,,或許能幫到后來人呢?
概念
這是低功耗藍牙的官方文檔,英文好的同學可以直接看看這個:https://developer.android.google.cn/guide/topics/connectivity/bluetooth-le.html
低功耗藍牙是android4.3(API level18)之后才支持的.
一個低功耗藍牙終端包含多個Service,而Service中又包含多個Characteristic,一個Characteristic又包含一個Value和多個Descriptor.Characteristic是手機和BLE終端交換數(shù)據(jù)的關(guān)鍵.
這三部分都是通過UUID來獲取,UUID是他們的唯一標識.
鏈接
掃描的部分我們就不多說了,參考官方Demo寫的很詳細.主要說一說鏈接及發(fā)送消息等.
參考官方Demo,所有的鏈接等操作都是放在一個service中進行的,通過在service中發(fā)送廣播來通知activity來處理相關(guān)的數(shù)據(jù).很簡單呦!我們先來看看service中都做了什么~
這是初始化藍牙適配器的方法,在開啟服務(wù)時調(diào)用.
/*** Initializes a reference to the local Bluetooth adapter.* 初始化一個藍牙適配器 里面會判斷系統(tǒng)版本,如果低于18則返回false(低于18不支持低功耗藍牙)** @return Return true if the initialization is successful.* 返回true表示初始化成功*/public boolean initialize() {// For API level 18 and above, get a reference to BluetoothAdapter through// BluetoothManager.if (mBluetoothManager == null) {mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);if (mBluetoothManager == null) {//無法初始化藍牙管理器Log.e(TAG, "Unable to initialize BluetoothManager.");return false;}}mBluetoothAdapter = mBluetoothManager.getAdapter();if (mBluetoothAdapter == null) {//無法獲取藍牙適配器Log.e(TAG, "Unable to obtain a BluetoothAdapter.");return false;}return true;}這是連接藍牙設(shè)備的方法,address就是藍牙設(shè)備的MAC地址,如果是掃描的則可以通過device.getAddress()來獲取到這個address.
/*** Connects to the GATT server hosted on the Bluetooth LE device.** 連接成功返回true 異步返回** @param address The device address of the destination device.** @return Return true if the connection is initiated successfully. The connection result* is reported asynchronously through the* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}* callback.*/public boolean connect(final String address) {if (mBluetoothAdapter == null || address == null) {//還沒有初始化或者指定地址Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");return false;}// Previously connected device. Try to reconnect. 以前連接的設(shè)備 嘗試重新連接if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)&& mBluetoothGatt != null) {Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");if (mBluetoothGatt.connect()) {mConnectionState = STATE_CONNECTING;return true;} else {return false;}}//根據(jù)mac地址獲取設(shè)備final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);//如果設(shè)備為null則表示未獲取到設(shè)備if (device == null) {Log.w(TAG, "Device not found. Unable to connect.");return false;}// We want to directly connect to the device, so we are setting the autoConnect//我們要直接連接到設(shè)備,所以我們設(shè)置自動連接// parameter to false.mBluetoothGatt = device.connectGatt(this, false, mGattCallback);//試圖創(chuàng)建一個新的連接Log.d(TAG, "Trying to create a new connection.");mBluetoothDeviceAddress = address;mConnectionState = STATE_CONNECTING;return true;}在調(diào)用connectGatt(context,autoConnect,callback)方法進行連接時,我們需要傳入一個context,一個boolean值,該參數(shù)表示以后是否需要自動連接到該設(shè)備,最后一個是藍牙連接的監(jiān)聽回調(diào)對象BluetoothGattCallback,我們需要new 出來這個對象,重寫他的幾個方法,如下:
藍牙連接狀態(tài)改變的回調(diào):在連接成功之后需要調(diào)用discoverServices方法來找服務(wù),只有找到了服務(wù)才算是真正的連接成功.
@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {super.onConnectionStateChange(gatt, status, newState);if (newState == BluetoothProfile.STATE_CONNECTED) {mConnectionState = STATE_CONNECTING;//開始找服務(wù),只有找到服務(wù)才算是真正的連接上了mBluetoothGatt.discoverServices();} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//發(fā)送廣播通知activity連接已斷開broadcastUpdate(ACTION_GATT_DISCONNECTED);mConnectionState = STATE_DISCONNECTED;} else {//發(fā)送廣播通知activity連接已斷開broadcastUpdate(ACTION_GATT_DISCONNECTED);mConnectionState = STATE_DISCONNECTED;}}發(fā)現(xiàn)服務(wù)的回調(diào):
在找到服務(wù)之后就是真正的連接成功了,我在這里設(shè)置了對返回數(shù)據(jù)的監(jiān)聽,后面具體說
Characteristic寫操作的結(jié)果回調(diào):
這個監(jiān)聽在分包發(fā)送的時候需要用到,在里面判斷的發(fā)送結(jié)果是否成功,成功的話則發(fā)送下一條數(shù)據(jù),這樣可以保證分包發(fā)送的順序不會錯誤.
Characteristic狀態(tài)改變的回調(diào):
這個方法挺重要的,藍牙廣播(是指藍牙設(shè)備本身發(fā)出的數(shù)據(jù))出來的數(shù)據(jù)在這里獲取,發(fā)送指令后藍牙的回應(yīng)也是在這里獲取.當然要走這個回調(diào)必須先設(shè)置相關(guān)的characteristic的監(jiān)聽.
以上就是BluetoothGattCallback對象中要重寫的幾個方法,下面我們說一說characteristic的監(jiān)聽設(shè)置
/*** 設(shè)置特征監(jiān)聽*/public void enableTXNotification() {BluetoothGattService RxService = mBluetoothGatt.getService(SERVICE_UUID);if (RxService == null) {L.e("未找到藍牙中的對應(yīng)服務(wù)");return;}BluetoothGattCharacteristic RxChar = RxService.getCharacteristic(RX_UUID);if (RxChar == null) {L.e("未找到藍牙中的對應(yīng)特征");return;}//設(shè)置true為啟用通知,false反之mBluetoothGatt.setCharacteristicNotification(RxChar, true);//下面為開啟藍牙notify功能,向CCCD中寫入值1BluetoothGattDescriptor descriptor = RxChar.getDescriptor(CCCD);descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mBluetoothGatt.writeDescriptor(descriptor);List<BluetoothGattDescriptor> descriptors = RxChar.getDescriptors();for (BluetoothGattDescriptor dp : descriptors) {dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mBluetoothGatt.writeDescriptor(dp);}} 先通過Service的UUID找到對應(yīng)的Service對象,再通過我們想要設(shè)置監(jiān)聽的Characteristic的UUID找到相應(yīng)的Characteristic對象,UUID都是藍牙設(shè)備廠商在文檔中提供的.找到相應(yīng)的特征后調(diào)用setCharacteristicNotification方法開啟監(jiān)聽,就可以在該特征狀態(tài)發(fā)生改變后走到onCharacteristicChanged方法中. 而藍牙的notify功能需要向CCCD中寫入值1才能開啟,CCCD值為:`public static final UUID CCCD = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");`往Characteristic中寫入數(shù)據(jù):
我們知道低功耗藍牙的特點就是快速連接,超低功耗保持連接和傳輸數(shù)據(jù),其缺點是傳輸速率很低,每次最多向Characteristic中寫入20字節(jié)的內(nèi)容.因此當我們需要寫入的數(shù)據(jù)過大時就要使用分包發(fā)送.
先來看看如何往Characteristic中寫入數(shù)據(jù)吧
還是要先獲取到Characteristic對象,然后調(diào)用setValue方法設(shè)置我們需要寫入的數(shù)據(jù),該方法接受byte[]和String,我們一般都是寫入byte[].基本都要求是十六進制byte[],很多同學會在這里糾結(jié)十六進制的轉(zhuǎn)換、數(shù)組中有些數(shù)據(jù)超出byte取值范圍了等問題,這些你其實完全不用考慮…不用非要寫成0x00這樣的形式,因為對于計算機來說都是一樣的,超出byte取值范圍也不用擔心,沒有什么影響的.不過如果可以的話最好還是能和你們的硬件工程師溝通一下.
分包發(fā)送的話還是需要與硬件工程師溝通具體的分包方法,寫入數(shù)據(jù)是延時多少毫秒,然后在上面onCharacteristicWrite方法中判斷寫入狀態(tài),成功的話則寫入下一條數(shù)據(jù),這樣來保證分包數(shù)據(jù)的順序不會錯亂.
總結(jié)
以上是生活随笔為你收集整理的Android BLE低功耗蓝牙开发的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于Springboot的新冠疫情可视化
- 下一篇: HTML菜单栏点击后变色,菜单怎么实现点