1. 程式人生 > >Android 5.x的低功耗藍芽BLE開發簡介

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開發的資料不是很多,我才下決心寫這篇文章的,希望能對做相關開發犯過迷糊的人有一點兒幫助。同時我也是個安卓開發的新手,對藍芽串列埠通訊也是一知半解,表述難免有紕漏,理解也不到位,如果有幸被大家看到這篇文章我會倍感欣慰,並希望能指出不足之處。


這篇文章簡單明瞭; 更多關於藍芽BLE的資料可以百度谷歌
from: http://www.cnblogs.com/witchiman/p/5320671.html