Android 藍牙4.0 BLE (onServicesDiscovered 返回 status 是 129,133時)

Android ble (Bluetooth Low Energy) 藍牙4.0,也就是說android 4.3+, API level >= 18,且支持藍牙4.0的手機纔可使用。html

BLE是藍牙4.0的核心Profile,主打功能是快速搜索,快速鏈接,無需配對,超低功耗保持鏈接和傳輸數據,弱點是數據傳輸速率低,因爲BLE的低功耗特色,所以廣泛用於穿戴設備。android

官方demo:http://developer.android.com/guide/topics/connectivity/bluetooth-le.htmlide

官方demo(csdn下載,感謝分享的人吧):http://download.csdn.net/detail/lqw770737185/8116019函數

因爲搜索須要儘可能減小功耗,所以在實際使用時須要注意:
一、當找到對應的設備後,當即中止掃描;
二、不要循環搜索設備,爲每次搜索設置適合的時間限制。避免設備不在可用範圍的時候持續不停掃描,消耗電量。
注意:添加藍牙權限:
1 <uses-permission android:name="android.permission.BLUETOOTH"/>
2 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
Android 6.0 及以上,還需添加 位置權限
若是6.0 這兩個權限仍是動態權限:
1 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
除了藍牙權限外,若是須要BLE feature則還須要聲明uses-feature:
1 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
設置required爲true時,則應用只能在支持BLE的Android設備上安裝運行;required爲false時,Android設備都可正常安裝運行,須要在代碼運行時判斷設備是否支持BLE feature:
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
      //不支持ble
      finish();
} 
 
(1)實現 BluetoothAdapter.LeScanCallback接口,BLE設備的搜索結果將經過這個callback返回
 1       private ExecutorService mExecutor; 
 2 
 3       // Device scan callback.
 4       private BluetoothAdapter.LeScanCallback mLeScanCallback =
 5               new BluetoothAdapter.LeScanCallback() {
 6   
 7           @Override
 8           public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
 9                // 不能作太多事情,特別周圍ble設備多的時候。容易出現錯誤或者ANR,須要把結果處理放到另外的線程去。
10                if(mExecutor == null) {
11                    mExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
12                }
13                new ScanProcessor().executeOnExecutor(mExecutor, new ScanData(device, rssi, scanRecord));
14          }
15  
16      };

ScanData:ui

 1 private class ScanData {
 2     public ScanData(BluetoothDevice device, int rssi, byte[] scanRecord) {
 3         this.device = device;
 4         this.rssi = rssi;
 5         this.scanRecord = scanRecord;
 6     }
 7 
 8     int rssi;
 9     BluetoothDevice device;
10     byte[] scanRecord;
11  }

掃描結果處理:this

 1 private class ScanProcessor extends AsyncTask<ScanData, Void, MingbikeBeacon> {
 2 
 3         public ScanProcessor() {
 4         }
 5 
 6         @Override
 7         protected Object doInBackground(ScanData... params) {
 8             if (params == null || params.length == 0)
 9                 return null;
10             ScanData scanData = params[0];
11             // todo scanData
12             return new Object();
13         }
14 
15         @Override
16         protected void onPostExecute(Object obj) {
17              // todo obj
18         }
19 
20         @Override
21         protected void onPreExecute() {
22         }
23 
24         @Override
25         protected void onProgressUpdate(Void... values) {
26         }
27     }

(2)關閉BLE設備的搜索spa

1 mBluetoothAdapter.stopLeScan(mLeScanCallback);

(3)開啓BLE設備的搜索.net

1 mBluetoothAdapter.startLeScan(mLeScanCallback);

*************注意:搜索時,你只能搜索傳統藍牙設備或者BLE設備,二者徹底獨立,不可同時被搜索。線程

(4)使用BluetoothGatt 來鏈接設備code

兩個設備經過BLE通訊,首先須要創建GATT鏈接。這裏咱們講的是Android設備做爲client端,鏈接GATT Server。
鏈接GATT Server,你須要調用BluetoothDevice的 connectGatt()方法。此函數帶三個參數:Context、autoConnect(boolean)和 BluetoothGattCallback對象。
1 private BluetoothGatt mBluetoothGatt;
 1   final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // 藍牙mac地址  2     if (device == null) {
 3       Log.w(TAG, "Device not found.  Unable to connect.");
 4       return false;
 5     }
 6     mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback);

參數autoConnect,若是爲 true 的話,系統就會發起一個後臺鏈接,等到系統發現了一個設備,就會自動連上,一般這個過程是很是慢的。爲 false 的話,就會直接鏈接,一般會比較快。一樣,BluetoothGatt.connect()只能發起一個後臺鏈接,不是直接鏈接。因此這個地方須要當心。

(5)使用BluetoothGattCallback 來跟設備進行通訊

 1 private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
 2     @Override
 3     public void onConnectionStateChange(BluetoothGatt gatt, 
 4         int status, int newState) {
 5         super.onConnectionStateChange(gatt, status, newState); 
9
if (newState == BluetoothProfile.STATE_CONNECTED) { 10 setState(State.CONNECTED); 11 gatt.discoverServices(); 12 } else { 13 setState(State.IDLE); 14 } 15 } 16 17 @Override 18 public void onServicesDiscovered(BluetoothGatt gatt, 19    int status) { 20 if(status == BluetoothGatt.GATT_SUCCESS) { 21 Log.v(TAG, "onServicesDiscovered: " + status); 22 } 23 } 24 }

