您的位置:首页 > 移动开发 > Android开发

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个。于是我跟了一下源码。设备发现的大概流程如下:

从这里出发

//开始计算设备距离
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?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