Android開發藍牙Bluetooth——《進階篇》

在深入瞭解Android藍牙Bluetooth——《基礎篇》一篇中我們對藍牙的各個版本的有瞭一個認識,藍牙版本的歷程及其優劣式介紹。那麼接下來咱們就深入一點繼續開車進入BLE的進及篇章。

BLE分為三部分:

Service

Characteristic

Descriptor

這三部分都用UUID作為唯一標識符。UUID為這種格式:0000ffe1-0000-1000-8000-00805f9b34fb。比如有3個Service,那麼就有三個不同的UUID與Service對應。這些UUID都寫在硬件裡,我們通過BLE提供的API可以讀取到。

一個BLE終端可以包含多個Service, 一個Service可以包含多個Characteristic,一個Characteristic包含一個value和多個Descriptor,一個Descriptor包含一個Value。Characteristic是比較重要的,是手機與BLE終端交換數據的關鍵,讀取設置數據等操作都是操作Characteristic的相關屬性。

錨點
API相關介紹

1.先介紹一下關於藍牙4.0中的一些名詞吧:

(1)GATT(Gneric Attibute Profile)

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

(2)ATT(Attribute Protocal) GATT是基於ATT Potocal的ATT針對BLE設備專門做的具體就是傳輸過程中使用盡量少的數據,每個屬性都有個唯一的UUID,屬性chartcteristics and Service的形式傳輸。

(3)Service是Characteristic的集合。

(4).Characteristic 特征類型。

比如。有個藍牙ble的血壓計。他可能包括多個Servvice,每個Service有包括多個Characteristic

註意:藍牙ble隻能支持Android 4.3以上的系統 SDK>=18

2.以下是開發的步驟:

2.1首先獲取BluetoothManager

2.2獲取BluetoothAdapter

2.3創建BluetoothAdapter.LeScanCallback

2.4.開始搜索設備。

2.5.BluetoothDevice 描述瞭一個藍牙設備 提供瞭getAddress()設備Mac地址,getName()設備的名稱。

2.6開始連接設備

2.7連接到設備之後獲取設備的服務(Service)和服務對應的Characteristic。

2.8獲取到特征之後,找到服務中可以向下位機寫指令的特征,向該特征寫入指令。

2.9寫入成功之後,開始讀取設備返回來的數據。

2.10、斷開連接

2.11、數據的轉換方法

錨點
大概整體就是如上的步驟。但是也是要具體根據廠傢的協議來實現通信的過程。

那麼具體要怎麼使用呢?我們據需開車往下走。

錨點
一.添加權限

? 和經典藍牙一樣,應用使用藍牙,需要聲明BLUETOOTH權限,如果需要掃描設備或者操作藍牙設置,則還需要BLUETOOTH_ADMIN權限:

12

除瞭藍牙權限外,如果需要BLE feature則還需要聲明uses-feature:

按時required為true時,則應用隻能在支持BLE的Android設備上安裝運行;required為false時,Android設備均可正常安裝運行,需要在代碼運行時判斷設備是否支持BLE feature:

// Use this check to determine whether BLE is supported on the device. Then

// you can selectively disable BLE-related features.

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {

Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();

finish();

}

錨點
第一步:開啟藍牙:

1.首先獲取有BluetoothAdapter兩種方式:

private BluetoothManager bluetoothManager;

bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

mBluetoothAdapter = bluetoothManager.getAdapter();

或者是:

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

兩行方式都是可以的。

註:這裡通過getSystemService獲取BluetoothManager,再通過BluetoothManager獲取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。

– 2.判斷手機設備是否有藍牙模塊

// 檢查設備上是否支持藍牙

if (mBluetoothAdapter == null) {

showToast("沒有發現藍牙模塊");

return;

}

3.開啟藍牙設備

開啟藍牙設備有兩種方式:

第一種直接簡單暴力不給用戶進行提示:

if (!mBluetoothAdapter.isEnabled()) {

mBluetoothAdapter.enable();

}

第二種直優雅的踐行開啟並且有彈框進行提示,隱式啟動Intent:

if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {

Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

}

4.掃描藍牙設備

我這裡是把掃描到的BLE地址存放到List集合中去。這裡我們可以寫一個方法進行封裝一下。

/***********

* 掃描設備

********/

private void scanLeDevice(final boolean enable) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {

if (enable) {

devices.clear();//清空集合

// Stops scanning after a pre-defined scan period.

mHandler.postDelayed(new Runnable() {

@Override

public void run() {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {

mBluetoothAdapter.stopLeScan(mLeScanCallback);

}

}

}, INTERVAL_TIME);

mBluetoothAdapter.startLeScan(mLeScanCallback);

} else {

try {

mBluetoothAdapter.stopLeScan(mLeScanCallback);

} catch (Exception e) {

}

}

}

}

在這個掃描方法中,我們在AndroidStudio或者是Eclipse中會看到startLeScan方法會有橫線,表明這個方式顯示過期的方法,那麼

