上一篇文章咱们讲述了低功耗蓝牙设备开发过程当中的广播数据解析,对于常见的应用场景而言,作到解析广播数据已经够了,何况一旦中心设备和外围设备创建链接的话,广播就会终止。可是对于蓝牙设备管理员而言,就须要链接上外围设备,而后进行设备参数的修改;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;
}复制代码