上一篇文章咱們講述了低功耗藍牙設備開發過程當中的廣播數據解析,對於常見的應用場景而言,作到解析廣播數據已經夠了,何況一旦中心設備和外圍設備創建鏈接的話,廣播就會終止。可是對於藍牙設備管理員而言,就須要鏈接上外圍設備,而後進行設備參數的修改;android
鏈接到GATT Server,須要用到BluetoothGatt這個對象,它是藍牙GATT配置文件的公共API.咱們經過BluetoothGatt對象進行鏈接的創建和斷開,Gatt Services數據的獲取,Gatt Characteristics數據的獲取和讀寫操做,Gatt Descriptor數據的讀寫操做等;數組
咱們先看一下,BluetoothGatt的經常使用API:安全
與支持藍牙GATT的設備創建鏈接。第二個參數是否自動鏈接;bash
開啓或禁用給定Gatt Characteristic的notifications(通知)/indications(指示)。一旦notifications設置爲true的話,若是遠程設備的Gatt Characteristic發生改變則BluetoothGattCallback的onCharacteristicChanged方法就會觸發。app
中心設備(手機等)有時候須要與外圍設備(低功耗藍牙)創建鏈接,進行參數的修改等操做。固然並非全部的低功耗藍牙設備都可以被鏈接上,這個就要看硬件開發者設計的產品允不容許被鏈接。這些咱們不在考慮。創建鏈接首先須要掃描到設備,設備的掃描不是本篇文章主要的討論對象,不清楚的童鞋能夠閱讀低功耗藍牙開發之設備掃描。掃描到設備以後拿到設備的信息,用來進行鏈接的創建。示例代碼以下:異步
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* @param address The device address of the destination device.
* @return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean connect(@NonNull String address) {
MLogger.i(TAG, TAG + " .. connect()~");
if (TextUtils.isEmpty(address)) {
MLogger.e(TAG, "unspecify address");
return false;
}
if (mBluetoothAdapter == null) {
MLogger.d(TAG, "BluetoothAdapter is not initialized");
return false;
}
// Previously connected device. Try to reconnect.
if (!TextUtils.isEmpty(mBluetoothDeviceAddress) && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
MLogger.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = BeaconContants.GATT_STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
MLogger.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, false, mGattCallback);
MLogger.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = BeaconContants.GATT_STATE_CONNECTING;
return true;
}複製代碼
在這裏須要用到外圍設備的Mac地址用來鏈接Gatt服務。async
當鏈接創建成功以後,會觸發BluetoothGattCallback的onConnectionStateChange方法。在回調方法裏咱們就可使用BluetoothGatt的對象,調用mBluetoothGatt.discoverServices()就能夠發現外圍設備Gatt的各類數據信息。當服務數據發現完畢以後會回調BluetoothGattCallback的onServicesDiscovered方法,此時咱們使用getServices就能夠獲取外圍設備的Gatt Services數據。ui
咱們提供一個BluetoothGattCharacteristic對象就能夠讀取它的特徵值。示例代碼以下:this
/**
* Reads the requested characteristic from the associated remote device.
*
* <p>This is an asynchronous operation. The result of the read operation
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
* callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic The characteristic to read from.
* @return true, if the read operation was initiated successfully
* @see BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)
*/
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean readCharacteristic(@NonNull BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter != null && mBluetoothGatt != null) {
if (mConnectionState == BeaconContants.GATT_STATE_CONNECTED) {
final boolean state = mBluetoothGatt.readCharacteristic(characteristic);
MLogger.d(TAG, "readCharacteristic..state : " + state);
return state;
} else {
MLogger.e(TAG, "GATT client has disconnected from GATT server!");
}
} else {
MLogger.d(TAG, "BluetoothAdapter not initialized");
}
return false;
}複製代碼
當咱們讀取操做成功以後,會回調BluetoothGattCallback的onCharacteristicRead方法。spa
實際場景中咱們會有修改外圍設備參數的需求,咱們只要經過特定的服務的UUID拿到須要服務對象就能夠進行參數的修改。示例代碼以下:
/**
* Writes a given characteristic and its values to the associated remote device.
*
* <p>Once the write operation has been completed, the
* {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
* reporting the result of the operation.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic Characteristic to write on the remote device.
* @return true, if the write operation was initiated successfully
* @see BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic)
*/
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter != null && mBluetoothGatt != null) {
if (mConnectionState == BeaconContants.GATT_STATE_CONNECTED) {
final boolean state = mBluetoothGatt.writeCharacteristic(characteristic);
MLogger.d(TAG, "writeCharacteristic..state : " + state
+ "..writetype : " + characteristic.getWriteType());
return state;
} else {
MLogger.e(TAG, "GATT client has disconnected from GATT server!");
}
} else {
MLogger.d(TAG, "BluetoothAdapter not initialized");
}
return false;
}複製代碼
當咱們的寫操做成功以後會觸發BluetoothGattCallback的onCharacteristicWrite回調方法,若是成功修改會回調onCharacteristicChanged方法。
iBeacon設備的參數修改就是基於該方法進行修改,不瞭解iBeacon設備的參數的童鞋,請閱讀:iBeacon參數。
若是咱們須要修改外圍設備的參數,最好仍是須要打開藍牙的notification功能,這樣的話修改特定的BluetoothGattCharacteristic就能夠接收到通知。同時安全起見,打開通知功能會觸發Android系統的輸入配對碼進行配對的功能。示例代碼以下:
/**
* Enable or disable notifications/indications for a given characteristic.
*
* @param characteristic The characteristic for which to enable notifications
* @param enable Set to true to enable notifications
* @param uuid TO get a descriptor with a given UUID out of the list of
* descriptors for this characteristic.
* @return true, if the requested notification status was set successfully
* @see BluetoothGatt#setCharacteristicNotification(BluetoothGattCharacteristic, boolean)
*/
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean setCharacteristicNotification(@NonNull BluetoothGattCharacteristic characteristic,
@NonNull boolean enable, UUID uuid) {
if (mBluetoothAdapter != null && mBluetoothGatt != null) {
if (mConnectionState == BeaconContants.GATT_STATE_CONNECTED) {
mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(uuid);
if (descriptor != null) {
MLogger.d(TAG, "It's going to set notifition value : " + enable);
descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE :
BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
final boolean state = mBluetoothGatt.writeDescriptor(descriptor);
MLogger.d(TAG, "setCharacteristicNotification..operation state : " + state);
return state;
} else {
MLogger.e(TAG, "The descriptor is null or no descriptor with the given UUID was found! ");
}
} else {
MLogger.e(TAG, "GATT client has disconnected from GATT server!");
}
} else {
MLogger.d(TAG, "BluetoothAdapter not initialized");
}
return false;
}複製代碼
執行這段代碼,會產生以下結果:
當咱們使用完畢以後,須要關閉Gatt鏈接,同時釋放掉資源。
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
MLogger.d(TAG, TAG + " .. close()~");
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}複製代碼