好久沒記錄東西了,前段時間研究了一哈android4.0控制多個外設的狀況,注意,須要使用android版本4.3以上,藍牙4.0及以上。android
我這裏使用的控制藍牙燈泡,使用android4.3的手機,手機上的藍牙是4.0.app
記得在manifest文件中加入權限:async
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
先拿到BluetoothManager和BluetoothAdapter的對象。ide
// 初始化 Bluetooth adapter, 經過藍牙管理器獲得一個參考藍牙適配器(API必須在以上android4.3或以上和版本) final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); // 檢查設備上是否支持藍牙 if (mBluetoothAdapter == null) { Toast.makeText(this, R.string.error_bluetooth_not_supported,Toast.LENGTH_SHORT).show(); finish(); return; }
看下是否開啓了藍牙,若是沒有開啓,跳轉到設置去開啓藍牙。函數
// 爲了確保設備上藍牙能使用, 若是當前藍牙設備沒啓用,彈出對話框向用戶要求授予權限來啓用 if (!mBluetoothAdapter.isEnabled()) { if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } }
調用startScan方法開始掃描,stopScan方法中止掃描,掃描到的設備都在回調函數裏。oop
private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); invalidateOptionsMenu(); } }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } invalidateOptionsMenu(); }
// Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { mLeDeviceListAdapter.addDevice(device); // mLeDeviceListAdapter.notifyDataSetChanged(); } }); } };
掃描後的BluetoothDevice加入到列表中,這時列表中就會有設備,經過getName能夠獲取設備的藍牙名字,getAddress獲取設備的藍牙地址。post
列表出來了以後,點擊某個設備進行鏈接。ui
注意這裏的鏈接跟2.0的藍牙的鏈接不同,經過設備的connectGatt方法進行鏈接,鏈接完成後會得到一個BluetoothGatt的對象,這個對象中有鏈接的一些重要信息,切記要保存好。this
public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) { Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); if (mBluetoothGatt.connect()) { return true; } else { return false; } } final BluetoothDevice device = mBluetoothAdapter .getRemoteDevice(address); if (device == null) { Log.w(TAG, "Device not found. Unable to connect."); return false; } // We want to directly connect to the device, so we are setting the // autoConnect // parameter to false. mBluetoothGatt = device.connectGatt(this, true, mGattCallback); Log.d(TAG, "Trying to create a new connection."); mBluetoothDeviceAddress = address; bluetoothGatts.add(mBluetoothGatt); return true; }
鏈接時有一個回調函數mGattCallback,這個函數中有不少設備的相關信息,好比設備的狀態啊,設備中的通道哈,一些服務啊之類的。spa
// Implements callback methods for GATT events that the app cares about. For // example, // connection change and services discovered. private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { System.out.println("onConnectionStateChange"); String intentAction; if (status == BluetoothProfile.STATE_DISCONNECTED && newState == BluetoothProfile.STATE_CONNECTED) { intentAction = ACTION_GATT_CONNECTED; Log.i(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); Log.e("shang", "鏈接成功"); mHandler.sendEmptyMessage(MESSAGE_START_SUCCESS); } else if (status == BluetoothProfile.STATE_DISCONNECTED && newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = ACTION_GATT_DISCONNECTED; setConnStatus(false); Log.e("shang", "鏈接失敗"); Log.i(TAG, "Disconnected from GATT server."); mHandler.sendEmptyMessage(STATE_CONNECTFAILED); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { System.out.println("onServicesDiscovered-----"); if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); displayGattServices(getSupportedGattServices()); mHandler.sendEmptyMessage(MESSAGE_BLUETOOTH_INIT); } else { Log.w(TAG, "onServicesDiscovered received: " + status); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { System.out.println("onCharacteristicRead"); if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { System.out.println("onDescriptorWriteonDescriptorWrite = " + status + ", descriptor =" + descriptor.getUuid().toString()); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); if (characteristic.getValue() != null) { System.out.println(characteristic.getStringValue(0)); } System.out.println("--------onCharacteristicChanged-----"); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { } public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { System.out.println("--------write success----- status:" + status); }; };
鏈接時會走這個方法onConnectionStateChange,傳過來的新狀態是鏈接狀態,這時在這個方法中調用一下這句:mBluetoothGatt.discoverServices(),
mBluetoothGatt是鏈接完成時的對象,還記得吧,調用這句後,會走回調函數的onServicesDiscovered方法。在這個方法中去獲取設備的一些服務,藍牙通道,而後經過這些通道去發送數據給外設。
查看該外設中支持的一些服務通道:
public List<BluetoothGattService> getSupportedGattServices() { if (mBluetoothGatt == null) return null; return mBluetoothGatt.getServices(); }
// Demonstrates how to iterate through the supported GATT // Services/Characteristics. // In this sample, we populate the data structure that is bound to the // ExpandableListView // on the UI. private void displayGattServices(List<BluetoothGattService> gattServices) { if (gattServices == null) return; String uuid = null; ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>(); ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>(); mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>(); // Loops through available GATT Services. for (BluetoothGattService gattService : gattServices) { HashMap<String, String> currentServiceData = new HashMap<String, String>(); uuid = gattService.getUuid().toString(); gattServiceData.add(currentServiceData); ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>(); List<BluetoothGattCharacteristic> gattCharacteristics = gattService .getCharacteristics(); ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>(); // Loops through available Characteristics. for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { charas.add(gattCharacteristic); HashMap<String, String> currentCharaData = new HashMap<String, String>(); uuid = gattCharacteristic.getUuid().toString(); gattCharacteristicGroupData.add(currentCharaData); } mGattCharacteristics.add(charas); gattCharacteristicData.add(gattCharacteristicGroupData); } bluetoothGattChacteristics.add(mGattCharacteristics); }
而後就能夠經過Gatt這個對像,就是藍牙鏈接完成後獲取到的對象,經過這個對象設置好指定的通道向設備中寫入和讀取數據。
寫數據:
public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.writeCharacteristic(characteristic); }
讀數據:
/** * Request a read on a given {@code BluetoothGattCharacteristic}. The read * result is reported asynchronously through the * {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} * callback. * * @param characteristic * The characteristic to read from. */ public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.readCharacteristic(characteristic); }
注意:BluetoothGattCharacteristic這個是指定的通道,藍牙服務:
BluetoothGattCharacteristic characteristic = null; characteristic = mGattCharacteristics.get(4).get(4);
這兩個數字就是從指定的服務中找到你要發送數據的那個服務。
最後,若是要進行多個鏈接,每次鏈接完成後能夠將BluetoothGatt的對象放到一個list裏面,獲取到的服務也放到一個List裏面,而後發送數據的時候調用不一樣的Gatt發送不一樣的通道數據便可。
關於藍牙4.0的BluetoothLeGatt鏈接,android Samples有一個例子,發上來吧,須要的朋友能夠下載看看。