如何识别EddystoneURL和uid?
How to identify Eddystone URL and uid?
我希望在不使用 Proximity Beacon API 或 Nearby Messages API 的情况下检测 Eddystone Ul 和 uid。我希望使用原生 android 库,如 BluetoothAdapter 或 BluetoothGatt 或 BluetoothGap 来解析 eddystone 帧。这可行吗?如果是这样的话,如果不可行,那么还有什么选择呢?
所有 Eddystone 数据都包含在蓝牙 4.0 ("Low Energy," "BLE") 广告数据包中,因此不需要 BluetoothGatt
或 BluetoothGap
。请改用 BluetoothLeScanner
。在 onScanResult
回调中,您可以通过以下方式访问广告数据:
// assuming `result` is the ScanResult passed to the `onScanResult` callback
byte[] rawData = result
.getScanRecord()
.getServiceData(ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB"));
然后,您需要根据 Eddystone 规范解析字节:
UID:
https://github.com/google/eddystone/tree/master/eddystone-uid
URL:
https://github.com/google/eddystone/tree/master/eddystone-url
Eddystone 存储库中还包含一个示例项目,因此您可以从那里开始,也许可以重用一些代码:
https://github.com/google/eddystone/tree/master/tools/eddystone-validator
您可以使用本机 Android onLeScan
回调检测 Eddystone-UID 信标。我在此处的答案中发布了示例代码,展示了如何执行此操作:
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
for (int startByte = 0; startByte < scanRecord.length; startByte++) {
if (scanRecord.length-startByte > 19) { // need at least 19 bytes for Eddystone-UID
// Check that this has the right pattern needed for this to be Eddystone-UID
if (scanRecord[startByte+0] == 0xaa && scanRecord[startByte+1] == 0xfe &&
scanRecord[startByte+2] == 0x00) {
// This is an Eddystone-UID beacon.
byte[] namespaceIdentifierBytes = Arrays.copyOfRange(scanRecord, startByte+4, startByte+13);
byte[] instanceIdentifierBytes = Arrays.copyOfRange(scanRecord, startByte+14, startByte+19);
// TODO: do something with the above identifiers here
}
}
}
}
这样做的关键是理解和解析每种信标类型的字节布局。这就是开源 Android Beacon Library 通过为每个信标定义布局表达式来帮助解析来解析多种信标类型(如 Eddystone)的方式。即使您想推出自己的代码,也可以查看其源代码并使用它来了解其工作原理。我已经在上面链接的答案中发布了关于这种解析如何发生的描述。
以下是获取有关 Eddystone AFAIK 信息的最简单方法。
// onLeScan() method of BluetoothAdapter.LeScanCallback interface.
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
{
// Parse the payload of the advertisement packet
// as a list of AD structures.
List<ADStructure> structures =
ADPayloadParser.getInstance().parse(scanRecord);
// For each AD structure contained in the advertisement packet.
for (ADStructure structure : structures)
{
// If the AD structure represents Eddystone UID.
if (structure instanceof EddystoneUID)
{
// Eddystone UID
EddystoneUID es = (EddystoneUID)structure;
Log.d(TAG, "Tx Power = " + es.getTxPower());
Log.d(TAG, "Namespace ID = " + es.getNamespaceIdAsString());
Log.d(TAG, "Instance ID = " + es.getInstanceIdAsString());
Log.d(TAG, "Beacon ID = " + es.getBeaconIdAsString());
// As byte arrays if you want.
byte[] namespaceId = es.getNamespaceId();
byte[] instanceId = es.getInstanceId();
byte[] beaconId = es.getBeaconId();
}
// If the AD structure represents Eddystone URL.
else if (structure instanceof EddystoneURL)
{
// Eddystone URL
EddystoneURL es = (EddystoneURL)structure;
Log.d(TAG, "Tx Power = " + es.getTxPower());
Log.d(TAG, "URL = " + es.getURL());
}
// If the AD structure represents Eddystone TLM.
else if (structure instanceof EddystoneTLM)
{
// Eddystone TLM
EddystoneTLM es = (EddystoneTLM)structure;
Log.d(TAG, "TLM Version = " + es.getTLMVersion());
Log.d(TAG, "Battery Voltage = " + es.getBatteryVoltage());
Log.d(TAG, "Beacon Temperature = " + es.getBeaconTemperature());
Log.d(TAG, "Advertisement Count = " + es.getAdvertisementCount());
Log.d(TAG, "Elapsed Time = " + es.getElapsedTime());
}
}
}
您不必了解 Eddystone specification if you use nv-bluetooth.
的详细信息
Gradle
dependencies {
compile 'com.neovisionaries:nv-bluetooth:1.7'
}
Java文档
备忘录
Eddystone TLM is expressed in a signed fixed-point notation. The code examples in How to detect Eddystone-Compatible Beacons (Android Beacon Library) don't show how to extract the data as a floating point number as of this writing. On the other hand, <a href="http://takahikokawasaki.github.io/nv-bluetooth/com/neovisionaries/bluetooth/ble/advertising/EddystoneTLM.html" rel="nofollow">EddystoneTLM</a>
class中的Beacon Temperature在nv-bluetooth中有如下所示的方法,因此您不必解码定点符号。
public float getBeaconTemperature();
同样,<a href="http://takahikokawasaki.github.io/nv-bluetooth/com/neovisionaries/bluetooth/ble/advertising/EddystoneURL.html" rel="nofollow">EddystoneURL</a>
class 有一种方法可以将 URL 作为 URL
.
public URL getURL();
因此,当您使用 Android 信标库时,您不必执行如下所示的步骤。
String url = UrlBeaconUrlCompressor.uncompress(beacon.getId1().toByteArray());
nv-bluetooth将Eddystone相关的数据结构实现为继承树,如下图。这种合适的继承树在其他库中很难找到。
ADStructure
|
+-- ServiceData
|
+-- Eddystone
|
+-- EddystoneUID
|
+-- EddystoneURL
|
+-- EddystoneTLM
适当的继承树的好处之一是方法被放置在正确的位置。像这样:
ADStructure
| // AD Structure Length - 1
| int getLength();
|
| // AD Type
| int getType();
|
| // AD Data
| byte[] getData();
|
+-- ServiceData
| | // Service UUID
| | UUID getServiceUUID();
| |
| +-- Eddystone
| | // Eddystone Frame Type
| | FrameType getFrameType();
| |
| +-- EddystoneUID
| | // Tx Power
| | int getTxPower();
| |
| | // Namespace ID (byte[])
| | byte[] getNamespaceId();
| |
| | // Instance ID (byte[])
| | byte[] getInstanceId();
| |
| | // Beacon ID (byte[])
| | byte[] getBeaconId();
| |
| | // Namespace ID (String)
| | String getNamespaceIdAsString();
| |
| | // Instance ID (String)
| | String getInstanceIdAsString();
| |
| | // Beacon ID (String)
| | String getBeaconIdAsString();
| |
| +-- EddystoneURL
| | // Tx Power
| | int getTxPower();
| |
| | // URL
| | URL getURL();
| |
| +-- EddystoneTLM
| // TLM Version
| int getTLMVersion();
|
| // Battery Voltage
| int getBatteryVoltage();
|
| // Beacon Temperature
| float getBeaconTemperature();
|
| // Advertisement Count
| long getAdvertisementCount();
|
| // Elapsed Time
| long getElapsedTime();
|
+-- ADManufacturerSpecific
| | // Company ID
| | int getCompanyId();
| |
| +-- IBeacon
| | // Major Number
| | int getMajor();
| |
| | (abbrev)
| |
| +-- Ucode
| | // Ucode
| | String getUcode();
| |
| | (abbrev)
我希望在不使用 Proximity Beacon API 或 Nearby Messages API 的情况下检测 Eddystone Ul 和 uid。我希望使用原生 android 库,如 BluetoothAdapter 或 BluetoothGatt 或 BluetoothGap 来解析 eddystone 帧。这可行吗?如果是这样的话,如果不可行,那么还有什么选择呢?
所有 Eddystone 数据都包含在蓝牙 4.0 ("Low Energy," "BLE") 广告数据包中,因此不需要 BluetoothGatt
或 BluetoothGap
。请改用 BluetoothLeScanner
。在 onScanResult
回调中,您可以通过以下方式访问广告数据:
// assuming `result` is the ScanResult passed to the `onScanResult` callback
byte[] rawData = result
.getScanRecord()
.getServiceData(ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB"));
然后,您需要根据 Eddystone 规范解析字节:
UID:
https://github.com/google/eddystone/tree/master/eddystone-uid
URL:
https://github.com/google/eddystone/tree/master/eddystone-url
Eddystone 存储库中还包含一个示例项目,因此您可以从那里开始,也许可以重用一些代码:
https://github.com/google/eddystone/tree/master/tools/eddystone-validator
您可以使用本机 Android onLeScan
回调检测 Eddystone-UID 信标。我在此处的答案中发布了示例代码,展示了如何执行此操作:
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
for (int startByte = 0; startByte < scanRecord.length; startByte++) {
if (scanRecord.length-startByte > 19) { // need at least 19 bytes for Eddystone-UID
// Check that this has the right pattern needed for this to be Eddystone-UID
if (scanRecord[startByte+0] == 0xaa && scanRecord[startByte+1] == 0xfe &&
scanRecord[startByte+2] == 0x00) {
// This is an Eddystone-UID beacon.
byte[] namespaceIdentifierBytes = Arrays.copyOfRange(scanRecord, startByte+4, startByte+13);
byte[] instanceIdentifierBytes = Arrays.copyOfRange(scanRecord, startByte+14, startByte+19);
// TODO: do something with the above identifiers here
}
}
}
}
这样做的关键是理解和解析每种信标类型的字节布局。这就是开源 Android Beacon Library 通过为每个信标定义布局表达式来帮助解析来解析多种信标类型(如 Eddystone)的方式。即使您想推出自己的代码,也可以查看其源代码并使用它来了解其工作原理。我已经在上面链接的答案中发布了关于这种解析如何发生的描述。
以下是获取有关 Eddystone AFAIK 信息的最简单方法。
// onLeScan() method of BluetoothAdapter.LeScanCallback interface.
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
{
// Parse the payload of the advertisement packet
// as a list of AD structures.
List<ADStructure> structures =
ADPayloadParser.getInstance().parse(scanRecord);
// For each AD structure contained in the advertisement packet.
for (ADStructure structure : structures)
{
// If the AD structure represents Eddystone UID.
if (structure instanceof EddystoneUID)
{
// Eddystone UID
EddystoneUID es = (EddystoneUID)structure;
Log.d(TAG, "Tx Power = " + es.getTxPower());
Log.d(TAG, "Namespace ID = " + es.getNamespaceIdAsString());
Log.d(TAG, "Instance ID = " + es.getInstanceIdAsString());
Log.d(TAG, "Beacon ID = " + es.getBeaconIdAsString());
// As byte arrays if you want.
byte[] namespaceId = es.getNamespaceId();
byte[] instanceId = es.getInstanceId();
byte[] beaconId = es.getBeaconId();
}
// If the AD structure represents Eddystone URL.
else if (structure instanceof EddystoneURL)
{
// Eddystone URL
EddystoneURL es = (EddystoneURL)structure;
Log.d(TAG, "Tx Power = " + es.getTxPower());
Log.d(TAG, "URL = " + es.getURL());
}
// If the AD structure represents Eddystone TLM.
else if (structure instanceof EddystoneTLM)
{
// Eddystone TLM
EddystoneTLM es = (EddystoneTLM)structure;
Log.d(TAG, "TLM Version = " + es.getTLMVersion());
Log.d(TAG, "Battery Voltage = " + es.getBatteryVoltage());
Log.d(TAG, "Beacon Temperature = " + es.getBeaconTemperature());
Log.d(TAG, "Advertisement Count = " + es.getAdvertisementCount());
Log.d(TAG, "Elapsed Time = " + es.getElapsedTime());
}
}
}
您不必了解 Eddystone specification if you use nv-bluetooth.
的详细信息Gradle
dependencies {
compile 'com.neovisionaries:nv-bluetooth:1.7'
}
Java文档
备忘录
Eddystone TLM is expressed in a signed fixed-point notation. The code examples in How to detect Eddystone-Compatible Beacons (Android Beacon Library) don't show how to extract the data as a floating point number as of this writing. On the other hand, <a href="http://takahikokawasaki.github.io/nv-bluetooth/com/neovisionaries/bluetooth/ble/advertising/EddystoneTLM.html" rel="nofollow">EddystoneTLM</a>
class中的Beacon Temperature在nv-bluetooth中有如下所示的方法,因此您不必解码定点符号。
public float getBeaconTemperature();
同样,<a href="http://takahikokawasaki.github.io/nv-bluetooth/com/neovisionaries/bluetooth/ble/advertising/EddystoneURL.html" rel="nofollow">EddystoneURL</a>
class 有一种方法可以将 URL 作为 URL
.
public URL getURL();
因此,当您使用 Android 信标库时,您不必执行如下所示的步骤。
String url = UrlBeaconUrlCompressor.uncompress(beacon.getId1().toByteArray());
nv-bluetooth将Eddystone相关的数据结构实现为继承树,如下图。这种合适的继承树在其他库中很难找到。
ADStructure
|
+-- ServiceData
|
+-- Eddystone
|
+-- EddystoneUID
|
+-- EddystoneURL
|
+-- EddystoneTLM
适当的继承树的好处之一是方法被放置在正确的位置。像这样:
ADStructure
| // AD Structure Length - 1
| int getLength();
|
| // AD Type
| int getType();
|
| // AD Data
| byte[] getData();
|
+-- ServiceData
| | // Service UUID
| | UUID getServiceUUID();
| |
| +-- Eddystone
| | // Eddystone Frame Type
| | FrameType getFrameType();
| |
| +-- EddystoneUID
| | // Tx Power
| | int getTxPower();
| |
| | // Namespace ID (byte[])
| | byte[] getNamespaceId();
| |
| | // Instance ID (byte[])
| | byte[] getInstanceId();
| |
| | // Beacon ID (byte[])
| | byte[] getBeaconId();
| |
| | // Namespace ID (String)
| | String getNamespaceIdAsString();
| |
| | // Instance ID (String)
| | String getInstanceIdAsString();
| |
| | // Beacon ID (String)
| | String getBeaconIdAsString();
| |
| +-- EddystoneURL
| | // Tx Power
| | int getTxPower();
| |
| | // URL
| | URL getURL();
| |
| +-- EddystoneTLM
| // TLM Version
| int getTLMVersion();
|
| // Battery Voltage
| int getBatteryVoltage();
|
| // Beacon Temperature
| float getBeaconTemperature();
|
| // Advertisement Count
| long getAdvertisementCount();
|
| // Elapsed Time
| long getElapsedTime();
|
+-- ADManufacturerSpecific
| | // Company ID
| | int getCompanyId();
| |
| +-- IBeacon
| | // Major Number
| | int getMajor();
| |
| | (abbrev)
| |
| +-- Ucode
| | // Ucode
| | String getUcode();
| |
| | (abbrev)