RadiusNetwork iBeacon Library For Android 设备发现过程梳理
2015-04-14 18:54
483 查看
我所使用的时这个library的老版本,也就是0.x版。最新版是2.x了。
老版本:https://github.com/Vinayrraj/Android-iBeacon-Demo(service就是library源码,reference是例子)
使用这个library提供的例子时,发现永远只能显示我4个iBeacon设备中的1个。于是我跟了一下源码。设备发现的大概流程如下:
Region是包含uuid,marjor,minor等等的一个bean
可以参考这两个例子:
Correct layout to detect Kontakt Beacon on Android with AltBeacon
Is this the correct layout to detect iBeacons with AltBeacon’s Android Beacon Library?
老版本: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?
相关文章推荐
- Transmitting Network Data Using Volley - Volley is an HTTP library that makes networking for Android
- An Asynchronous HTTP Library for Android
- Codelab for Android Design Support Library used in I/O Rewind Bangkok session
- 深入学习:如何实现不同Android设备之间相同应用程序的网络服务发现功能
- 让你的安卓设备跑起kali——kali for android
- eclipse导入github上的android项目,出现unable to get system library for the project
- 以Android Library的方式使用<工程> for <Vitamio >
- android bluetooth开发基础-5发现设备
- ubuntu下android设备连接出现error: insufficient permissions for device 错误
- 使用网络服务发现(无线连接设备)——翻译自developer.android.com-Trainning
- 【常见错误】Android工程出现unable to get system library for the project异常问题
- Introduction to Glide, Image Loader Library for Android, recommended by Google
- 关于Eclipse for Android安装SDK过程中出现的错误——The import android.support cannot be resolved
- 使用QQ2013时连接Android物理设备Eclipse发现不了
- android开发过程中,测试apk进程对设备内存占用的一般方法
- android蓝牙开发:无法发现蓝牙设备的问题
- VLC for Android 编译过程
- chromium for android render进程创建过程分析
- Eclipse调试Android App若选择“Use same device for future launches”就再也无法选择其他设备的问题
- Android 6.0 Kotlin 蓝牙BLE扫描(改为指定时间没有发现新设备后停止扫描使用interface)