6-低功耗蓝牙开发之建立连接

目录

 

一、前言

二、连接到GATT Server

1.建立连接:

2.读取Gatt Characterstic

3.写入 Gatt Characteristics:

4.打开通知功能:

5.关闭Gatt Client:


一、前言

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

二、连接到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的设备建立连接。第二个参数是否自动连接;

  • 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方法就会触发。

  • 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服务。

当连接建立成功之后,会触发BluetoothGattCallback的onConnectionStateChange方法。在回调方法里我们就可以使用BluetoothGatt的对象,调用mBluetoothGatt.discoverServices()就可以发现外围设备Gatt的各种数据信息。当服务数据发现完毕之后会回调BluetoothGattCallback的onServicesDiscovered方法,此时我们使用getServices就可以获取外围设备的Gatt Services数据。

 

2.读取Gatt Characterstic

我们提供一个BluetoothGattCharacteristic对象就可以读取它的特征值。示例代码如下:

/**

     * 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方法。

 

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;

    }

>>下一篇:7-iBeacon参数

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心灵行者

你的鼓励是我最大的创作动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值