鏈接時會走這個方法onConnectionStateChange,傳過來的新狀態是鏈接狀態,這時在這個方法中調用一下這句:mBluetoothGatt.discoverServices(),

mBluetoothGatt是鏈接完成時的對象,調用這句後,會走回調函數的onServicesDiscovered方法。在這個方法中去獲取設備的一些服務,藍牙通道,而後經過這些通道去發送數據給外設。

有些設備,在 onServicesDiscovered 回調中,返回的 status 是 129,133時,在關閉,從新打開藍牙,沒法解決問題時,建議更換設備,這些問題大可能是設備底層gatt 服務異常,從新鏈接,進行discoverServices();

1 // 出現129,133時。關閉藍牙
2 mBluetoothAdapter.disable();
3 // 關閉藍牙後,延時1s,從新開啓藍牙
4 mBluetoothAdapter.enable();

在藍牙設備中, 其包含有多個BluetoothGattService, 而每一個BluetoothGattService中又包含有多個BluetoothGattCharacteristic。

當onServicesDiscovered()回調的 status == BluetoothGatt.GATT_SUCCESS, 能夠進行獲取service。

(1)獲取到設備中的服務列表  mBluetoothGatt.getServices(); 或者經過uuid 來獲取某一個服務:

public List<BluetoothGattService> getSupportedGattServices() {
        if (mBluetoothGatt == null)
            return null;
        return mBluetoothGatt.getServices();
        // 或者經過uuid來獲取某一個服務 mBluetoothGatt.getServices(uuid);
}

(2)經過Gatt這個對像,就是藍牙鏈接完成後獲取到的對象,經過這個對象設置好指定的通道向設備中寫入和讀取數據。

在onServicesDiscovered(BluetoothGatt gatt, int status) 回調中, 獲取服務對象,獲取讀取、寫入、描述的特徵。

 1  // 獲取指定uuid的服務
 2  BluetoothGattService service = gatt.getService(BluetoothUUID.bleServerUUID);
 3  // 獲取讀取特徵
 4  BluetoothGattCharacteristic readCharacteristic = service.getCharacteristic(BluetoothUUID.readDataUUID);
 5  // 獲取寫入特徵
 6  writeCharacteristic = service.getCharacteristic(BluetoothUUID.writeDataUUID);
 7  gatt.setCharacteristicNotification(readCharacteristic, true);
 8  // 獲取描述特徵
 9  BluetoothGattDescriptor descriptor = readCharacteristic.getDescriptor(BluetoothUUID.CLIENT_CHARACTERISTIC_CONFIG);
10  // 要看外圍設備的設置
11  if (isNotify) {
12     descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
13  } else {
14     descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
15  }
16  gatt.writeDescriptor(descriptor);

服務中, 也能夠經過調用 gattService.getCharacteristics():得到Characteristic 集合.

在 Characteristic中, 能夠經過  mBluetoothGatt.readCharacteristic(characteristic); 來讀取其裏面的數據, 其結果在mGattCallback 回調函數中獲取.

寫如數據:  

mCurrentcharacteristic.setValue(data); 

mBluetoothGatt.wirteCharacteristic(mCurrentcharacteristic);

1 public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) {
2 
3         if (mBluetoothAdapter == null || mBluetoothGatt == null) {
4             Log.w(TAG, "BluetoothAdapter not initialized");
5             return;
6         }
7 
8         mBluetoothGatt.writeCharacteristic(characteristic);
9  }
1 public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
2         if (mBluetoothAdapter == null || mBluetoothGatt == null) {
3             Log.w(TAG, "BluetoothAdapter not initialized");
4             return;
5         }
6         mBluetoothGatt.readCharacteristic(characteristic);
7  }

當外圍設備,調用:

BluetoothGattServer.class
notifyCharacteristicChanged(BluetoothDevice device,
BluetoothGattCharacteristic characteristic, boolean confirm);

就會觸發中心設備的onCharractersticChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) 方法回調:

1 @Override
2 public void onCharacteristicChanged(BluetoothGatt gatt,
3                                             BluetoothGattCharacteristic characteristic) {
4      byte[] values = characteristic.getValue();
5      // todo values
6 }

注意:BluetoothGattCharacteristic這個是指定的通道,藍牙服務:

1 BluetoothGattCharacteristic characteristic = null;
2 characteristic = mGattCharacteristics.get(4).get(4);

這兩個數字就是從指定的服務中找到你要發送數據的那個服務。

若是要進行多個鏈接,每次鏈接完成後能夠將BluetoothGatt的對象放到一個list裏面,獲取到的服務也放到一個List裏面,而後發送數據的時候調用不一樣的Gatt發送不一樣的通道數據便可。

參考:

Android提升之Android手機與BLE終端通訊

android 藍牙4.0多通道

Android Bluetooth Low Energy(官方)

相關文章
相關標籤/搜索