Android藍芽那點事——深入瞭解藍芽BlE藍芽 《總結篇》

codeGoogle發表於2017-08-22

在我的上兩篇博文中講解了有關android藍芽的認識以及API的相關的介紹,藍芽BLE的搜尋,連線以及讀取。
沒有了解的童鞋們請參考:

  1. 深入瞭解Android藍芽Bluetooth——《基礎篇》
  1. 深入瞭解Android藍芽Bluetooth——《進階篇》

目前專案中的效果圖:

專案效果圖
專案效果圖

接下來我們就對藍芽BLE4.0進行一下總結。

藍芽API

Android ble 藍芽4.0,也就是說API level >= 18,且支援藍芽4.0的手機才可以使用,如果手機系統版本API level < 18,也是用不了藍芽4.0的哦

  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);複製程式碼
  1. BluetoothAdapter

    一個Android系統只有一個BluetoothAdapter ,通過BluetoothManager 獲取

     BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
     1.8 BluetoothGattCallback複製程式碼

    已經連線上裝置,對裝置的某些操作後返回的結果。這裡必須提醒下,已經連線上裝置後的才可以返回,沒有返回的認真看看有沒有連線上裝置。

     private BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
         // 這裡有9個要實現的方法,看情況要實現那些,用到那些就實現那些
         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){};
         public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){};
     };
     BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
     BluetoothGatt gatt = device.connectGatt(this, false, mGattCallback);複製程式碼
  2. notification對應onCharacteristicChanged

     gatt.setCharacteristicNotification(characteristic, true);複製程式碼
  3. readCharacteristic對應onCharacteristicRead

     gatt.readCharacteristic(characteristic);複製程式碼
  4. writeCharacteristic對應onCharacteristicWrite
    gatt.wirteCharacteristic(mCurrentcharacteristic);複製程式碼
  5. 連線藍芽或者斷開藍芽 對應 onConnectionStateChange

  6. readDescriptor對應onDescriptorRead;

  7. writeDescriptor對應onDescriptorWrite;

    gatt.writeDescriptor(descriptor);複製程式碼
  8. readRemoteRssi對應onReadRemoteRssi
    gatt.readRemoteRssi()複製程式碼
  9. executeReliableWrite對應onReliableWriteCompleted;

  10. discoverServices對應onServicesDiscovered

    gatt.discoverServices()複製程式碼
  11. BluetoothDevice
    掃描後發現可連線的裝置,獲取已經連線的裝置

    二、開啟藍芽許可權

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>複製程式碼

Android ble 藍芽4.0,也就是說API level >= 18,且支援藍芽4.0的手機才可以使用,如果手機系統版本API level < 18,也是用不了藍芽4.0的

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, "裝置不支援藍芽4.0", Toast.LENGTH_SHORT).show();
    finish();
}複製程式碼

或者是

// 檢查當前手機是否支援blue 藍芽,如果不支援退出程式
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            showToast("不支援藍芽4.0通訊");
            return;
        }
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        // 檢查裝置上是否支援藍芽
        if (mBluetoothAdapter == null) {
            showToast("沒有發現藍芽模組");
            return;
        }複製程式碼

三、對藍芽的啟動關閉操作

  • isEnabled()

    如果本地藍芽處在可用狀態(例如手機藍芽開啟)就返回true

  • getState()

    獲得藍芽狀態 一般有BluetoothAdapter.STATE_BLE_ON ,STATE_BLE_TURNING_ON ,STATE_BLE_TURNING_OFF ,STATE_OFF

  • enable()

    開啟藍芽裝置,這種方式不友好,建議使用下面方法

      Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
      startActivityForResult(intent,OPEN_REQUEST_CODE);複製程式碼

    這樣會有個彈窗提示使用者是否開啟藍芽

  • disable()

    關閉所有的藍芽連線後關閉本地藍芽服務

  • getAddress()

    獲得藍芽mac地址

  • getName()

    獲得藍芽名稱,也就收我們經常設定的藍芽名稱

  • setName()

    設定藍芽名稱

  • startDiscovery()

    開始發現裝置(注意是裝置,例如另外一個手機,而不是藍芽耳機之類的)

  • getBondedDevices()

    獲取繫結(配對)的裝置,測試發現只有手動取消繫結才管用,否則即使關閉藍芽,間隔一會再開啟,這些仍然是繫結的.
    同時一些繫結的裝置(例如手環)用這個方法並沒有返回對應的device

  • startLeScan(LeScanCallback)

    開始對Bluetooth LE devices裝置(藍芽耳機,手環,電子稱等)的掃描.回撥函式會把掃描到的裝置返回,
    注意裝置會重複被掃描到,最好去掉重複,去重時可以用mac地址,也可以用名稱,但是掃描到的Device第一次沒有把
    名稱帶回,所以獲取名稱時最好做非空判斷

  • stopLeScan(LeScanCallback)

    停止掃描

  • 利用系統預設開啟藍芽對話方塊

    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
      Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
      startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }複製程式碼

