在棉花糖中获取蓝牙本地mac地址

Posted

技术标签:

【中文标题】在棉花糖中获取蓝牙本地mac地址【英文标题】:Get Bluetooth local mac address in Marshmallow 【发布时间】:2016-01-27 10:55:16 【问题描述】:

Pre Marshmallow 我的应用程序将通过BluetoothAdapter.getDefaultAdapter().getAddress(). 获取它的设备 MAC 地址

现在有了 Marshmallow,android 将返回 02:00:00:00:00:00

我看到一些链接(抱歉,现在不确定在哪里)说您需要添加额外的权限

<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"/> 

能够得到它。但是它对我不起作用。

获取mac地址是否需要一些额外的权限?

我不确定这里是否相关,但清单中还包括

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

那么有没有办法获取本地蓝牙mac地址呢?

【问题讨论】:

【参考方案1】:

对mac地址的访问被特意去掉了:

为了向用户提供更好的数据保护,从这个版本开始,Android 移除了使用 Wi-Fi 和蓝牙 API 的应用程序对设备本地硬件标识符的编程访问。

(来自Android 6.0 Changes)

【讨论】:

是的。我读过那个。但是 API 23 BluetoothAdapter 具有以下内容: /** * 默认 MAC 地址报告给没有 * android.permission.LOCAL_MAC_ADDRESS 权限的客户端。 * * @hide */ public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";所以这意味着有某种方法可以得到它。 (也许还没有实施?我抱有希望。) LOCAL_MAC_ADDRESS 权限只能由系统应用使用,Google 不太可能改变这一点。【参考方案2】:

您可以从文件中访问 Mac 地址 "/sys/class/net/" + networkInterfaceName+ "/address",其中networkInterfaceName可以是wlan0或者eth1,但是它的权限可能是读保护的,所以可能无法在某些设备中使用。 我还附上了我从 SO 获得的代码部分。

public static String getWifiMacAddress() 
        try 
            String interfaceName = "wlan0";
            List<NetworkInterface> interfaces = Collections
                    .list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface intf : interfaces) 
                if (!intf.getName().equalsIgnoreCase(interfaceName)) 
                    continue;
                

                byte[] mac = intf.getHardwareAddress();
                if (mac == null) 
                    return "";
                

                StringBuilder buf = new StringBuilder();
                for (byte aMac : mac) 
                    buf.append(String.format("%02X:", aMac));
                
                if (buf.length() > 0) 
                    buf.deleteCharAt(buf.length() - 1);
                
                return buf.toString();
            
         catch (Exception exp) 

            exp.printStackTrace();
         
        return "";
    

【讨论】:

谢谢。它适用于我尝试过的 Nexus 平板电脑。 Android N 及更高版本也将使用此方法返回错误的 MAC 地址。 我测试的两台设备都有两个甚至略有不同的 WiFi 和蓝牙 MAC 地址... 我在 android 10 上试过这个方法,效果很好,但是正如你所说,这是本地 wifi mac 地址,有没有办法使用这样的方法获取蓝牙 mac 地址?【参考方案3】:

zmarties 是对的,但你仍然可以通过反射或 Settings.Secure 获取 mac 地址:

  String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");

【讨论】:

wifi地址呢? ,你能处理一下mac地址吗? 这给出了不同的 bdaddr(但一个有效的 mac)。反射方法给出正确的 bdaddr。 @Rilwan 对隐藏/列入黑名单的 API 使用反射会使您的应用在下一次操作系统更新时崩溃,这永远不是正确的解决方案,只是临时解决方法。 android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address") 在 Android 10 中返回 null【参考方案4】:

通过反射获取 MAC 地址如下所示:

private static String getBtAddressViaReflection() 
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    Object bluetoothManagerService = new Mirror().on(bluetoothAdapter).get().field("mService");
    if (bluetoothManagerService == null) 
        Log.w(TAG, "couldn't find bluetoothManagerService");
        return null;
    
    Object address = new Mirror().on(bluetoothManagerService).invoke().method("getAddress").withoutArgs();
    if (address != null && address instanceof String) 
        Log.w(TAG, "using reflection to get the BT MAC address: " + address);
        return (String) address;
     else 
        return null;
    

使用反射库 (net.vidageek:mirror),但您会明白的。

【讨论】:

代码不起作用。使用该库,它总是在具有不同 API 级别的服务器上返回 null 我只是在一些设备上尝试了代码,但总是得到一个 mac 地址(在 4.4、5.0、5.1 和 6.0 的设备上使用 targetSDK 22 进行了测试) 在 Android 8.0 Oreo 的 Pixel 2 版本上,此方法将不再有效。我收到 java.lang.reflect.InvocationTargetException 原因:java.lang.SecurityException:需要 LOCAL_MAC_ADDRESS 权限:用户 10141 和当前进程都没有 android.permission.LOCAL_MAC_ADDRESS。 Google 似乎已将“修复”推广到任何安装 Android 8.1 的设备。更新到 8.1 预览版的 Nexus 5X 也有例外。作为一个小小的安慰,Google 已经开始在蓝牙设置 UI 中显示自己的蓝牙 MAC,因此至少用户可以手动将其复制到需要它的应用中。 我可以确认手动输入然后使用 MAC 地址对我的应用程序建立无对连接有效。【参考方案5】:

事实证明,我最终没有从 Android 获取 MAC 地址。蓝牙设备最终提供了 Android 设备 MAC 地址,该地址被存储并在需要时使用。是的,这似乎有点古怪,但在我参与的项目中,蓝牙设备软件也在开发中,结果证明这是处理这种情况的最佳方式。

【讨论】:

【参考方案6】:

请使用以下代码获取蓝牙mac地址。如果有任何问题,请告诉我。

private String getBluetoothMacAddress() 
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    String bluetoothMacAddress = "";
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
        try 
            Field mServiceField = bluetoothAdapter.getClass().getDeclaredField("mService");
            mServiceField.setAccessible(true);

            Object btManagerService = mServiceField.get(bluetoothAdapter);

            if (btManagerService != null) 
                bluetoothMacAddress = (String) btManagerService.getClass().getMethod("getAddress").invoke(btManagerService);
            
         catch (NoSuchFieldException e) 

         catch (NoSuchMethodException e) 

         catch (IllegalAccessException e) 

         catch (InvocationTargetException e) 

        
     else 
        bluetoothMacAddress = bluetoothAdapter.getAddress();
    
    return bluetoothMacAddress;

【讨论】:

提示:使用列入黑名单的 API 的反思从来都不是好的解决方案,它可能会在下一次 Android 更新时打击你【参考方案7】:

首先必须将以下权限添加到 Manifest;

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />

那么,

public static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";

String macAddress = Settings.Secure.getString(getContentResolver(), SECURE_SETTINGS_BLUETOOTH_ADDRESS);

之后,必须使用 OEM / 系统密钥对应用程序进行签名。在 Android 8.1.0 上测试和验证。

【讨论】:

在 Android 10 中,还需要权限 @Kotdroid 您是否使用 OEM / 系统密钥签署了 APK? 怎么办?能否请您详细告诉我。我在调试版本中使用了这个。 @Kotdroid 签名取决于 OEM。如果您是 OEM,请咨询您的系统团队。普通应用开发者无权访问 OEM 密钥。谢谢。 LOCAL_MAC_ADDRESS - 它显示警告清单,例如仅由系统应用授予的权限【参考方案8】:

效果很好

 private String getBluetoothMacAddress() 
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        String bluetoothMacAddress = "";
        try 
            Field mServiceField = bluetoothAdapter.getClass().getDeclaredField("mService");
            mServiceField.setAccessible(true);

            Object btManagerService = mServiceField.get(bluetoothAdapter);

            if (btManagerService != null) 
                bluetoothMacAddress = (String) btManagerService.getClass().getMethod("getAddress").invoke(btManagerService);
            
         catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignore) 

        
        return bluetoothMacAddress;
    

【讨论】:

Field @Vinayak 的包名是什么我发现有很多 Field 类。 @Iqbalhossain 这是java.lang.reflect.Field【参考方案9】:

由于下面的方法为 android O 返回 null。

String macAddress = android.provider.Settings.Secure.getString(context.getContentResolver(), "bluetooth_address");

我找到了获取蓝牙Mac地址的新方法,您可以使用下面的命令行尝试。

su strings /data/misc/bluedroid/bt_config.conf | grep Address

注意:就我而言,我使用的是 root 设备,因此我的应用拥有超级用户权限。

【讨论】:

以上是关于在棉花糖中获取蓝牙本地mac地址的主要内容,如果未能解决你的问题,请参考以下文章

iOS 蓝牙连接获取MAC地址的方法

iOS 蓝牙获取MAC地址

IOS怎么获取蓝牙连接到的设备的MAC地址,私有方法也可以

安卓蓝牙-MAC地址

使用 BluetoothManager 私有框架获取蓝牙的 MAC 地址

获取蓝牙低功耗外设的MAC地址