安卓模拟ibeacon_android BLE Peripheral 做外设模拟设备,供ios、android 连接通讯。

本文详细介绍了如何在Android设备上模拟ibeacon,通过启动特定广播并使用BluetoothGattServer创建BLE外设。内容涵盖了Android 5.0后蓝牙地址的变化、BLE设备地址类型、广播数据设置、服务UUID添加以及如何处理客户端的读写请求。此外,还提到了获取蓝牙MAC地址的方法和兼容iOS设备的注意事项。
摘要由CSDN通过智能技术生成

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

对于广播可见的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 对外发出广播,都一样,只是更改其中的方法:

开始广播: 增加使用BluetoothGattServer

1 public voidstartAdvertising(MockServerCallBack callBack) {2 //获取BluetoothLeAdvertiser,BLE发送BLE广播用的一个API

3 if (mBluetoothAdvertiser == null) {4 mBluetoothAdvertiser =mBluetoothAdapter.getBluetoothLeAdvertiser();5 }6 //创建BluetoothGattServerCallback,7 //MockServerCallBack这个类继承自BluetoothGattServerCallback8 //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 staticAdvertiseData createAdvertiseData(UUID proximityUuid) {2 AdvertiseData.Builder builder = newAdvertiseData.Builder();

4 builder.addManufacturerData(0x0301, new byte[]{0x01, 0x03});5 builder.addServiceUuid(ParcelUuid.fromString(BluetoothUUID.bleServerUUID.toString())

7 AdvertiseData adv =builder.build();

10 returnadv;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, intrequestId2 , BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {3 //这个里可以获得 来自客户端发来的数据 requestBytes

4 }

(4) 处理响应内容

BluetoothGattServerCallback :

1 public class MockServerCallBack extendsBluetoothGattServerCallback {2

3 public void setupServices(Context context, BluetoothGattServer gattServer) throwsInterruptedException {4 if (gattServer == null) {5 throw new IllegalArgumentException("gattServer is null");6 }7 mGattServer =gattServer;8 //设置一个GattService以及BluetoothGattCharacteristic

9 BluetoothGattService service = newBluetoothGattService(BluetoothUUID.bleServerUUID,10 BluetoothGattService.SERVICE_TYPE_PRIMARY);11

12 BluetoothGattService service2 = newBluetoothGattService(BluetoothUUID.bleServerUUID2,13 BluetoothGattService.SERVICE_TYPE_PRIMARY);14

15 //add a read characteristic.16 //当是ios设备连接过来时,需添加BluetoothGattCharacteristic.PROPERTY_INDICATE或者notify进行兼容。

17 mCharacteristicRead = newBluetoothGattCharacteristic(BluetoothUUID.readDataUUID18 , BluetoothGattCharacteristic.PROPERTY_READ |BluetoothGattCharacteristic.PROPERTY_INDICATE19 , BluetoothGattCharacteristic.PERMISSION_READ);20 //add a descriptor

21 BluetoothGattDescriptor descriptor = newBluetoothGattDescriptor(BluetoothUUID.CLIENT_CHARACTERISTIC_CONFIG22 , BluetoothGattCharacteristic.PERMISSION_WRITE);23 mCharacteristicRead.addDescriptor(descriptor);24 service.addCharacteristic(mCharacteristicRead);25

26 BluetoothGattCharacteristic write = newBluetoothGattCharacteristic(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(intstatus, 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, intstatus,52 intnewState) {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 voidonCharacteristicReadRequest(android.bluetooth.BluetoothDevice device,68 int requestId, intoffset, 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 @Override87 public voidonCharacteristicWriteRequest(android.bluetooth.BluetoothDevice device,88 int requestId, BluetoothGattCharacteristic characteristic, booleanpreparedWrite,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 @Override101 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.42 adb shell service call bluetooth_manager 103 // 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");

推荐文章:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值