簡(jiǎn)述Android Bluetooth Low Energy

目錄
[TOC]

Bluetooth Low Energy

  • 簡(jiǎn)介:
    • 與傳統(tǒng)藍(lán)牙相比,低功耗藍(lán)牙的設(shè)計(jì)對(duì)電量消耗更低。
    • 只支持Android 4.3以上的系統(tǒng)版本,即 API Level>=18。

藍(lán)牙開發(fā)對(duì)象

  • BluetoothManager

    • 獲取對(duì)象:

        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
      
    • 注意:BluetoothManager僅在Android4.3以上的系統(tǒng)版本支持,即 API Level>=18。

  • BluetoothAdapter

    • 獲取對(duì)象:

        BluetoothAdapter mBluetoothAdapter = BluetoothManager.getAdapter();
        // 或者
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
      
      • 注意:一個(gè)Android系統(tǒng)只有一個(gè)BluetoothAdapter。
    • 方法描述:

      • 藍(lán)牙狀態(tài)
        • isEnabled()
          • 判斷系統(tǒng)藍(lán)牙是否打開
        • disable()
          • 隱式關(guān)閉系統(tǒng)藍(lán)牙
        • enable()
          • 隱式打開系統(tǒng)藍(lán)牙
      • 藍(lán)牙設(shè)備搜索
        • startDiscovery()/cancelDiscovery()
          • 開始/取消搜索設(shè)備(經(jīng)典藍(lán)牙 和 低功耗藍(lán)牙)
          • 執(zhí)行過程(耗時(shí)12秒):
            1. 系統(tǒng)發(fā)送 BluetoothAdapter.ACTIOIN_DISCOVERY_STARTED 的廣播
            2. 搜索藍(lán)牙設(shè)備...
            3. 只要找到一個(gè)設(shè)備就發(fā)送一個(gè) BluetoothDevice.ACTION_FOUND 的廣播
            4. 從廣播接收器中就可以得到這個(gè)BluetoothDevice對(duì)象
            5. 系統(tǒng)發(fā)送 BluetoothAdapter.ACTION_FINISHED 的廣播
        • startLeScan()/stopLeScan()
          • 開始/取消搜索設(shè)備(低功耗藍(lán)牙)
          • 注意:
            • 在API Level-21以上被標(biāo)記廢棄使用
  • BluetoothLeScanner

    • 獲取對(duì)象:

        BluetoothLeScanner mBluetoothLeScanner= BluetoothAdapter.getBluetoothLeScanner();
      
    • 方法描述:

      • startScan()/stopScan()
        • 開始/取消搜索設(shè)備(低功耗藍(lán)牙)
        • 注意:
          • 在API Level-21以上使用
  • BluetoothDevice

    • 代表了一個(gè)遠(yuǎn)程的藍(lán)牙設(shè)備, 通過這個(gè)類可以查詢遠(yuǎn)程設(shè)備的物理地址, 名稱, 連接狀態(tài)等信息,
    • 獲取對(duì)象:
      • 物理地址對(duì)應(yīng)的Device:

          BluetoothAdapter.getRemoteDevice(address);
        
      • 已經(jīng)配對(duì)的Device集合:

          BluetoothAdapter.getBoundedDevices();
        
      • 掃描結(jié)果回調(diào)中的Device:

          BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
              @Override
              public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
              }
          };
        
  • BluetoothGatt

    • BluetoothGatt繼承BluetoothProfile,
    • 通過BluetoothGatt可以連接設(shè)備(connect),發(fā)現(xiàn)服務(wù)(discoverServices),并把相應(yīng)地屬性返回到 BluetoothGattCallback,
    • 獲取對(duì)象:
      • BluetoothGattCallback回調(diào)方法中獲取。
  • BluetoothProfile

    • 一個(gè)通用的規(guī)范,按照這個(gè)規(guī)范來收發(fā)數(shù)據(jù)。
  • 連接成功后,我們首先需要獲得服務(wù),然后是該服務(wù)所包含的特征,最后是特征的描述符。

  • 服務(wù)(Service):

    • BluetoothGattService
      • 一個(gè) Service 可以包含多個(gè) Characteristic,
      • 獲取對(duì)象:
        • 通過指定的 UUID 從 BluetoothGatt 實(shí)例中獲得:

            BluetoothGattService service = BluetoothGatt.getService(UUID.fromString(BLE_SERVICE));
          
  • 特征(Characteristic):

    • BluetoothGattCharacteristic
      • 一個(gè) Characteristic 包含一個(gè) Value 和多個(gè) Descriptor,
      • 相當(dāng)于一個(gè)數(shù)據(jù)類型,它包括一個(gè)value和0~n個(gè)value的描述(Descriptor),
      • 獲取對(duì)象:
        • 通過指定的 UUID 從 BluetoothGattService 中得到:

            BluetoothGattCharacteristic characteristic = BluetoothGattService.getCharacteristic(UUID.fromString(BLE_CHARACTERISTIC))
          
  • 描述符(Descriptor):

    • BluetoothGattDescriptor
      • 一個(gè) Descriptor 包含一個(gè) Value,
      • 對(duì) Characteristic 的描述,包括范圍、計(jì)量單位等,
      • 獲取對(duì)象:
        • 通過指定的 UUID 從 BluetoothGattCharacteristic 對(duì)象中獲得:

            List<BluetoothGattDescriptor> descriptorList = BluetoothGattCharacteristic.getDescriptors();
            // 或者
            BluetoothGattDescriptor descriptor = BluetoothGattCharacteristic.getDescriptor(UUID.fromString("BLE_DESCRIPTOR"));
          

