Beacon 和 Eddystone 检测问题
Beacon and Eddystone detection issue
问题在于检测 IBeacon 和 Eddystone 框架,当我有 Eddystone 时,我必须使用特定功能,IBeacon 也是如此。
我在 Android Studio 中使用 Java,因此向我提供 IBeacon 结果的函数是 getManufatureSpecificData(),对于 Eddystone,是 getServiceData()。
问题是为什么有不同的功能来产生结果?以及如何检查接收到的帧是 Eddystone 还是 IBeacon?
代码片段
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
beaconManager.clean();
Log.i(TAG, "On batch called, size of result is : " + results.size());
for (int index = 0; index < results.size(); ++index) {
try {
ScanRecord mScanRecord = results.get(index).getScanRecord();
Map<ParcelUuid, byte[]> myMap = mScanRecord.getServiceData();
int mRsi = results.get(index).getRssi();
String url = "";
byte[] txPower = new byte[1];
byte[] nameSpaceId = new byte[10];
byte[] instanceId = new byte[6];
float distance;
for (Map.Entry<ParcelUuid, byte[]> eddystoneFrame : myMap.entrySet()) {
// for eddystone URL
if (eddystoneFrame.getValue()[0] == 16) {
url += urlSchemePrefix[eddystoneFrame.getValue()[2]];
for (int i = 3; i < eddystoneFrame.getValue().length - 1; i++) {
url += (char) eddystoneFrame.getValue()[i];
}
url += topLevelDomain[eddystoneFrame.getValue()[eddystoneFrame.getValue().length - 1]];
txPower[0] = eddystoneFrame.getValue()[1];
distance = (float) Utils.calculateDistance((int) txPower[0], (double) mRsi);
try {
beaconManager.addEddyBeacon(Utils.bytesToHex(nameSpaceId), Utils.bytesToHex(instanceId), distance);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
else if (eddystoneFrame.getValue()[0] == 0) {
// For Eddystone UID
System.arraycopy(eddystoneFrame.getValue(), 2, nameSpaceId, 0, nameSpaceId.length);
System.arraycopy(eddystoneFrame.getValue(), 12, instanceId, 0, instanceId.length);
System.arraycopy(eddystoneFrame.getValue(), 1, txPower, 0, txPower.length);
distance = (float) Utils.calculateDistance((int) txPower[0], (double) mRsi);
/** beaconList.add(new String[]{"Name Space ID : " + Utils.bytesToHex(nameSpaceId)+ "\n" + "Instance ID :" + Utils.bytesToHex(instanceId),
String.format("%.2f", distance),
"eddystoneuid"});**/
try {
beaconManager.addEddyBeacon(Utils.bytesToHex(nameSpaceId), Utils.bytesToHex(instanceId), distance);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
Log.i(TAG, "The size of the frame is: " + eddystoneFrame.getValue().length);
}
} catch (Exception e) {
Log.e("Error123456789", e.toString());
break;
}
}
Bluetooth SIG 标准机构定义了两种 Bluetooth LE 广告变体:
- GATT 服务广告 - 这些旨在宣传 GATT 服务并且可能具有服务数据字节,旨在告诉您有关广告服务的一些信息。
- 制造商广告 - 这些是为蓝牙设备制造商希望使用的任何目的而设计的。它们总是包含 0-24 字节的制造商数据。
Apple 在设计 iBeacon 格式时,选择使用制造商广告。因此,无论何时检测到它们,都必须获取制造商数据才能解码内容。
当Google设计Eddystone时,它选择不使用制造商广告,而是使用GATT服务广告。它做出这个选择是因为它希望他的格式在 iOS 设备上运行良好,并且 iOS 通常拒绝让第 3 方应用程序在后台检测制造商广告(iBeacon 除外)。
由于 Google 的设计决策,您在尝试解码 Eddystone 广告时必须检查是否有服务数据。
如果您想检测两种信标类型,请使用如下逻辑:
- 是否有附加服务数据?如果否,转到步骤 3。
- 服务数据可以解码为Eddystone吗?如果是,我们就完成了。
- 该广告是制造商广告吗?如果否,转到第 5 步。
- 制造商数据能否在iOS解码,如果是,我们就完成了。
- 广告既不是 Eddystone 也不是 iBeacon。
问题在于检测 IBeacon 和 Eddystone 框架,当我有 Eddystone 时,我必须使用特定功能,IBeacon 也是如此。 我在 Android Studio 中使用 Java,因此向我提供 IBeacon 结果的函数是 getManufatureSpecificData(),对于 Eddystone,是 getServiceData()。 问题是为什么有不同的功能来产生结果?以及如何检查接收到的帧是 Eddystone 还是 IBeacon?
代码片段
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
beaconManager.clean();
Log.i(TAG, "On batch called, size of result is : " + results.size());
for (int index = 0; index < results.size(); ++index) {
try {
ScanRecord mScanRecord = results.get(index).getScanRecord();
Map<ParcelUuid, byte[]> myMap = mScanRecord.getServiceData();
int mRsi = results.get(index).getRssi();
String url = "";
byte[] txPower = new byte[1];
byte[] nameSpaceId = new byte[10];
byte[] instanceId = new byte[6];
float distance;
for (Map.Entry<ParcelUuid, byte[]> eddystoneFrame : myMap.entrySet()) {
// for eddystone URL
if (eddystoneFrame.getValue()[0] == 16) {
url += urlSchemePrefix[eddystoneFrame.getValue()[2]];
for (int i = 3; i < eddystoneFrame.getValue().length - 1; i++) {
url += (char) eddystoneFrame.getValue()[i];
}
url += topLevelDomain[eddystoneFrame.getValue()[eddystoneFrame.getValue().length - 1]];
txPower[0] = eddystoneFrame.getValue()[1];
distance = (float) Utils.calculateDistance((int) txPower[0], (double) mRsi);
try {
beaconManager.addEddyBeacon(Utils.bytesToHex(nameSpaceId), Utils.bytesToHex(instanceId), distance);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
else if (eddystoneFrame.getValue()[0] == 0) {
// For Eddystone UID
System.arraycopy(eddystoneFrame.getValue(), 2, nameSpaceId, 0, nameSpaceId.length);
System.arraycopy(eddystoneFrame.getValue(), 12, instanceId, 0, instanceId.length);
System.arraycopy(eddystoneFrame.getValue(), 1, txPower, 0, txPower.length);
distance = (float) Utils.calculateDistance((int) txPower[0], (double) mRsi);
/** beaconList.add(new String[]{"Name Space ID : " + Utils.bytesToHex(nameSpaceId)+ "\n" + "Instance ID :" + Utils.bytesToHex(instanceId),
String.format("%.2f", distance),
"eddystoneuid"});**/
try {
beaconManager.addEddyBeacon(Utils.bytesToHex(nameSpaceId), Utils.bytesToHex(instanceId), distance);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
Log.i(TAG, "The size of the frame is: " + eddystoneFrame.getValue().length);
}
} catch (Exception e) {
Log.e("Error123456789", e.toString());
break;
}
}
Bluetooth SIG 标准机构定义了两种 Bluetooth LE 广告变体:
- GATT 服务广告 - 这些旨在宣传 GATT 服务并且可能具有服务数据字节,旨在告诉您有关广告服务的一些信息。
- 制造商广告 - 这些是为蓝牙设备制造商希望使用的任何目的而设计的。它们总是包含 0-24 字节的制造商数据。
Apple 在设计 iBeacon 格式时,选择使用制造商广告。因此,无论何时检测到它们,都必须获取制造商数据才能解码内容。
当Google设计Eddystone时,它选择不使用制造商广告,而是使用GATT服务广告。它做出这个选择是因为它希望他的格式在 iOS 设备上运行良好,并且 iOS 通常拒绝让第 3 方应用程序在后台检测制造商广告(iBeacon 除外)。
由于 Google 的设计决策,您在尝试解码 Eddystone 广告时必须检查是否有服务数据。
如果您想检测两种信标类型,请使用如下逻辑:
- 是否有附加服务数据?如果否,转到步骤 3。
- 服务数据可以解码为Eddystone吗?如果是,我们就完成了。
- 该广告是制造商广告吗?如果否,转到第 5 步。
- 制造商数据能否在iOS解码,如果是,我们就完成了。
- 广告既不是 Eddystone 也不是 iBeacon。