Android藍芽服務的相關類簡介之BluetoothGatt

Generic Attribute Profile (GATT)—The GATT profile is a general specification for sending and receiving short
pieces of data known as "attributes" over a BLE link. All current Low Energy application profiles are based on
GATT.主從裝置都維護了GATT 分別是client 和 server

  • 獲得方法,建立連線時返回

      mConnGatt = bleDevie.connectGatt(this, false, mGattcallback);複製程式碼

回撥

    public abstract class BluetoothGattCallback {

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

    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
    }

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

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


    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
    }複製程式碼

設定通知

    public boolean setCharacteristicNotification(UUID serviceUuid, UUID characteristicUuid, boolean enable) {
    BluetoothGattCharacteristic characteristic = mConnGatt.getService(serviceUuid).getCharacteristic(characteristicUuid);
    mConnGatt.setCharacteristicNotification(characteristic, enable);
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID);
    descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : new byte[]{0x00, 0x00});
    return mConnGatt.writeDescriptor(descriptor); // descriptor write
}複製程式碼

曾經遇到的坑

  • 藍芽接連時超時

    解決方法:
    在廣播中相應的方法裡進行重新連線

    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
    
            @Override
            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();
                if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {//藍芽已連線
                    tvBluetooth.setText("(已連線)");
                } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                    showToast("藍芽連線斷開,請重試");
                    //這裡重新連線藍芽
                    hideLoading();
                } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {//發現藍芽,設定命令
                    ......
                } else if(BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { //接收到資料
                   ......
                }
            }
        };複製程式碼
  • 藍芽搜尋進行匹配不來BLE裝置

    有些手效能比較低端,這裡可以重啟藍芽,進行重新連線

  • 連線成功後斷開
    1. 保證BLE小裝置沒有被其他連線
    2. 先停止掃描---》重新掃描---》重新連線
  • 讀取過程中藍芽斷開

    首先要保證連線藍芽之前,上一次斷開連線時的操作:

    1. 斷開連線
    2. 斷開(關閉)service
    3. 關閉藍芽

    然後執行:
    先停止掃描---》重新掃描---》重新連線

  • 上傳資料失敗

    把讀取到的資料解析後進行儲存在本地,下次上傳的時候一起上傳。上傳成功後記得進行本低資料的清空

    注意:BLE藍芽連線小裝置時一般屬於主從模組,其中主模組藍芽可以同時連線多個裝置,但讀取時只能讀取一個。
    • 主機:可主動搜尋從機,可以傳送資料,也可以接收資料
    • 從機:可以傳送資料,也可以接收資料,但只能被搜尋
有關專案下載地址: download.csdn.net/detail/lqw7…
GitHub下載連結:github.com/androidstar…

接下來推薦兩個關於Android藍芽BLE的學習網址:

詳細解析BluetoothAdapter的詳細api

www.open-open.com/lib/view/op…

Android:藍芽4.0-BLE-小結=1.0

www.itnose.net/detail/6095…

如果你覺得此文對您有所幫助,歡迎入群 QQ交流群 :232203809   
微信公眾號:終端研發部

Markdown
Markdown

(歡迎關注學習和交流)

相關文章