RadiusNetwork iBeacon Library For Android 设备发现过程梳理
来源:互联网 发布:红衣军 知乎 编辑:程序博客网 时间:2024/06/07 01:30
我所使用的时这个library的老版本,也就是0.x版。最新版是2.x了。
老版本:https://github.com/Vinayrraj/Android-iBeacon-Demo(service就是library源码,reference是例子)
使用这个library提供的例子时,发现永远只能显示我4个iBeacon设备中的1个。于是我跟了一下源码。设备发现的大概流程如下:
从这里出发
//开始计算设备距离iBeaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
- Region是包含uuid,marjor,minor等等的一个bean
接着到startRangingBeaconsInRegion 这个方法
public void startRangingBeaconsInRegion(Region region) throws RemoteException { Message msg = Message.obtain(null, IBeaconService.MSG_START_RANGING, 0, 0); StartRMData obj = new StartRMData(new RegionData(region), rangingCallbackAction()); msg.obj = obj; msg.replyTo = rangingCallback; serviceMessenger.send(msg); }
然后 IBeaconService.MSG_START_RANGING被执行
scanLeDevice
方法被调用ScanProcessor
和onLeScan
。
private class ScanProcessor extends AsyncTask<ScanData, Void, Void> { @Override protected Void doInBackground(ScanData... params) { ScanData scanData = params[0]; IBeacon iBeacon = IBeacon.fromScanData(scanData.scanRecord, scanData.rssi); if (iBeacon != null) { lastIBeaconDetectionTime = new Date(); trackedBeacons.add(iBeacon); Log.d(TAG, "iBeacon detected :"+iBeacon.getProximityUuid()+" "+iBeacon.getMajor()+" "+iBeacon.getMinor()+" accuracy: "+iBeacon.getAccuracy()+" proximity: "+iBeacon.getProximity()); List<Region> matchedRegions = matchingRegions(iBeacon, monitoredRegionState.keySet()); Iterator<Region> matchedRegionIterator = matchedRegions.iterator(); while (matchedRegionIterator.hasNext()) { Region region = matchedRegionIterator.next(); MonitorState state = monitoredRegionState.get(region); if (state.markInside()) { state.getCallback().call(IBeaconService.this, "monitoringData", new MonitoringData(state.isInside(), region)); } } Log.d(TAG, "looking for ranging region matches for this ibeacon"); matchedRegions = matchingRegions(iBeacon, rangedRegionState.keySet()); matchedRegionIterator = matchedRegions.iterator(); while (matchedRegionIterator.hasNext()) { Region region = matchedRegionIterator.next(); Log.d(TAG, "matches ranging region: "+region); RangeState rangeState = rangedRegionState.get(region); rangeState.addIBeacon(iBeacon); } } //I see a device: 00:02:72:C5:EC:33 with scan data: 02 01 1A 1A FF 4C 00 02 15 84 2A F9 C4 08 F5 11 E3 92 82 F2 3C 91 AE C0 5E D0 00 00 69 C5 0000000000000000000000000000000000000000000000000000000000000000 // // 9: proximityUuid (16 bytes) 84 2A F9 C4 08 F5 11 E3 92 82 F2 3C 91 AE C0 5E // 25: major (2 bytes unsigned int) // 27: minor (2 bytes unsigned int) // 29: tx power (1 byte signed int) return null; }
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { Log.d(TAG, "got record"); new ScanProcessor().execute(new ScanData(device, rssi, scanRecord)); } };
onLeScan
是Android的内部方法,可以得到byte[] 型的scanRecord和rssi,这两个交给ScanProcessor
。ScanProcessor
调用IBeacon.fromScanData(scanData.scanRecord, scanData.rssi),将这上两个数据转为IBeacon的bean。方法是:
/** * Construct an iBeacon from a Bluetooth LE packet collected by Android's Bluetooth APIs * * @param scanData The actual packet bytes * @param rssi The measured signal strength of the packet * @return An instance of an <code>IBeacon</code> */ public static IBeacon fromScanData(byte[] scanData, int rssi) { if (((int)scanData[5] & 0xff) == 0x4c && ((int)scanData[6] & 0xff) == 0x00 && ((int)scanData[7] & 0xff) == 0x02 && ((int)scanData[8] & 0xff) == 0x15) { // yes! This is an iBeacon // 可以确定是一个iBeacon设备 } else if (((int)scanData[5] & 0xff) == 0x2d && ((int)scanData[6] & 0xff) == 0x24 && ((int)scanData[7] & 0xff) == 0xbf && ((int)scanData[8] & 0xff) == 0x16) { // this is an Estimote beacon //可以确定是一个Estimote厂商的beacon设备 IBeacon iBeacon = new IBeacon(); iBeacon.major = 0; iBeacon.minor = 0; iBeacon.proximityUuid = "00000000-0000-0000-0000-000000000000"; iBeacon.txPower = -55; return iBeacon; } else { // This is not an iBeacon Log.d(TAG, "This is not an iBeacon advertisment. The bytes I see are: "+bytesToHex(scanData)); return null; } IBeacon iBeacon = new IBeacon(); iBeacon.major = (scanData[25] & 0xff) * 0x100 + (scanData[26] & 0xff); iBeacon.minor = (scanData[27] & 0xff) * 0x100 + (scanData[28] & 0xff); iBeacon.txPower = (int)scanData[29]; // this one is signed iBeacon.rssi = rssi; // AirLocate: // 02 01 1a 1a ff 4c 00 02 15 # Apple's fixed iBeacon advertising prefix // e2 c5 6d b5 df fb 48 d2 b0 60 d0 f5 a7 10 96 e0 # iBeacon profile uuid // 00 00 # major // 00 00 # minor // c5 # The 2's complement of the calibrated Tx Power // Estimote: // 02 01 1a 11 07 2d 24 bf 16 // 394b31ba3f486415ab376e5c0f09457374696d6f7465426561636f6e00000000000000000000000000000000000000000000000000 byte[] proximityUuidBytes = new byte[16]; System.arraycopy(scanData, 9, proximityUuidBytes, 0, 16); String hexString = bytesToHex(proximityUuidBytes); StringBuilder sb = new StringBuilder(); sb.append(hexString.substring(0,8)); sb.append("-"); sb.append(hexString.substring(8,12)); sb.append("-"); sb.append(hexString.substring(12,16)); sb.append("-"); sb.append(hexString.substring(16,20)); sb.append("-"); sb.append(hexString.substring(20,32)); iBeacon.proximityUuid = sb.toString(); return iBeacon; }
问题来了
上面这段代码中可以看到,对蓝牙扫描到的byte[]型的scanData数据解析是需要手动解析的,解析的规则各个厂家可能不一样。这断代码的作者对2种规则进行了解析,一种是标准iBeacon设备(应该是某协会或论坛的标准),另一种是Estimote公司的设备。如果你用了这个library,但自己的设备不能被找到,问题应该就出在这了。解决的方法就是去找到厂家的scanData的解析规则,然后解析。可以参考这个例子:Correct layout to detect Kontakt Beacon on Android with AltBeacon
在2.x版本的library上解决这个问题
以上问题在0.x版本上如何解决我没有尝试过,但是原理就是我上面所说的。在2.x版上,这个问题有比较好的解决方法:给她 beaconManager的BeaconParsers()添加一个BeaconLayout。
beaconManager.getBeaconParsers().add(new BeaconParser(). setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));//这个layout经过我的测试,原本2.x版本一个都找不出来的iBeacon设备全都找出来了,设备是我在淘宝买的,应该是标准解析方式。
可以参考这两个例子:
- Correct layout to detect Kontakt Beacon on Android with AltBeacon
- Is this the correct layout to detect iBeacons with AltBeacon’s Android Beacon Library?
- RadiusNetwork iBeacon Library For Android 设备发现过程梳理
- PCIe设备发现过程
- platform总线--驱动发现设备的过程
- 重大发现:MSDN for DOS - Microsoft Library 1.03
- Chat UI library for Android
- android 蓝牙之:ibeacon
- android 防丢器 ibeacon
- Android检测IBeacon热点
- Android iBeacon 开发
- Android模拟IBeacon周边
- Android知识点总结,学习过程梳理
- 信驰达微信iBeacon摇一摇周边方案ibeacon蓝牙设备
- 美国 Android 设备发现新型僵尸网络
- android bluetooth开发基础-5发现设备
- 局域网内android设备发现及通讯
- Android adb无法发现设备处理方法
- gupnp代码分析(二) gssdp即设备发现过程
- Ibeacon
- Hessian与REST性能测试
- cocos2dx使用googlebreakpad收集崩溃日志
- 【转】SLF4J 的几种实际应用模式--之三:JCL-Over-SLF4J+SLF4J
- oracle学习笔记,待续~
- hdu 3342 Legal or Not
- RadiusNetwork iBeacon Library For Android 设备发现过程梳理
- hdu oj 5000 Clone DP
- 修改filesystemio_options 引起的故障
- UI 登陆界面的写法
- C#中自定义异常类
- UML的基本概念【类图关系 依赖、关联、泛化、实现】
- <Head First Java>学习笔记--第二章:类与对象
- QList介绍
- 【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记12 Custom Views视图绘制1