Android下如何通过Extended Inquiry Response过滤经典蓝牙设备?
获取Android经典蓝牙Extended Inquiry Response(EIR)的方案
现状说明
Android公开API并未直接提供获取经典蓝牙EIR数据的接口,BluetoothDevice类的公开方法无法直接获取厂商特定值这类EIR中的细节信息。但可以通过反射访问系统隐藏的内部实现来获取,JNI调用底层蓝牙栈的方案需要特殊权限,不推荐普通应用使用。
反射获取并解析EIR的示例
1. 反射获取EIR字节数组
通过反射访问BluetoothDevice内部的隐藏字段或方法,获取原始EIR数据:
import java.lang.reflect.Field; import java.lang.reflect.Method; import android.bluetooth.BluetoothDevice; private byte[] retrieveEirData(BluetoothDevice device) { // 尝试读取mEir字段(适配部分Android版本) try { Field eirField = BluetoothDevice.class.getDeclaredField("mEir"); eirField.setAccessible(true); return (byte[]) eirField.get(device); } catch (NoSuchFieldException | IllegalAccessException e) { // 尝试调用getExtendedInquiryResponse()方法(适配其他版本) try { Method eirMethod = BluetoothDevice.class.getDeclaredMethod("getExtendedInquiryResponse"); eirMethod.setAccessible(true); return (byte[]) eirMethod.invoke(device); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { ex.printStackTrace(); return null; } } }
2. 解析EIR中的厂商特定值
EIR采用TLV(Type-Length-Value)格式存储数据,厂商特定值的类型标识为0xFF,解析代码如下:
private byte[] extractManufacturerData(byte[] eirData) { if (eirData == null || eirData.length == 0) { return null; } int offset = 0; while (offset < eirData.length) { int itemLength = eirData[offset] & 0xFF; if (itemLength == 0) { break; } int itemType = eirData[offset + 1] & 0xFF; // 匹配厂商特定值类型 if (itemType == 0xFF) { byte[] manufacturerData = new byte[itemLength - 1]; System.arraycopy(eirData, offset + 2, manufacturerData, 0, itemLength - 1); return manufacturerData; } offset += itemLength + 1; } return null; }
3. 判断是否为Android设备
厂商特定值的前两个字节是厂商ID,Google的厂商ID为0x00E0(小端存储为0xE0, 0x00),可通过此过滤Android设备:
private boolean isAndroidDevice(byte[] manufacturerData) { if (manufacturerData == null || manufacturerData.length < 2) { return false; } // 检查厂商ID是否为Google(0x00E0,小端字节序) return manufacturerData[0] == (byte) 0xE0 && manufacturerData[1] == (byte) 0x00; }
使用流程与权限要求
- 权限申请:
- Android 11及以下:需要
BLUETOOTH、BLUETOOTH_ADMIN权限,部分设备需ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限才能扫描蓝牙设备。 - Android 12+:需要
BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限,同样可能需要定位权限。
- Android 11及以下:需要
- 扫描回调中使用:
在BluetoothAdapter.OnDiscoveryListener的onDeviceFound回调中,拿到BluetoothDevice实例后,调用上述方法获取并解析EIR数据。
局限性
- 反射依赖Android系统的内部实现,不同版本的系统可能修改字段名或方法名,需针对不同版本做适配。
- 部分厂商定制ROM可能限制反射访问系统内部API,导致方法失效。
内容的提问来源于stack exchange,提问作者bagya gunawardana
相关产品推荐
相关产品推荐

