zoukankan      html  css  js  c++  java
  • android BLE Peripheral 做外设模拟设备,供ios、android 连接通讯。

    为了能让其它设备可以发现其设备,先启动特定广播。看自己需要什么广播格式。

    对于广播可见的mac address:

    在调用startAdvertising();时,mac address 就会改变。

    并且跟mBluetoothAdapter.getAddress();获取到的蓝牙mac 地址不一样。

    这是因为在android 5.0 之后,为了保护真正的mac address。

    在广播出来的地址,是经过随机可解析隐秘转换的(Resolvable private address)。

    所以要在广播数据中添加mac address 输出,就要用静态蓝牙地址。

    BLE设备的地址类型:

    一个BLE设备,可以使用两种类型的地址(一个BLE设备可同时具备两种地址):

    1、 Public Device Address (公有地址)

         该地址需要向IEEE申请(购买),IEEE保证地址的唯一性。

    2、Random Device Address (随机地址)

         设备地址不是固定分配的,而是在设备设备启动后随机生成的。

         Random Device Address分为:

         (1)Static Device Address (静态地址)

           在一个上电周期内保持不变。地址随机生成。

         (2)Private Device Address (私有地址)

                通过定时更新和地址加密两种方法,提高蓝牙地址的可靠性和安全性。

                Private Device Address分为

                    1) Non-resolvable Private Address (不可解析私有地址)

                    会定时更新。以T_GAP(private_addr_int)为周期,建议15分钟。

                    2) Resolvable Private Address  (可解析私有地址)

                    以T_GAP(private_addr_int)为周期,定时更新。哪怕在广播、扫描、已连接等过程中,也可能改变。它通过一个随机数和一个称作identity resolving key (IRK) 的密码生成,因此只能被拥有相同IPK的设备扫描到,可以防止被未知设备扫描和追踪。

    android 对外发出广播,都一样,只是更改其中的方法:

    android BLE Peripheral 模拟 ibeacon 发出ble 广播

    开始广播: 增加使用BluetoothGattServer

     1 public void startAdvertising(MockServerCallBack callBack) {
     2         //获取BluetoothLeAdvertiser,BLE发送BLE广播用的一个API
     3         if (mBluetoothAdvertiser == null) {
     4             mBluetoothAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
     5         }
     6         //创建BluetoothGattServerCallback,
     7         // MockServerCallBack这个类继承自BluetoothGattServerCallback
     8         // BluetoothGattServerCallback这个回调类主要是一些BLE读写的接口
     9         // 关于BLE读写的操作都在这个Callback中完成
    10         if (mBluetoothAdvertiser != null) {
    11             mMockServerCallBack = callBack;
    12             //打开BluetoothGattServer
    13             mGattServer = mBluetoothManager.openGattServer(mActivity, mMockServerCallBack);
    14             if (mGattServer == null) {
    15                 Log.e(TAG, "gatt is null");
    16             }
    17             try {
    18                 mMockServerCallBack.setupServices(mActivity, mGattServer);
    20                 mBluetoothAdvertiser.startAdvertising(createAdvSettings(true, 0)
    21                         , createAdvertiseData(BluetoothUUID.bleServerUUID), mAdvCallback);
    22             } catch (Exception e) {
    23                 Log.v(TAG, "Fail to setup BleService");
    24             }
    25         }
    26 
    27         isAdvertising = true;
    28     }

    创建广播,添加serviceUuid,广播内容,自行决定。

    addServiceUuid(ParcelUuid serviceUuid) 的作用。

    广播数据加入serviceUuid , 当其它设备扫描时,就可以根据此serviceUuid进行特定扫描.

    扫描BLE设备的时候:启动扫描时,有可选参数,传入uuid数组。

    BluetoothAdapter
    public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback);

    使用该函数启动扫描的,会根据所传入的uuid,去扫描过滤,只返回符合条件的设备。

    注意:部分手机可能设置uuid后,扫描不到设备,可能底层扫描问题。

     1  public static AdvertiseData createAdvertiseData(UUID proximityUuid) {
     2     AdvertiseData.Builder builder = new AdvertiseData.Builder();
     4     builder.addManufacturerData(0x0301, new byte[]{0x01, 0x03});
     5     builder.addServiceUuid(ParcelUuid.fromString(BluetoothUUID.bleServerUUID.toString())
     7     AdvertiseData adv = builder.build();
    10     return adv;
    11  }

    BluetoothGattServerCallback:服务事件的回调

    打开notification 对应的value为 BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE

    打开indication 对应的value为 BluetoothGattDescriptor.ENABLE_INDICATION_VALUE

    关闭notification 对应的value均为BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE

    服务事件响应过程:

    (1) 当客户端开始写入数据时: 触发回调方法 onDescriptorWriteRequest

    (2) 在 onDescriptorWriteRequest 方法中,执行下面的方法表示 写入成功 BluetoothGatt.GATT_SUCCESS

    1 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
    2 // 执行 sendResponse后,会触发回调方法 onCharacteristicWriteRequest

    (3) 在 onCharacteristicWriteRequest方法中:

    1 public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId
    2 , BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
    3        // 这个里可以获得 来自客户端发来的数据 requestBytes
    4 }

    (4) 处理响应内容

    BluetoothGattServerCallback :

      1 public class MockServerCallBack extends BluetoothGattServerCallback {
      2 
      3 public void setupServices(Context context, BluetoothGattServer gattServer) throws InterruptedException {
      4         if (gattServer == null) {
      5             throw new IllegalArgumentException("gattServer is null");
      6         }
      7         mGattServer = gattServer;
      8         // 设置一个GattService以及BluetoothGattCharacteristic
      9         BluetoothGattService service = new BluetoothGattService(BluetoothUUID.bleServerUUID,
     10                 BluetoothGattService.SERVICE_TYPE_PRIMARY);
     11 
     12         BluetoothGattService service2 = new BluetoothGattService(BluetoothUUID.bleServerUUID2,
     13                 BluetoothGattService.SERVICE_TYPE_PRIMARY);
     14 
     15         //add a read characteristic.
     16         // 当是ios设备连接过来时,需添加BluetoothGattCharacteristic.PROPERTY_INDICATE或者notify进行兼容。
     17         mCharacteristicRead = new BluetoothGattCharacteristic(BluetoothUUID.readDataUUID
     18                 , BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_INDICATE
     19                 , BluetoothGattCharacteristic.PERMISSION_READ);
     20         //add a descriptor
     21         BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(BluetoothUUID.CLIENT_CHARACTERISTIC_CONFIG
     22                 , BluetoothGattCharacteristic.PERMISSION_WRITE);
     23         mCharacteristicRead.addDescriptor(descriptor);
     24         service.addCharacteristic(mCharacteristicRead);
     25 
     26         BluetoothGattCharacteristic write = new BluetoothGattCharacteristic(
     27                 BluetoothUUID.writeDataUUID,
     28                 BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_INDICATE,
     29                 BluetoothGattCharacteristic.PERMISSION_WRITE);
     30 
     31         service.addCharacteristic(write);
     32 
     33         if (mGattServer != null && service != null) {
     34             mGattServer.addService(service);
     35             mGattServer.addService(service2);
     36         }
     37 
     38     }
     39 
     40     //当添加一个GattService成功后会回调改接口。
     41     public void onServiceAdded(int status, BluetoothGattService service) {
     42         super.onServiceAdded(status, service);
     43         if (status == BluetoothGatt.GATT_SUCCESS) {
     44             Log.d(TAG, "onServiceAdded status=GATT_SUCCESS service=" + service.getUuid().toString());
     45         } else {
     46             Log.d(TAG, "onServiceAdded status!=GATT_SUCCESS");
     47         }
     48     }
     49 
     50     //BLE设备连接状态发生改变后回调的接口
     51     public void onConnectionStateChange(android.bluetooth.BluetoothDevice device, int status,
     52                                         int newState) {
     53         super.onConnectionStateChange(device, status, newState);
     54         Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s"
     55                 , device.getName(), device.getAddress()));
     56         Log.d(TAG, "onConnectionStateChange status=" + status + "->" + newState);
     57         if (newState == BluetoothProfile.STATE_DISCONNECTED) {
     58             btClient = null; // 移除客户端连接设备
     59         }
     60     }
     61 
     62     //当有客户端来读数据时回调的接口
     64     /**
     65      * 特征被读取。当回复响应成功后,客户端会读取然后触发本方法, 
     66      */
     67     public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice device,
     68                                             int requestId, int offset, BluetoothGattCharacteristic characteristic) {
     69         super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
     70         characteristic.setValue(new byte[]{0x03, 0x01});
     71         Log.e(TAG, String.format("1.onCharacteristicReadRequest:device name = %s, address = %s"
     72                 , device.getName(), device.getAddress()));
     73         Log.e(TAG, String.format("onCharacteristicReadRequest:requestId = %s, offset = %s", requestId, offset));
     74         boolean result = mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
     75 
     76         Log.e(TAG, "read request send response:" + result);
     77     }
     78 
     79     //当有客户端来写数据时回调的接口
     81     /**
     82      * 接受具体数据字节
    */ 86 @Override 87 public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device, 88 int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, 89 boolean responseNeeded, int offset, byte[] value) { 90 super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); 91 // 需调用 sendResponse 来响应,为了保持连接。 92 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null); 93 94 // 处理其它设备写进来的数据 95 value. // 处理数据 byte[] value,记住连接设备 96 97 } 98
    // 当有客户端来写Descriptor 时回调的接口 99 /** 描述被写入时,在这里执行bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS...) 时
    * 触发onCharacteristicWriteRequest **/
    100 @Override 101 public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { 102 super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); 103 104 Log.d(TAG, "onDescriptorWriteRequest:" + Arrays.toString(value)); 105 // now tell the connected device that this was all successfull 106 mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); 107 } 108 109 }

    通过adb 获取 蓝牙 mac address: 

    1 adb shell settings get secure bluetooth_address

    或者

    1 // for Android 4.4.4
    2 adb shell service call bluetooth_manager 10 
    3 // for Android 5.0+
    4 adb shell service call bluetooth_manager 12 

    编程获取bluetooth mac address :

    1 String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");

    推荐文章:

    蓝牙4.2保护隐私

    蓝牙协议分析_BLE地址类型

  • 相关阅读:
    python yield yield from
    python isinstance()与type()的区别
    python isinstance用法
    python 展开嵌套的序列
    python getmtime() 最近修改文件内容的时间
    python getctime() 文件最后一次的改变时间
    python getatime() 查看文件的访问时间
    python模拟随机游走
    getopt例子
    matplotlib 代码风格
  • 原文地址:https://www.cnblogs.com/CharlesGrant/p/7155812.html
Copyright © 2011-2022 走看看