如果你隻需要搜索指定UUID的外設,你可以調用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。

其中UUID數組指定你的應用程序所支持的GATT Services的UUID。

那麼LeScanCallback的初始化代碼如下:

private void initCallBack(){

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {

mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

@Override

public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {

runOnUiThread(new Runnable() {

@Override

public void run() {

if (device != null) {

if (!TextUtils.isEmpty(device.getName())) {

// devices.add(device);

String name = device.getName();

if (name.contains(BluetoothDeviceAttr.OYGEN_DEVICE_NAME)) {

if (!devices.contains(device)) {

devices.add(device);

}

}

}

}

}

});

}

};

} else {

getToast("設備藍牙版本過低");

return;

}

}

那麼如果在設備多的情況下我們講搜出很多的設備。我們可以選擇我們所需要的地址進行鏈接。但是這類要註意的是:搜索時,你隻能搜索傳統藍牙設備或者BLE設備,兩者完全獨立,不可同時被搜索.

5.進行鏈接設備

final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

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

// parameter to false.

mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

這裡調用的是device的connectGatt方法

/**

* Connect to GATT Server hosted by this device. Caller acts as GATT client.

* The callback is used to deliver results to Caller, such as connection status as well

* as any further GATT client operations.

* The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct

* GATT client operations.

* @param callback GATT callback handler that will receive asynchronous callbacks.

* @param autoConnect Whether to directly connect to the remote device (false)

* or to automatically connect as soon as the remote

* device becomes available (true).

* @throws IllegalArgumentException if callback is null

*/

public BluetoothGatt connectGatt(Context context, boolean autoConnect,

BluetoothGattCallback callback) {

return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));

}

?api中闡述的是第一個參數是上下文對象Context,第二個參數是是否自動連接,第三個是藍牙的GattCallback回調。

private BluetoothGattCallback GattCallback = new BluetoothGattCallback() {

// 這裡有9個要實現的方法,看情況要實現那些,用到那些就實現那些

//當連接狀態發生改變的時候

@Override

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){

};

//回調響應特征寫操作的結果。

@Override

public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){

};

//回調響應特征讀操作的結果。

@Override

public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

}

//當服務被發現的時候回調的結果

@Override

public void onServicesDiscovered(BluetoothGatt gatt, int status) {

}

當連接能被被讀的操作

@Override

public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {

super.onDescriptorRead(gatt, descriptor, status);

}

……

};

?連接的過程我們一個通過service來進行連接,也可以在activity中進行操作。

好,到此為止,一個BLE藍牙連接設備的整個流程我們已經清楚完畢。

錨點
Android4.x的藍牙不太成熟性

?但是在實際操作過程中難免會出現一些比較坑人的問題。比如我用一個地址進行藍牙設備連接,偶爾會出現藍牙連接不上或者是說連接上設備後不返回數據等問題。那麼此時我們可能會重啟一下藍牙或手機就立馬有成功瞭。此時我們千萬不能蒙蔽,也不要懷疑自己的人生。這是因為Android4.x的藍牙還是不太成熟。目前可以來說是個測試階段。

* 手機可能會搜索不到藍牙設備

* 有時候會在廣播中接收不到數據

* 出現異常需要重新啟動手機或者是重啟才能恢復正常

這個時候我們怎麼辦呢?

此時不要抱怨什麼,難到我們作為Android程序員就註定如此的苦逼嗎?

答案是否定的。

如何去優化呢?那麼我們就應該從UI界面,用戶體驗上進行操作來實現

* 做一個定時器,如果在在確定藍牙設備一打開並且存在的情況系,可以在手機搜索5s內沒有搜索到藍牙設備時重啟藍牙,並且在廣播中接收到藍牙開啟後再次搜索

* 可以在UI上進行對用戶進行相對應的提示

– 當藍牙為啟動時,提示用戶去開啟器藍牙

– 當藍牙開啟後,在處在開啟狀態後,提示用戶藍牙正在開啟…

– 藍牙已開啟,設備並沒有連接上,提示用戶去進行連接

– 設備正在連接上手機,提示用戶,正在連接,請等待…

– 藍牙設備連接上手機,正在讀取,提示數據正在讀取中…

我們不能子在Android系統上來操作什麼,我們在體驗上做到瞭我們能做的就可以的。

錨點
手機藍牙連接BLE設備要求

手機Android 4.3以上的系統 SDK>=18

藍牙版本>=4.0

學到這裡,關於AndroidBLE藍牙連接我們已經基本上實現瞭藍牙的搜索,連接,讀取等。

大傢項目中如果經常涉及到硬件比如手環,溫度計,汗液儀,心電圖,血壓計等這些ble的藍牙設備,就一定會用到藍相關方面的知識。這裡筆者先給大傢提前踩一下坑,進行瞭總結,為後面的小夥伴在研究藍牙方面盡量的少踩一些坑。

You May Also Like