關於Android 5.x的低功耗藍牙BLE開發簡介


  藍牙4.0分為標准藍牙和低功耗藍牙(BLE),標准藍牙就是手機上用的那種,低功能耗藍牙由於其具有最大化的待機時間、快速連接和低峰值的發送和接收特性,被廣泛用於智能手表、智能手環等可穿戴設備上。在安卓4.3之前,安卓平台上的BLE開發相當難搞,好在谷歌在4.3之后發布了官方的API。在安卓5.0之后又引入了新的API,原來的API已經被廢棄。在新的系統里采用舊API開發的APP仍可使用,但采用新API開發的APP只能在LOLLIPOP即安卓5.0及其以后的版本使用。

  標准藍牙的的開發和BLE不同。標准藍牙連接里有兩個角色一個是客戶端一個是服務器,當客戶端搜索到藍牙服務器后並與之配對后,才能通過UUID(這個是唯一的,服務器端必須與客戶端一致)建立socket,然后使用流像文件讀寫和網絡通信那樣傳輸數據就行了。在BLE里,變成了中心設備(central)和外圍設備(peripheral),中心設備就是你的手機,外圍設備就是智能手環一類的東西。開發BLE的應用都得遵守Generic Attribute Profile (GATT),一個BLE藍牙設備包含多個service,每個service又包含多個characteristic。每個characteristic有一個value和多個descriptor,通過characteristic中心設備與外圍設備進行通信。descriptor顧名思義,包含了BLE設備的一些信息。不同service、characteristic和descriptor都有各自己唯一的UUID。想要跟BLE設備通信,首先通過UUID獲取目標服務,然后再通過UUID獲取characteristic,charateristic起着載體的作用,通過writeCharacteristic()和readCharacteristic(),可以寫入和讀出信息。每個characteristic都有一些自己的屬性,其中在property里,說明了該characteristic的屬性,例如READ|WRITE|WRITE_NO_RESPONSE|NOTIFY。

  以下是關鍵代碼:

  1.首先,在AndroidManifest.xml里加入  

   <uses-feature android:name="android.bluetooth.le" android:required="true"/> //Android 5.0之前是android.hardware.bluetooth_le
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>

  使用新API時,最好在調用方法前判斷下系統版本,否則會出現意想不到的錯誤。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  ...
}

 

  2.獲取BluetoothAdapter。

 BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);//這里與標准藍牙略有不同
 BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
  /*隱式打開藍牙*/
  if (!bluetoothAdapter.isEnabled()) {
    bluetoothAdapter.enable();
  }

 

 

  3.然后獲取BluetoothLeScanner,通過startScan()方法掃描周圍的BLE設備。當搜索到目標設備或者搜索一定時間后通過BluetoothScanner的stopScan()方法停止搜索。  

BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
scanner.startScan(leCallback);

   leCallback是一個回調函數,通過onScanResult()把每次搜索到的設備添加到本地。leCallback還有一個方法onBatchScanResults(),按理說應該是批量處理搜索到的結果,但是不知道為什么在我這里無法調用。  

leCallback = new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    super.onScanResult(callbackType, result);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        BluetoothDevice device = result.getDevice();
                        if (!devices.contains(device)) {  //判斷是否已經添加
                            devices.add(device);
                        }
                        deviceAdapter.notifyDataSetChanged();
                    }
                }

                @Override
                public void onScanFailed(int errorCode) {
                    super.onScanFailed(errorCode);
                    Log.e("搜索失敗");
                }
            };

 

  4.開始連接。

BluetoothGatt bluetoothGatt = device.connectGatt(MainActivity.this, false, new BluetoothGattCallback() {

                @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                    if (newState == BluetoothProfile.STATE_CONNECTED) {   
                        gatt.discoverServices();          //連接成功,開始搜索服務,一定要調用此方法,否則獲取不到服務
                    }
                }

                @Override
                public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                      Log.e(TAG,gatt.getDevice().getName() + " write successfully");
                }

                @Override
                public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
                      String value = UtilOnStr.parseBytesToHexString(characteristic.getValue());
                        Log.e(TAG,gatt.getDevice().getName() + " recieved " + value);
                }

        @Override
          public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                String response = UtilOnStr.parseBytesToHexString(characteristic.getValue());
             Log.e(TAG,  "The response is "+ response); 
            }

});

 

  

   5.寫入和讀取數據。

BluetoothGattService service = bluetoothGatt.getService(SERVICE_UUID);
if(service != null) {
  characteristic = service.getCharacteristic(CHARACTERISTIC_UUID);
  if (characteristic !=null) {    
    bluetoothGatt.setCharacteristicNotification(characteristic, true);  //設置characteristic的通知,觸發bluetoothGatt.onCharacteristicWrite()事件。
        characteristic.setValue(UtilOnStr.parseHexStringToBytes(value));
        bluetoothGatt.writeCharacteristic(characteristic);  
    }
}

  當連接上BLE設備后,調用discoveryServices()發現服務,通過SERVICE_UUID獲取目標service,如果service不為空,再通過CHARACTERISTIC_UUID獲取characteristic,借助characteristic寫入指定值與BLE設備進行通信。這里要注意的是characteristic接收的是一個byte數組,而且讀寫的方法都是異步的。調用bluetoothGatt.readCharacteristic(characteristic)可讀取BLE設備返回的值。bluetoothGatt的writeCharacteristic()方法會觸發BluetoothGattCallback里的onCharacteristicWrite(),相應的,bluetoothGatt的readCharacteristic()方法會觸發onCharacteristicRead()。

  對中心設備與外圍設備的傳輸數據的處理發生在onCharacteristicChanged()里,當characteristic寫入了正確的數值后,會激活BLE設備,不時地返回數據。

  當不知道BLE設備的service和characteristic的對應的UUID時,可以在回調函數里的onServicesDiscovered()方法里,通過BluetoothGatt的getServices()獲得該設備所有的service,然后再調用service的getUuid()得到其UUID,同理通過service的getCharacteristics()可以得到每個service所有的characteristic和其UUID。然后一個個不厭其煩的嘗試,找到正確的service和characteristic(我就是這樣干的)。

  6.總結

  由於網上關於Android 5.x 低功耗藍牙 BLE開發的資料不是很多,我才下決心寫這篇文章的,希望能對做相關開發犯過迷糊的人有一點兒幫助。同時我也是個安卓開發的新手,對藍牙串口通信也是一知半解,表述難免有紕漏,理解也不到位,如果有幸被大家看到這篇文章我會倍感欣慰,並希望能指出不足之處。

 

 

 

 

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM