You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

使用流程与权限要求

  1. 权限申请:
    • Android 11及以下:需要BLUETOOTH、BLUETOOTH_ADMIN权限,部分设备需ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限才能扫描蓝牙设备。
    • Android 12+:需要BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限,同样可能需要定位权限。
  2. 扫描回调中使用:
    在BluetoothAdapter.OnDiscoveryListener的onDeviceFound回调中,拿到BluetoothDevice实例后,调用上述方法获取并解析EIR数据。

局限性

  • 反射依赖Android系统的内部实现,不同版本的系统可能修改字段名或方法名,需针对不同版本做适配。
  • 部分厂商定制ROM可能限制反射访问系统内部API,导致方法失效。

内容的提问来源于stack exchange,提问作者bagya gunawardana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 11:40:31