______________________________________________________________
Android BLE 框架发布,功能全面,简单易用:
https://github.com/a1anwang/okble
______________________________________________________________
iBeacon其实就是在BLE的基础上把广播报的数据格式化了一下。
可以先看一下上一篇文章 《android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser》
熟悉一下BLE的广播数据。
本次文章就是在上一章发出BLE广播的基础上进行改造,让手机成为iBeacon设备。
iBeacon是apple公司定义的,那么我先上一张iBeacon设备的广播协议:
Proximity Beacon Advertising Packet
这个协议规定了 BLE设备广播数据包的格式,按照这个格式进行广播的BLE设备就是一个 合格的iBeacon设备
首先我先上一段真正的 iBeacon设备广播数据包来分析一下:
scandata:0201061AFF4C000215FDA50693A4E24FB1AFCFC6EB0764782500010016C50B0945786869626974696F6E0000000000000000000000000000000000000000
我把这个广播包拆开一下:
020106 这前三个字节跟 iBeacon协议定义是一样的,02表示下面的数据有2个字节长度(0106这2个),01表示数据类型为flag,06是数据.
1AFF 第3-4个字节也是跟协议上一样,蓝牙广播格式,1A表示接下来的一段数据长度是0x1A=26, 26加上020106这3个长度,再加上1A本身1个长度,正好是上图协议上的30字节长度。 FF表示这段数据类型是厂商数据ManufacturerData。
4C00 这个对饮第5-6字节,company id,厂商id ,看过我上篇文章的同学都知道,这个其实就是ManufacturerData ID,这个顺序是倒过来的,所以跟协议上也是一样,4C00表示苹果公司,固定数据,不能变
0215 第7-8字节 跟上图协议上也是一样,Beacon Type 表示这个广播是iBeacon广播,固定字段,不能变,所以其实我们可以解析BLE广播数据包的第5, 6,7,8字节的数据来判断这个BLE设备是不是iBeacon设备
FDA50693A4E24FB1AFCFC6EB07647825 这段数据对应上图协议的第9-24字节,16个字节长度,表示uuid
0001 对应上图协议的第25-26字节,表示major,major共占2字节,所以最大值为 0xFF =65535
0016 对应上图协议的第27-28字节,表示minor,minor也占2字节,所以最大值也是65535
C5对应上图最后一个字节,是个负数 其值对应 10进制的-59,表示iBeacon距离手机1米时候的参考 信号强度(rssi)
从上面的分析可以看出,其实iBeacon就是一个BLE设备,只是其中的某些广播数据符合apple的规定
那么接下来直接基于上篇文章 上代码来实现手机模拟iBeacon设备,主要就是修改 广播数据那一块
先来一个预览图,我把uuid,major,minor等都作为可编辑,方便使用,点击“开启广播”按钮,便会广播iBeacon数据
代码如下:
public void startAction(View v){ if(!mBluetoothAdapter.isEnabled()){ ToastUtils.showToast(this,"请开启蓝牙",2000); return; } String uuid =edit_uuid.getText().toString().toUpperCase(); boolean isvaliduuid= isValidUUID(uuid); if(!isvaliduuid){ ToastUtils.showToast(this,"UUID 格式不正确",2000); return; } int major = -1; if (!TextUtils.isEmpty(edit_major.getText().toString())) { major = Integer.parseInt(edit_major.getText().toString()); } int minor = -1; if (!TextUtils.isEmpty(edit_minor.getText().toString())) { minor = Integer.parseInt(edit_minor.getText().toString()); } if (major < 0 || major > 65535) { ToastUtils.showToast(this,"major ranges:0- 65535",2000); return; } if (minor < 0 || minor > 65535) { ToastUtils.showToast(this,"minor ranges:0- 65535",2000); return; } startAdvertise(uuid,major,minor); } private void startAdvertise(String uuid, int major, int minor) { if (mBluetoothAdapter == null) { return; } if (mBluetoothLeAdvertiser == null) { mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser(); } if (mBluetoothLeAdvertiser != null) { AdvertiseSettings settings=createAdvertiseSettings(0); AdvertiseData data=createAdvertiseData( uuid , major, minor, -59); //-59是 measuredPower,一般设备默认都是-59,这里固定了 mBluetoothLeAdvertiser.startAdvertising(settings ,data , mAdvCallback); } } public AdvertiseSettings createAdvertiseSettings( int timeoutMillis) { AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder(); builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY); builder.setTimeout(timeoutMillis); builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH); return builder.build(); } public AdvertiseData createAdvertiseData(String uuidString, int major, int minor, int txPower) { AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder(); String beaconType="0215"; //按照apple iBeacon协议 String uuid=uuidString.replace("-",""); String majorStr= Conversion.formatStringLenth(4,Integer.toHexString(major),'0'); String minorStr=Conversion.formatStringLenth(4,Integer.toHexString(minor),'0'); String measuredPower=Conversion.formatStringLenth(2,Integer.toHexString(txPower),'0'); String dataStr=beaconType+uuid+majorStr+minorStr+measuredPower; byte[] data=Conversion.hexStringToBytes( dataStr); mDataBuilder.addManufacturerData(0x004C, data);//004c是厂商id,代表apple公司 AdvertiseData mAdvertiseData = mDataBuilder.build(); return mAdvertiseData; }
通过代码可以看到,其实就是在拼凑 ManufacturerData,
我先把需要广播的数据一个一个都先变成16进制字符串,然后把字符串拼起来,最后把字符串转成byte[]
上面的Conversion.formatStringLenth(int targetLenth, String src, char leftCharacter)方法作用主要是把字符串变成指定的长度
长度不足的话,左边补齐字符, major,minor,取值范围是0-65535,共占2字节,对应4个字符串长度, 假如major是10的话,使用Integer.toHexString(major)
转成16进制字符串是A,所以需要左边补3个0。 measurePower同样道理,占1个字节,2个字符串长度,也要补齐。
OK,使用另一个手机打开 Beacon扫描工具来扫描试一下是否广播成功:
检测成功。
为了严谨,我使用apple 手机下载了一个 “Locate Beacon”,这个APP是使用 ios 中的iBeacon的api来检测周围的iBeacon设备,如果它可以检测到的话,那我们的手机模拟iBeacon无疑是成功的:
检测成功,完美!
附上模拟iBeacon源码:http://pan.baidu.com/s/1o7XhPnO
原文地址《android BLE 手机模拟iBeacon发出广播》
发表评论