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"/>
1 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 2 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
1 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { //不支持ble finish(); }
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
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發送不一樣的通道數據便可。
參考: