您的足迹:首页 > 蓝牙BLE >android BLE Peripheral BluetoothGattServer 手机模拟设备,可以被连接 通信

android BLE Peripheral BluetoothGattServer 手机模拟设备,可以被连接 通信

______________________________________________________________

Android BLE 框架发布,功能全面,简单易用:

https://github.com/a1anwang/okble

______________________________________________________________

上期讲过android手机可以模拟BLE设备来进行广播,有兴趣的同学可以再去看一下,有助于理解BLE设备广播数据的分析android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser    android BLE 手机模拟iBeacon发出广播


好了,本期重点是 在广播的基础上 可以被其他手机通过BLE的api进行连接,也就是 手机完全模拟成一个BLE设备。

在BLE协议中,有两个角色,周边(Peripheral)和中央(Central)

开发过BLE的app的同学对 BluetoothGatt都不陌生,给设备发送数据,读取数据都是通过BluetoothGatt, BluetoothGatt其实就是中央,  BLE设备就是周边来提供数据。 那么 周边 对应的类是 BluetoothGattServer ,注意不是BluetoothGattService.

直接进入主题,创建BluetoothGattServer :

public class MainActivity extends Activity {
    BluetoothAdapter bluetoothAdapter;
    BluetoothGattServer gattServer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

        bluetoothAdapter = bluetoothManager.getAdapter();
        gattServer = bluetoothManager.openGattServer(this, gattServerCallback);

    }
    private BluetoothGattServerCallback gattServerCallback = new BluetoothGattServerCallback() {
        @Override
        public void onConnectionStateChange(final BluetoothDevice device, int status, int newState) {
            super.onConnectionStateChange(device, status, newState);

            LogUtils.e(TAG, " onConnectionStateChange:" + status + " newState:" + newState + " devicename:" + device.getName() + " mac:" + device.getAddress());

        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            super.onServiceAdded(status, service);

            LogUtils.e(TAG, " onServiceAdded status:" + status+" service:"+service.getUuid().toString());
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
            LogUtils.e(TAG, " onCharacteristicReadRequest requestId:" + requestId + " offset:" + offset + " characteristic:" + characteristic.getUuid().toString());

        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);

            LogUtils.e(TAG, " onCharacteristicWriteRequest requestId:" + requestId + " preparedWrite:" + preparedWrite + " responseNeeded:" + responseNeeded + " offset:" + offset + " value:" + OKBLEDataUtils.Bytes2HexString(value) + " characteristic:" + characteristic.getUuid().toString());


        }

        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
            super.onDescriptorReadRequest(device, requestId, offset, descriptor);

            LogUtils.e(TAG, " onCharacteristicReadRequest requestId:" + requestId + " offset:" + offset + " descriptor:" + descriptor.getUuid().toString());


        }

        @Override
        public void onDescriptorWriteRequest(final BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
            LogUtils.e(TAG, " onDescriptorWriteRequest requestId:" + requestId + " preparedWrite:" + preparedWrite + " responseNeeded:" + responseNeeded + " offset:" + offset + " value:" + OKBLEDataUtils.Bytes2HexString(value) + " characteristic:" + descriptor.getUuid().toString());

        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            super.onExecuteWrite(device, requestId, execute);

            LogUtils.e(TAG, " onExecuteWrite requestId:" + requestId + " execute:" + execute);
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);

            LogUtils.e(TAG, " onNotificationSent status:" + status);
        }

        @Override
        public void onMtuChanged(BluetoothDevice device, int mtu) {
            super.onMtuChanged(device, mtu);
            LogUtils.e(TAG, " onMtuChanged mtu:" + mtu);
        }
    };




}

有一个回调 BluetoothGattServerCallback,里面很多回调方法大家应该很眼熟,但是有点区别,和BluetoothGattCallback很像,因为这是成对存在的嘛。

代码写到这里呢,如果把手机开启BLE广播的话(开启方法见上面提到的文章),其他手机是可以扫描到并连接这个模拟设备的,会走到回调:onConnectionStateChange    BLE重点不是连接,还是连接之后的数据通信,通信大家都知道特征值BluetoothGattCharacteristic, 没错,那么我们现在来给这个模拟设备加上特征值,特征值是属于BluetoothGattService的,那么我们先创建BluetoothGattService:


BluetoothGattService service1 = new BluetoothGattService(UUID.fromString("0000ccc0-0000-1000-8000-00805f9b34fb"),
                BluetoothGattService.SERVICE_TYPE_PRIMARY);

BluetoothGattCharacteristic characteristic1 = new BluetoothGattCharacteristic(
                UUID.fromString("0000ccc1-0000-1000-8000-00805f9b34fb"),
                BluetoothGattCharacteristic.PROPERTY_WRITE,
                BluetoothGattCharacteristic.PERMISSION_WRITE);

service1.addCharacteristic(characteristic1);
gattServer.addService(service1);
 
这里创建了 uuid为ccc0的service, uuid为ccc1的characteristic,然后把 characteristic添加进service里面。


new BluetoothGattCharacteristic() 有3个参数,第一个参数就是uuid,第二个是property属性,例子里填的的是PROPERTY_WRITE,表示可写,也就是手机是可以向这个特征值发送数据的, 第三个参数permission权限,填的是PERMISSION_WRITE,表示有权限写入,其实我一直没理解透为什么还要个permission,如果不想被写入 不要PROPERTY_WRITE可写不就行了嘛。  如果你想能正确写入数据到模拟设备里,这里的permission参数必须填PERMISSION_WRITE,如果你填PERMISSION_READ等其他数据,你write数据下去的时候回调会告诉你失败,无权写入,这个待会我都会一一分析。

这样就完整的创建出带有特征值的BluetoothGattService,熟悉BLE开发的同学还知道,每个BluetoothGattService可以拥有多个BluetoothGattCharacteristic,再加一个特征值:


BluetoothGattCharacteristic characteristic2 = new BluetoothGattCharacteristic(
                UUID.fromString("0000ccc2-0000-1000-8000-00805f9b34fb"),
                BluetoothGattCharacteristic.PROPERTY_READ,
                BluetoothGattCharacteristic.PERMISSION_READ);

service1.addCharacteristic(characteristic2);
gattServer.addService(service1);

这样又给BluetoothGattService加了一个特征值,同样的,permission参数必须填PERMISSION_READ,不然读取会回调失败。这样可读可写的特征值都有了(有同学提到了通知,这个下面重点介绍)。接下来我们用2台手机,一台作为中央(手机1号),一台模拟周边(手机2号)来看一下这个运行过程:

为了排版,我用了一张长图片:

好的,读和写的操作很类似,上面的一个过程 详细表示了中央和周围2个角色的运行。


那么再讲一下 notify/indicate

熟悉BLE开发的同学已经知道,使用notify/indicate功能,连接成功之后需要开启 notify/indicate才可以,这个开启的过程其实是对 特征值characteristic下的2902这个描述符descriptor的value 进行设置。



我先上一段 开启notify/indicate 的代码:


private boolean setNotificationOrIndication(boolean enable,
                                                BluetoothGattCharacteristic characteristic) {
        if (characteristic == null) {
            LogUtils.e(TAG, "setNotificationOrIndication failed, characteristic is null");
            return false;
        }
        if((characteristic.getProperties()&BluetoothGattCharacteristic.PROPERTY_NOTIFY)==0
                &&(characteristic.getProperties()&BluetoothGattCharacteristic.PROPERTY_INDICATE)==0){
            LogUtils.e(TAG, "setNotificationOrIndication failed, characteristic has no notification or indication function");
            return false;
        }
        if (!isConnected()) {
            LogUtils.e(TAG, "setNotificationOrIndication failed, device not connected");
            return false;
        }
        if (mBluetoothGatt == null) {
            LogUtils.e(TAG, "setNotificationOrIndication failed, mBluetoothGatt is null");
            return false;
        }

        if (!mBluetoothGatt.setCharacteristicNotification(characteristic,
                enable)) {
            LogUtils.e(TAG, "setNotificationOrIndication failed");
            return false;
        }

        BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));

        if (clientConfig == null) {
            LogUtils.e(TAG, "setNotificationOrIndication failed,clientConfig is null");
            return false;
        }
        byte[] configValue=null;
        if(enable){
            if((characteristic.getProperties()&BluetoothGattCharacteristic.PROPERTY_NOTIFY)!=0){
                configValue=BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
            }else if((characteristic.getProperties()&BluetoothGattCharacteristic.PROPERTY_INDICATE)!=0){
                configValue=BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
            }
        }else{
            configValue=BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
        }
        boolean b = clientConfig.setValue(configValue);
        if (!b) {
            LogUtils.e(TAG, "setNotificationOrIndication failed,clientConfig setValue failed");
            return false;
        }
        b = mBluetoothGatt.writeDescriptor(clientConfig);
        LogUtils.e(TAG, "setNotificationOrIndication:" + b);
        return b;
    }

