低功耗蓝牙开发之创建链接

1、前言

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

2、链接到GATT Server

链接到GATT Server,须要用到BluetoothGatt这个对象,它是蓝牙GATT配置文件的公共API.咱们经过BluetoothGatt对象进行链接的创建和断开,Gatt Services数据的获取,Gatt Characteristics数据的获取和读写操做,Gatt Descriptor数据的读写操做等;数组

咱们先看一下,BluetoothGatt的经常使用API:安全

  • connect():重连方法。当外围设备和中心设备蓝牙断开链接时,用于进行从新链接。若是外围设备超出范围,则等在范围内时就会触发重连;
  • connect(Boolean autoConnect, BluetoothGattCallback callback,Handler handler):

与支持蓝牙GATT的设备创建链接。第二个参数是否自动链接;bash

  • disconnect():断开链接。能够是已经创建的链接或取消正在创建的链接;
  • discoverServices():发现服务。通常用于当GATT链接创建以后,使用BluetoothGatt对象调用该方法来获取外围设备的Gatt Services,Gatt Characteristics,Gatt Descriptors数据。当服务数据发现完毕以后会回调BluetoothGattCallback的onServicesDiscovered方法,此时咱们使用getServices就能够获取外围设备的Gatt Services数据。
  • getService(UUID uuid):返回特定UUID的BluetoothGattService。前提条件是必须针对特定外围设备去获取Gatt Service,也就是说创建链接,获取到BluetoothGatt对象才可使用此方法。同时须要注意可能返回null,若是存在多个具备相同UUID的Gatt Service,默认返回第一个。
  • readCharacteristic(BluetoothGattCharacteristic characteristic):读取相关联外围设备的BluetoothGattCharacteristic.这是异步操做,该操做结果会在BluetoothGattCallback的onCharacteristicRead回调方法里返回。
  • writeCharacteristic(BluetoothGattCharacteristic characteristic):将BluetoothGattCharacteristic 写入相关联外围设备。一旦写操做完成会在BluetoothGattCallback的onCharacteristicWrite方法中回调。
  • readDescriptor(BluetoothGattDescriptor descriptor):读取相关联外围设备的BluetoothGattDescriptor。一旦读操做完成会在BluetoothGattCallback的onDescriptorRead方法进行回调。
  • writeDescriptor(BluetoothGattDescriptor descriptor):将BluetoothGattDescriptor写入相关联外围设备。一旦写操做完成会在BluetoothGattCallback的onDescriptorWrite方法里进行回调。
  • setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enable):

开启或禁用给定Gatt Characteristic的notifications(通知)/indications(指示)。一旦notifications设置为true的话,若是远程设备的Gatt Characteristic发生改变则BluetoothGattCallback的onCharacteristicChanged方法就会触发。app

  • readRemoteRssi():读取已链接的远程设备的RSSI。当RSSI的值被读取以后,会回调BluetoothGattCallback的onReadRemoteRssi方法。
  • readPhy():读取链接的当前发送器PHY和接收器PHY。最终结果会在BluetoothGattCallback的onPhyRead方法里回调。
  • requestMtu(int mtu):针对当前链接请求MTU大小。当咱们使用BluetoothGatt对象调用writeCharacteristic()方法进行数据写入操做时,若是数据大小超过MTU的默认大小时,会被分拆为多个小包进行数据写入的操做。该方法容许开发者修改MTU的大小。会触发BluetoothGattCallback的onMtuChanged方法回调。


1.创建链接:

中心设备(手机等)有时候须要与外围设备(低功耗蓝牙)创建链接,进行参数的修改等操做。固然并非全部的低功耗蓝牙设备都可以被链接上,这个就要看硬件开发者设计的产品允不容许被链接。这些咱们不在考虑。创建链接首先须要扫描到设备,设备的扫描不是本篇文章主要的讨论对象,不清楚的童鞋能够阅读低功耗蓝牙开发之设备扫描。扫描到设备以后拿到设备的信息,用来进行链接的创建。示例代码以下:异步

/**

     * 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


2.读取Gatt Characterstic

咱们提供一个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


3.写入 Gatt Characteristics:

实际场景中咱们会有修改外围设备参数的需求,咱们只要经过特定的服务的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参数。

4.打开通知功能:

若是咱们须要修改外围设备的参数,最好仍是须要打开蓝牙的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;

    }复制代码

执行这段代码,会产生以下结果:

  • 当打开通知功能时,会触发Android系统的蓝牙配对功能,若是配对码输入正确且没有超时时onBondStateChanged方法会有配对状态的变化,onDescriptorWrite方法会有设置的状态值的数组,和设置状态;当配对码输入错误,取消配对或者配对超时,onBondStateChanged会返回配对状态变化,onConnectionStateChange会返回链接状态的变化;(注意:配对码错误或者配对超时,会致使链接断开!)
  • 当关闭Notify功能时,onDescriptorWrite会返回关闭Notify对应数组和状态;


5.关闭Gatt Client:

当咱们使用完毕以后,须要关闭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;

    }复制代码
相关文章
相关标签/搜索