Android 藍牙開發
我們在進行藍牙開發時首先要了解低功耗藍牙、經典藍牙、單模藍牙、雙模藍牙之間的關系。
單模藍牙:支持低功耗藍牙
雙模藍牙:支持低功耗藍牙和經典藍牙
經典藍牙:支持經典藍牙
藍牙開發大致分為這幾步
前面需要定位權限和藍牙權限的支持
發現設備:
經典藍牙發現設備api
BluetoothAdapter.startDiscovery
聽說可以同時發現經典藍牙和低功耗藍牙(BLE)。但我這沒單模的藍牙,所以沒辦法測試。
因為startDiscovery返回的是一個是否開始掃描設備,我們要獲取藍牙設備的信息需要注冊一個 BroadcastReceiver 針對 ACTION_FOUND
Intent 會攜帶額外的字段 EXTRA_DEVICE 和 EXTRA_CLASS。這兩者分別包含 BluetoothDevice 和 BluetoothClass。
var filter =IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver,filter); val mReceiver = object :BroadcastReceiver(){ override fun onReceive(context: Context?, intent: Intent?) { var action = intent?.action if(BluetoothDevice.ACTION_FOUND == action){ var device = intent?.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) } } } override fun onDestroy() { super.onDestroy() unregisterReceiver(mReceiver) }
Ble發現設備api
BluetoothAdapter.getBluetoothLeScanner()
BluetoothLeScanner.startScan(ScanCallback callback)//掃描會在屏幕關閉時停止以節省電量。 再次打開屏幕時,將恢復掃描。 為避免這種情況,請使用下面兩個
BluetoothLeScanner.startScan(List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)
BluetoothLeScanner.startScan(List<ScanFilter> filters, ScanSettings settings, PendingIntent callbackIntent)
BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); filters.add(new ScanFilter.Builder() .setServiceUuid(ParcelUuid.fromString("0000000-0000-0000-0000-000000000000")) .build()); bluetoothLeScanner.startScan(filters , new ScanSettings.Builder().build(), new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Log.d(MainActivity.ACTIVITY_SERVICE, "onScanResult:"+ "\n Rssi() "+result.getRssi()+ "\n AdvertisingSid() "+result.getAdvertisingSid()+ "\n DataStatus() "+result.getDataStatus()+ "\n ScanRecord() "+result.getScanRecord().getBytes()+ "\n Address() "+result.getDevice().getAddress()+ "\n Address() "+result.getDevice().getName() ); } } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); } } );
建立連接:
在配對之前應該先cancelDiscovery()或者stopScan(callback),
然后根據獲取到藍牙Mac地址連接即可
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(result.getDevice().getAddress()); device.connectGatt(MainActivity.this, false, new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); //status 連接或斷開連接操作成功 BluetoothGatt.GATT_SUCCESS(0) //newState 新的連接狀態 BluetoothProfile.STATE_DISCONNECTED(0-斷開狀態) BluetoothProfile.STATE_CONNECTED(1-連接狀態) } } );
數據通信:
ble寫入操作
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); //status 連接或斷開連接操作成功 BluetoothGatt.GATT_SUCCESS(0) //newState 新的連接狀態 BluetoothProfile.STATE_DISCONNECTED(0-斷開狀態) BluetoothProfile.STATE_CONNECTED(1-連接狀態) //獲取遠程設備提供的服務以及它們的特征和描述符。這步很重要而且是一個異步操作(這里需要時間直接接在下面寫不可取) bluetoothGatt.discoverServices(); //獲取藍牙GATT服務 BluetoothGattService gattService = bluetoothGatt.getService(UUID.fromString("00000000-0000-0000-0000-000000000000"/*藍牙協議*/)); //GATT特性:用於構建 GATT 服務的基本數據元素 BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID.fromString("00000000-0000-0000-0000-000000000000")); //設置數據,這里是我加密后的數據所以看起來有點不習慣 byte[] data = {-27, 36, 65, -70, -8, 94, 18, -12, -56, 116, -68, -124, 92, -19, 94, -91 }; //設置此特性的本地存儲值。 characteristic.setValue(data); //寫入到遠程藍牙設備 bluetoothGatt.writeCharacteristic(characteristic); }
Ble通知讀取操作
//通知UUID BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(UUID.fromString("00000000-0000-0000-0000-000000000000")); enableNotification(bluetoothGatt,true,gattCharacteristic); public void enableNotification(BluetoothGatt bluetoothGatt, boolean enable, BluetoothGattCharacteristic characteristic) { if (bluetoothGatt == null || characteristic == null) { return; } if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) { return; } //獲取到Notify當中的Descriptor通道 然后再進行注冊 List<BluetoothGattDescriptor> clientConfigs = characteristic.getDescriptors(); if (clientConfigs == null || clientConfigs.size() ==0) { return; } if (enable) { for (BluetoothGattDescriptor clientConfig: clientConfigs) { clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(clientConfig); } } else { for (BluetoothGattDescriptor clientConfig: clientConfigs) { clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(clientConfig); } } }