开启 notification/indication 的代码里我们可以看到  首先获取 了特征值的 uuid为2902的这个BluetoothGattDescriptor

为什么是2902?其实这就是BLE协议的规定,2902就是专门用来描述特征值是否拥有notify/indicate的功能的。

然后给这个descriptor 设置了value :

打开notification 对应的value为 BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE

打开indication对饮的value为BluetoothGattDescriptor.ENABLE_INDICATION_VALUE

关闭对应的value均为BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE

我们来看一下这些常量对应的源码:



然后贴一张BLE的协议:


这样我们就清楚了 value值得由来。


好了,不多BB,直接给我们的模拟设备(手机2)加上一个拥有notification功能的特征值:


public class MainActivity extends AppCompatActivity {
    private String TAG = "MainActivity";

    Handler handler = new Handler();

    BluetoothAdapter bluetoothAdapter;
    BluetoothLeAdvertiser mBluetoothLeAdvertiser;

    BluetoothGattServer gattServer;

    TextView tv_status;
    BluetoothManager bluetoothManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

        bluetoothAdapter = bluetoothManager.getAdapter();

        mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();

        gattServer = bluetoothManager.openGattServer(this, gattServerCallback);
        BluetoothGattCharacteristic characteristic1 = new BluetoothGattCharacteristic(
                UUID.fromString("0000ccc1-0000-1000-8000-00805f9b34fb"),
                BluetoothGattCharacteristic.PROPERTY_WRITE,
                BluetoothGattCharacteristic.PERMISSION_WRITE);


        BluetoothGattCharacteristic characteristic2 = new BluetoothGattCharacteristic(
                UUID.fromString("0000ccc2-0000-1000-8000-00805f9b34fb"),
                BluetoothGattCharacteristic.PROPERTY_READ,
                BluetoothGattCharacteristic.PERMISSION_READ);
        BluetoothGattService service1 = new BluetoothGattService(UUID.fromString("0000ccc0-0000-1000-8000-00805f9b34fb"),
                BluetoothGattService.SERVICE_TYPE_PRIMARY);
        service1.addCharacteristic(characteristic1);
        service1.addCharacteristic(characteristic2);
        gattServer.addService(service1);