低功耗藍(lán)牙開發(fā)基本流程

  • 申請(qǐng)權(quán)限

    • 基礎(chǔ)權(quán)限:

        <!-- 執(zhí)行所有的藍(lán)牙通信,如請(qǐng)求連接,接受連接和傳輸數(shù)據(jù) -->
        <uses-permission android:name="android.permission.BLUETOOTH"/>
        <!-- 初始化設(shè)備發(fā)現(xiàn)或者操縱藍(lán)牙設(shè)置 -->
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
      
    • 注意:

      • 如果應(yīng)用僅支持低功耗藍(lán)牙
        • 在 AndroidManifest.xml 添加以下聲明:

            <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
          
        • 動(dòng)態(tài)判斷:

            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
                Toast.makeText(this, "該設(shè)備不支持低功耗藍(lán)牙", Toast.LENGTH_SHORT).show();
            }  
          
      • 在 Android 6.0 及以上的系統(tǒng)版本,需動(dòng)態(tài)申請(qǐng)位置權(quán)限。
        如果應(yīng)用沒有位置權(quán)限,藍(lán)牙掃描功能不能使用(其它藍(lán)牙操作例如連接藍(lán)牙設(shè)備和寫入數(shù)據(jù)不受影響)。
        • 在 AndroidManifest.xml 添加以下聲明:

          <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
          或
          <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
          
        • 動(dòng)態(tài)申請(qǐng):

          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
              if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                  requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
              }
          }
          
          @Override
          public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
              switch (requestCode) {
                  case PERMISSION_REQUEST_COARSE_LOCATION:
                      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                          // 權(quán)限申請(qǐng)成功,處理業(yè)務(wù)邏輯
                      }
                      break;
                  default:
                      break;
              }
          }
          
  • 是否支持藍(lán)牙

      BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
      
      if (bluetoothManager.getAdapter() == null) {
          Toast.makeText(Context, "沒有發(fā)現(xiàn)藍(lán)牙模塊", Toast.LENGTH_SHORT).show();
      }
    
  • 開啟/關(guān)閉藍(lán)牙

    • 檢查藍(lán)牙是否開啟

        BluetoothAdapter.isEnabled();
      
    • 開啟

      • 隱式開啟

          BluetoothAdapter.enable();
        
        • 注意:
          • 需要注冊(cè)權(quán)限:

              <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
            
          • 在 Android 6.0 及以上的系統(tǒng)版本,隱式開啟依舊會(huì)提示用戶。

      • 顯示開啟

          Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
          startActivityForResult(enableBtIntent, REQUESTCODE_BLUETOOTH);
        
        • 確認(rèn)結(jié)果:

          • 方法一:注冊(cè)廣播

              IntentFilter intentFilter = new IntentFilter();  
              intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//藍(lán)牙狀態(tài)
              intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);// 掃描開始
              intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);// 掃描結(jié)束
              registerReceiver(new BluetoothReceiver(), intentFilter);
            
              private class BluetoothReceiver extends BroadcastReceiver {
            
                  @Override
                  public void onReceive(Context context, Intent intent) {
            
                      String action = intent.getAction();
                      if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                          switch (BluetoothAdapter.getDefaultAdapter().getState()) {
                              case BluetoothAdapter.STATE_ON:// 打開
                                  break;
                              case BluetoothAdapter.STATE_OFF:// 關(guān)閉
                                  break;
                              case BluetoothAdapter.STATE_TURNING_OFF:// 藍(lán)牙處于關(guān)閉過程中
                                  break;
                              case BluetoothAdapter.STATE_TURNING_ON:// 藍(lán)牙處于打開過程中
                                  break;
                              default:
                                  break;
                          }
                      }
                  }
              }
            
          • 方法二:重寫onActivityResult()

              @Override
              protected void onActivityResult(int requestCode, int resultCode, Intent data) {
                  super.onActivityResult(requestCode, resultCode, data);
                  if (resultCode == RESULT_OK) {//藍(lán)牙開啟成功
                      switch (requestCode) {
                          case REQUESTCODE_BLUETOOTH:
                              break;
                          default:
                              break;
                      }
                  } else if (resultCode == RESULT_CANCELED) {//藍(lán)牙開啟失敗
                      ToastUtils.showShort("藍(lán)牙開啟失敗,請(qǐng)手動(dòng)開啟藍(lán)牙");
                  }
              }
            
        • 前往系統(tǒng)設(shè)置界面

            startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
          
    • 關(guān)閉

      • 隱式關(guān)閉

          BluetoothAdapter.disable();
        
      • 前往系統(tǒng)設(shè)置界面

          startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
        
  • 掃描藍(lán)牙設(shè)備

    • 開啟/關(guān)閉掃描設(shè)備
      • 開啟

        • 掃描全部藍(lán)牙設(shè)備

            BluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback callback)
          
        • 只掃描含有特定 UUID Service 的藍(lán)牙設(shè)備

            BluetoothAdapter.startLeScan(UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback)
          
      • 關(guān)閉

          BluetoothAdapter.stopLeScan(BluetoothAdapter.LeScanCallback callback)
        
  • 連接設(shè)備

      BluetoothGatt BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) {}
    
    • autoConnect:表示是否需要自動(dòng)連接。
      • 設(shè)置為 true 表示如果設(shè)備斷開了,會(huì)不斷的嘗試自動(dòng)連接。
      • 設(shè)置為 false 表示只進(jìn)行一次連接嘗試。
    • BluetoothGattCallback:表示連接后進(jìn)行的一系列操作的回調(diào),共計(jì)9個(gè)回調(diào)方法,以下列舉常用的5個(gè)。
      • 連接狀態(tài)變化

          void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {}
        
      • 執(zhí)行BluetoothGatt.discoverServices();后回調(diào),發(fā)現(xiàn)服務(wù)

          void onServicesDiscovered(BluetoothGatt gatt, int status) {}
        
      • 執(zhí)行BluetoothGatt.writeCharacteristic();后回調(diào),寫入數(shù)據(jù)執(zhí)行結(jié)果

          void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {}
        
      • 執(zhí)行BluetoothGatt.setCharacteristicNotification();后回調(diào),Characteristic值發(fā)生改變

          void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {}
        
      • 執(zhí)行BluetoothGatt.writeDescriptor();后回調(diào)

          void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {}
        
  • 發(fā)現(xiàn)服務(wù)

    • 在onConnectionStateChange()中,判斷連接狀態(tài),連接成功,搜索連接設(shè)備所支持的service

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
      
            if (newState == BluetoothGatt.STATE_CONNECTED) {//連接成功
      
                gatt.discoverServices();//搜索連接設(shè)備所支持的service
      
            } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {//連接斷開
            }
        }
      
    • discoverServices()被執(zhí)行后,在onServicesDiscovered()中,獲取指定UUID Service,存下BluetoothGatt對(duì)象

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
      
            BluetoothGattService service = gatt.getService(UUID.fromString(BLE_SERVICE));
      
            if (service != null) {
                mBluetoothGatt = gatt;
            }
        }
      
  • 讀寫數(shù)據(jù)

    • 寫:
      • 獲取指定 UUID Serivce 的 BluetoothGattService 對(duì)象,

      • 從而得到指定 UUID Characteristic 的 BluetoothGattCharacteristic 對(duì)象,將數(shù)據(jù)設(shè)置進(jìn)去,

      • 最后用 BluetoothGatt 對(duì)象向藍(lán)牙設(shè)備寫入數(shù)據(jù)

          public void writeCharacteristic() {
              
              byte[] data = {0x00};//封包數(shù)據(jù),根據(jù)硬件協(xié)議填寫
              
              BluetoothGattCharacteristic characteristic = mBluetoothGatt.getService(UUID.fromString(BLE_SERVICE)).getCharacteristic(UUID.fromString(BLE_WRITE));
              characteristic.setValue(data);//設(shè)置數(shù)據(jù)
        
              mBluetoothGatt.writeCharacteristic(characteristic);//寫入設(shè)備
          }
        
    • 讀:
      • writeCharacteristic() 調(diào)用后,

      • 會(huì)走 onCharacteristicChanged() 回調(diào),

      • BluetoothGattCharacteristic 對(duì)象中獲取藍(lán)牙設(shè)備傳回的數(shù)據(jù),

      • 通過藍(lán)牙硬件協(xié)議判斷并做出相應(yīng)處理。

          @Override
          public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
              super.onCharacteristicChanged(gatt, characteristic);
              
              byte[] value = characteristic.getValue();
        
              switch (value[0]) {//判斷協(xié)議,對(duì)應(yīng)處理
                  case 0x00:
                      break;
                  default:
                      break;
              }
          }
        
  • 斷開連接

      BluetoothGatt.disconnect();
      BluetoothGatt.close();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容