        BluetoothGattCharacteristic characteristic3 = new BluetoothGattCharacteristic(
                UUID.fromString("0000bbb1-0000-1000-8000-00805f9b34fb"),
                BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ ,
                BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ );
        characteristic3.addDescriptor(new BluetoothGattDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"), BluetoothGattDescriptor.PERMISSION_WRITE));

        final BluetoothGattService service2 = new BluetoothGattService(UUID.fromString("0000bbb0-0000-1000-8000-00805f9b34fb"),
                BluetoothGattService.SERVICE_TYPE_PRIMARY);
        service2.addCharacteristic(characteristic3);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    gattServer.addService(service2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

这里面有几个注意点

1.我新建了一个uuid为bbb0的服务service2,一个 uuid为bbb1的特征值characteristic3 ,然后给bbb1这个特征值添加了 2902这个Descriptor,必须添加这个Descriptor。

2.在 new bbb1 这个characteristic3  的时候,第二个property参数我填的是:

BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ 
没错,使用|(或)运算,熟悉BLE开发的同学遇到过 有些特征值 同时拥有读/写/通知等组合功能, 我这里这样写就可以让bbb1这个特征值同时拥有这3个操作,可以自由组合。 第三个 permission参数 填的是
BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ


也是使用|(或)运算,既然bbb1同时可读可写,那么permission也需要把2个加上,不然会权限不够,读写失败。

3.在添加了 第一个 service1之后,我用线程睡眠了1000毫秒,然后才添加的service2,这是我在测试中发现连续添加service,有时候会有部分service添加失败,没有回调onServiceAdded,这个跟 连续进行读写特征值,有些操作失败一样 应该是一个道理(虽然读写特征值的源码里有busy这个boolean值可以明确的看出来蓝牙操作事个耗时操作,需要排队进行, 但是我在gattserver源码里没有找到连续添加失败的原因,也没有busy这个变量,但我想原理应该也是一样的吧)。


那么用手机1(中央)连接手机2(周边),然后打开通知,进行数据传递,前面打开通知的过程跟上面的读写过程差的不多:

手机1 调用 setNotificationOrIndication 会像2902的descriptor写入数据,然后手机2会收到回调onDescriptorWriteRequest:


        int i = 0;
        @Override
        public void onDescriptorWriteRequest(final BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
            LogUtils.e(TAG, " onDescriptorWriteRequest requestId:" + requestId + " preparedWrite:" + preparedWrite + " responseNeeded:" + responseNeeded + " offset:" + offset + " value:" + OKBLEDataUtils.Bytes2HexString(value) + " characteristic:" + descriptor.getUuid().toString());
            gattServer.sendResponse(device, requestId,0, offset, value);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (isConnected(device)) {
                        try {
                            Thread.sleep(1000);
                            notifyData(device, "bbb1", new byte[]{(byte) i}, false);
                            i++;
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    private void notifyData(final BluetoothDevice device, String uuid, byte[] value, final boolean confim) {

        final String entireUUID = CommonUUIDUtils.Common_UUID_String_xxxx.replace("xxxx", uuid.toLowerCase());

        BluetoothGattCharacteristic characteristic = null;
        for (BluetoothGattService service : gattServer.getServices()) {
            for (BluetoothGattCharacteristic mcharacteristic : service.getCharacteristics()) {
                if (mcharacteristic.getUuid().toString().equals(entireUUID)) {
                    characteristic = mcharacteristic;
                    break;
                }
            }
        }
        if (characteristic != null) {
            characteristic.setValue(value);
            gattServer.notifyCharacteristicChanged(device, characteristic, confim);

        }
    }


这里代码收到onDescriptorWriteRequest回调后,也是用了gattServer.sendResponse(device, requestId,0, offset, value);进行回复,然后手机1就会收到回调:public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) 表示开启完成。

然后手机2(周边) 里,我用了一个线程,来循环发送数据,数据发送后手机2会收到回调:

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);

            LogUtils.e(TAG, " onNotificationSent status:" + status);
        }


,手机1会收到回调:

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);

            LogUtils.e(TAG," onCharacteristicChanged characteristic:"+characteristic.getUuid().toString() +" value:"+OKBLEDataUtils.Bytes2HexString(characteristic.getValue()));

        }


然后手机1收到的数据打印结果如下:


07-03 17:34:11.955 12132-12147/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:00
07-03 17:34:12.950 12132-12580/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:01
07-03 17:34:14.030 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:02
07-03 17:34:15.067 12132-12147/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:03
07-03 17:34:15.987 12132-12580/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:04
07-03 17:34:17.031 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:05
07-03 17:34:18.111 12132-12147/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:06
07-03 17:34:19.034 12132-12580/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:07
07-03 17:34:20.026 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:08
07-03 17:34:21.147 12132-12147/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:09
07-03 17:34:22.076 12132-12580/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:0A
07-03 17:34:23.070 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:0B
07-03 17:34:24.067 12132-12147/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:0C
07-03 17:34:25.150 12132-12580/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:0D
07-03 17:34:26.110 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:0E
07-03 17:34:27.110 12132-12147/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:0F
07-03 17:34:28.112 12132-12580/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:10
07-03 17:34:29.192 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:11
07-03 17:34:30.147 12132-12147/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:12
07-03 17:34:31.192 12132-12580/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:13
07-03 17:34:32.190 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:14
07-03 17:34:33.187 12132-12148/com.a1anwang.mybledemo E/OKBLEDevice:  onCharacteristicChanged characteristic:0000bbb1-0000-1000-8000-00805f9b34fb value:15


好了,notification过程介绍完毕,indication跟这个差不多。

其他注意点:

1. 周边(手机2)APP在每次重新运行时,模拟出的BLE设备的MAC地址都是随机变化的,也就是说 手机2每次重新运行这个模拟BLE设备的app的时候,手机1在进行扫描的时候,扫描到的 模拟设备(手机2)的MAC地址都是不一样的。其实更准确的说法:手机2每次使用BluetoothLeAdvertiser.startAdvertising() 开启模拟BLE广播的时候,这个模拟的BLE设备的MAC地址都是不一样的。

而,在周边BluetoothGattServer的回调onConnectionStateChange里的 BluetoothDevice,这个蓝牙设备是指 中央设备即手机1,这个device的MAC地址不会随着APP的重启而改变,只会随着 手机蓝牙开关的重启而改变(重启手机?蓝牙也会重启,当然也改变)

 private BluetoothGattServerCallback gattServerCallback = new BluetoothGattServerCallback() {
        @Override
        public void onConnectionStateChange(final BluetoothDevice device, int status, int newState) {
            super.onConnectionStateChange(device, status, newState);
            //这个device是中央设备, mac地址会 因为 中央(手机)蓝牙重启而变化
            LogUtils.e(TAG, " onConnectionStateChange:" + status + " newState:" + newState + " devicename:" + device.getName() + " mac:" + device.getAddress());
        }


2.周边(手机2)在被连接成功后 如果调用BluetoothLeAdvertiser.stopAdvertising 停止BLE广播的话,会造成断线,这一点和我们连接真正的智能硬件时体验不一样。

3.周边(手机2)在被 中央设备(手机1的APP)连接后,周边设备的广播还是在继续,依然可以被其他 手机的APP或者 手机1的其他的APP连接并通信


最后附上 手机模拟BLE设备BluetoothGattServer 的使用代码:http://pan.baidu.com/s/1nvQaoit




相关推荐

发表评论

路人甲 表情
看不清楚?点图切换 Ctrl+Enter快速提交

网友评论(6)

BluetoothGattCharacteristic.PROPERTY_READ + BluetoothGattCharacteristic.PROPERTY_NOTIFY
同时拥有读/写/通知等组合功能,我觉得不应该是直接相加,因为相加后没法拆开啊
应该用 | 合并,然后用 & 可以拆开,+和 | 可能结果一样(这种情况刚好正确),但也可能不一样
01 + 10  = 01 | 10 = 11
11 + 10  = 101
11 | 10  = 11
lioil.win 3周前 (2018-06-05) 回复
@lioil.win:嗯,你说的对, 用|, 拆开的时候用&,那么对应的组合用|肯定没毛病
AlanWang 3周前 (2018-06-06) 回复
我看到有些人用逻辑或
BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY
二进制或运算,直接相加 ,它们结果相似,但还是有差别,我觉得Android经常用的是 |
lioil.win 3周前 (2018-06-05) 回复
通知有疑问,
为什么要新加service?
通知UUID应该是随便写吧,如果服务端是我们自己定的,这个通知没什么意义,不设置通知,也可以主动发送给客户端
lioil 3周前 (2018-06-05) 回复
@lioil:不设置通知不可以发送哦
AlanWang 3周前 (2018-06-06) 回复
CreeperSan 2个月前 (2018-05-09) 回复