在Android 6.0中获取MAC地址

42

我正在开发一个获取设备MAC地址的应用程序,但自从Android 6.0后,我的代码不起作用了,给我返回了错误的值。

以下是我的代码...

public String ObtenMAC()
{
    WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    WifiInfo info = manager.getConnectionInfo();

    return(info.getMacAddress().toUpperCase());
}

它返回了一个奇怪的代码 02:00:00:00:00:00,而不是真实的MAC地址。


你确定在获取MAC地址之前检查了ACCESS_WIFI_STATE吗?在M版本中,如果你只在清单文件中请求它,是行不通的,你必须像这样在运行时实现:https://www.youtube.com/watch?v=C8lUdPVSzDk&index=3&list=PLWz5rJ2EKKc-lJo_RGGXL2Psr8vVCTWjM - Ichor de Dionysos
谢谢你的回答。我在清单文件中有这个权限,但是当我像视频中所示那样以编程方式检查它时,Android Studio无法识别“checkSelfPermission”,我不知道是否因为我针对API 21棒棒糖并未安装API 23棉花糖。 - Mazinger
在调用checkSelfPermission之前,您应该检查SDK版本是否小于API 23 Marshmallow,就像这里所示:https://dev59.com/jXA75IYBdhLWcg3wMmCo - Ichor de Dionysos
在目标级别上拥有最新的Android API版本总是很好的。 - Ichor de Dionysos
2
请检查这个解决方案,它对我有效。https://dev59.com/1l0Z5IYBdhLWcg3wiw0v - Gorio
11个回答

35
请参考Android 6.0 变更
为了为用户提供更好的数据保护,自此版本开始,Android已经移除了对使用Wi-Fi和蓝牙API的应用程序获取设备本地硬件标识符的编程访问。WifiInfo.getMacAddress()和BluetoothAdapter.getAddress()方法现在返回一个常量值02:00:00:00:00:00。
要通过蓝牙和Wi-Fi扫描访问附近外部设备的硬件标识符,您的应用程序现在必须拥有ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION权限。

11
我在我的应用程序上拥有这些权限,但仍然无法工作。 - Hrodger
8
@Hrodger,即使拥有那些权限,你也无法获取自己的MAC地址。仔细阅读。它说的是你可以获取其他设备的MAC地址,但不能获取你自己的。 - Vladyslav Matviienko
4
没办法做到吗? - Hrodger
3
显然,您仍然可以通过java.net.NetworkInterface获取MAC地址。是的,我非常看好Google开发人员的能力;)。 - begemotv2718

27

使用下面的代码在Android 6.0中获取Mac地址

public static String getMacAddr() {
    try {
        List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
        for (NetworkInterface nif : all) {
            if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

            byte[] macBytes = nif.getHardwareAddress();
            if (macBytes == null) {
                return "";
            }

            StringBuilder res1 = new StringBuilder();
            for (byte b : macBytes) {
                res1.append(Integer.toHexString(b & 0xFF) + ":");
            }

            if (res1.length() > 0) {
                res1.deleteCharAt(res1.length() - 1);
            }
            return res1.toString();
        }
    } catch (Exception ex) {
        //handle exception
    }
    return "";
}

7
以上答案取自以下博客文章:http://robinhenniges.com/en/android6-get-mac-address-programmatically - zerobandwidth
9
这个答案有一个bug,当一个字节的十六进制形式只有一位数字时,它前面不会出现“0”。将附加到res1的部分更改为res1.append(String.format("%02X:",b));。 - CodeMonkey
2
同样适用于Android 7。 - Stephen M -on strike-
WiFi的MAC地址并不总是与蓝牙接口相同。在我的手机上,只有前三个八位字节匹配(顺便提一下,这些字节可以告诉你制造商信息)。 - AgainPsychoX

15

我没能让上面的答案起作用,但是偶然发现了另一个答案。

这里有一个完整简单的方法可以获取IPv6地址,并从中获取mac地址。

如何在Android Marshmallow中获取Wi-Fi Mac地址

public static String getMacAddr() {
    try {
        List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
        for (NetworkInterface nif : all) {
            if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

            byte[] macBytes = nif.getHardwareAddress();
            if (macBytes == null) {
                return "";
            }

            StringBuilder res1 = new StringBuilder();
            for (byte b : macBytes) {
                res1.append(String.format("%02X:",b));
            }

            if (res1.length() > 0) {
                res1.deleteCharAt(res1.length() - 1);
            }
            return res1.toString();
        }
    } catch (Exception ex) {
    }
    return "02:00:00:00:00:00";
}

我已经测试过了,它可以正常工作。非常感谢Rob Anderson!


2
谢谢,正如其他地方所述,这需要<uses-permission android:name="android.permission.INTERNET" />才能工作。 - lejonl

11

这是在Marshmallow上成功获取它的完整代码,只需复制粘贴即可运行!

//Android 6.0 : Access to mac address from WifiManager forbidden
    private static final String marshmallowMacAddress = "02:00:00:00:00:00";
    private static final String fileAddressMac = "/sys/class/net/wlan0/address";    

public static String recupAdresseMAC(WifiManager wifiMan) {
        WifiInfo wifiInf = wifiMan.getConnectionInfo();

        if(wifiInf.getMacAddress().equals(marshmallowMacAddress)){
            String ret = null;
            try {
                ret= getAdressMacByInterface();
                if (ret != null){
                    return ret;
                } else {
                    ret = getAddressMacByFile(wifiMan);
                    return ret;
                }
            } catch (IOException e) {
                Log.e("MobileAccess", "Erreur lecture propriete Adresse MAC");
            } catch (Exception e) {
                Log.e("MobileAcces", "Erreur lecture propriete Adresse MAC ");
            }
        } else{
            return wifiInf.getMacAddress();
        }
        return marshmallowMacAddress;
    }

private static String getAdressMacByInterface(){
        try {
            List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (nif.getName().equalsIgnoreCase("wlan0")) {
                    byte[] macBytes = nif.getHardwareAddress();
                    if (macBytes == null) {
                        return "";
                    }

                    StringBuilder res1 = new StringBuilder();
                    for (byte b : macBytes) {
                        res1.append(String.format("%02X:",b));
                    }

                    if (res1.length() > 0) {
                        res1.deleteCharAt(res1.length() - 1);
                    }
                    return res1.toString();
                }
            }

        } catch (Exception e) {
            Log.e("MobileAcces", "Erreur lecture propriete Adresse MAC ");
        }
        return null;
    }

private static String getAddressMacByFile(WifiManager wifiMan) throws Exception {
        String ret;
        int wifiState = wifiMan.getWifiState();

        wifiMan.setWifiEnabled(true);
        File fl = new File(fileAddressMac);
        FileInputStream fin = new FileInputStream(fl);
        StringBuilder builder = new StringBuilder();
    int ch;
    while((ch = fin.read()) != -1){
        builder.append((char)ch);
    }

    ret = builder.toString();
    fin.close();

        boolean enabled = WifiManager.WIFI_STATE_ENABLED == wifiState;
        wifiMan.setWifiEnabled(enabled);
        return ret;
    }

清单:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
  • 摘要:此代码将首先尝试通过接口获取MAC地址,如果失败,则从文件系统获取。

  • 注意:对于文件系统方式,您需要启用WiFi以访问文件。

感谢Sam在此处的回答https://dev59.com/eVwX5IYBdhLWcg3w-Thv#39288868


6
您可以从IPv6本地地址获取MAC地址。例如,IPv6地址“fe80 :: 1034:56ff:fe78:9abc”对应于MAC地址“12-34-56-78-9a-bc”。请参见下面的代码。仅需要android.permission.INTERNET权限即可获取WiFi IPv6地址。
请参阅维基百科页面{{link1:IPv6地址}},特别是有关“本地地址”fe80 :: / 64和“修改的EUI-64”的注释部分。
/**
 * Gets an EUI-48 MAC address from an IPv6 link-local address.
 * E.g., the IPv6 address "fe80::1034:56ff:fe78:9abc"
 * corresponds to the MAC address "12-34-56-78-9a-bc".
 * <p/>
 * See the note about "local addresses" fe80::/64 and the section about "Modified EUI-64" in
 * the Wikipedia article "IPv6 address" at https://en.wikipedia.org/wiki/IPv6_address
 *
 * @param ipv6 An Inet6Address object.
 * @return The EUI-48 MAC address as a byte array, null on error.
 */
private static byte[] getMacAddressFromIpv6(final Inet6Address ipv6)
{
    byte[] eui48mac = null;

    if (ipv6 != null) {
        /*
         * Make sure that this is an fe80::/64 link-local address.
         */
        final byte[] ipv6Bytes = ipv6.getAddress();
        if ((ipv6Bytes != null) &&
                (ipv6Bytes.length == 16) &&
                (ipv6Bytes[0] == (byte) 0xfe) &&
                (ipv6Bytes[1] == (byte) 0x80) &&
                (ipv6Bytes[11] == (byte) 0xff) &&
                (ipv6Bytes[12] == (byte) 0xfe)) {
            /*
             * Allocate a byte array for storing the EUI-48 MAC address, then fill it
             * from the appropriate bytes of the IPv6 address. Invert the 7th bit
             * of the first byte and discard the "ff:fe" portion of the modified
             * EUI-64 MAC address.
             */
            eui48mac = new byte[6];
            eui48mac[0] = (byte) (ipv6Bytes[8] ^ 0x2);
            eui48mac[1] = ipv6Bytes[9];
            eui48mac[2] = ipv6Bytes[10];
            eui48mac[3] = ipv6Bytes[13];
            eui48mac[4] = ipv6Bytes[14];
            eui48mac[5] = ipv6Bytes[15];
        }
    }

    return eui48mac;
}

似乎即使您可以捕获它,Mac地址也是随机的! - Behrouz.M
WifiManager API在Android 6.0中被更改以返回虚假的MAC地址。但是,您仍然可以获取Wi-Fi网络的IPv6本地链接地址,然后像上面那样提取MAC地址。这在我尝试过的每个设备上都有效。 - Yojimbo
嗨@Yojimbo,这段代码会返回路由器的MAC地址还是设备的MAC地址? - Daniel Jomphe
1
这是设备的WiFi MAC地址。您可以使用WiFiManager.getScanResults()获取WiFi接入点的MAC地址。对于WAP,BSSID等于MAC地址。 - Yojimbo
您可以使用NetworkInterface枚举网络接口。请参考此SO问题进行示例。使用Java的instanceof运算符来确定哪些IP地址是Inet6Address - Yojimbo

5

完全没有问题

package com.keshav.fetchmacaddress;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e("keshav","getMacAddr -> " +getMacAddr());
    }

    public static String getMacAddr() {
        try {
            List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

                byte[] macBytes = nif.getHardwareAddress();
                if (macBytes == null) {
                    return "";
                }

                StringBuilder res1 = new StringBuilder();
                for (byte b : macBytes) {
                    res1.append(Integer.toHexString(b & 0xFF) + ":");
                }

                if (res1.length() > 0) {
                    res1.deleteCharAt(res1.length() - 1);
                }
                return res1.toString();
            }
        } catch (Exception ex) {
            //handle exception
        }
        return "";
    }
}

欢迎像我一样的zums。 - Keshav Gera
在Android 12上它将不再起作用。https://developer.android.com/about/versions/12/behavior-changes-all#mac-address - Nilesh Deokar

5

我尝试使用两种方法获取MAC地址,首先通过接口获取,如果失败则通过文件系统获取,但需要启用WiFi才能访问该文件。

//Android 6.0 : Access to mac address from WifiManager forbidden
    private static final String marshmallowMacAddress = "02:00:00:00:00:00";
    private static final String fileAddressMac = "/sys/class/net/wlan0/address";    

public static String recupAdresseMAC(WifiManager wifiMan) {
        WifiInfo wifiInf = wifiMan.getConnectionInfo();

        if(wifiInf.getMacAddress().equals(marshmallowMacAddress)){
            String ret = null;
            try {
                ret= getAdressMacByInterface();
                if (ret != null){
                    return ret;
                } else {
                    ret = getAddressMacByFile(wifiMan);
                    return ret;
                }
            } catch (IOException e) {
                Log.e("MobileAccess", "Erreur lecture propriete Adresse MAC");
            } catch (Exception e) {
                Log.e("MobileAcces", "Erreur lecture propriete Adresse MAC ");
            }
        } else{
            return wifiInf.getMacAddress();
        }
        return marshmallowMacAddress;
    }

private static String getAdressMacByInterface(){
        try {
            List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (nif.getName().equalsIgnoreCase("wlan0")) {
                    byte[] macBytes = nif.getHardwareAddress();
                    if (macBytes == null) {
                        return "";
                    }

                    StringBuilder res1 = new StringBuilder();
                    for (byte b : macBytes) {
                        res1.append(String.format("%02X:",b));
                    }

                    if (res1.length() > 0) {
                        res1.deleteCharAt(res1.length() - 1);
                    }
                    return res1.toString();
                }
            }

        } catch (Exception e) {
            Log.e("MobileAcces", "Erreur lecture propriete Adresse MAC ");
        }
        return null;
    }

private static String getAddressMacByFile(WifiManager wifiMan) throws Exception {
        String ret;
        int wifiState = wifiMan.getWifiState();

        wifiMan.setWifiEnabled(true);
        File fl = new File(fileAddressMac);
        FileInputStream fin = new FileInputStream(fl);
        ret = convertStreamToString(fin);
        fin.close();

        boolean enabled = WifiManager.WIFI_STATE_ENABLED == wifiState;
        wifiMan.setWifiEnabled(enabled);
        return ret;
    }

将此行添加到您的清单中。
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

我建议您在首选项中保留您的MAC地址,就像这里一样。
mac = activity.getSharedPreferences("MAC_ADDRESS", Context.MODE_PRIVATE).getString("MAC_ADDRESS", "");
                if(mac == null || mac.equals("")){
                    WifiManager wifiMan = (WifiManager) activity.getSystemService(Context.WIFI_SERVICE);
                    mac = MobileAccess.recupAdresseMAC(wifiMan);
                    if(mac != null && !mac.equals("")){
                        SharedPreferences.Editor editor = activity.getSharedPreferences("MAC_ADDRESS", Context.MODE_PRIVATE).edit();
                        editor.putString("MAC_ADDRESS", mac).commit();
                    }
                }

1
使用 wifiInfo.getBSSID() 来获取访问点的 Mac 地址,而不是使用 getMacAddress 方法。

仅提供您连接的设备(如WiFi路由器)的MAC地址,而不是设备本身。 - ldrrp

1
首先您需要添加互联网用户权限。
<uses-permission android:name="android.permission.INTERNET" />

然后,您可以通过NetworkInterfaces API找到mac地址。
public static String getMacAddr() {
    try {
        List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
        for (NetworkInterface nif : all) {
            if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

            byte[] macBytes = nif.getHardwareAddress();
            if (macBytes == null) {
                return "";
            }

            StringBuilder res1 = new StringBuilder();
            for (byte b : macBytes) {
                res1.append(String.format("%02X:",b));
            }

            if (res1.length() > 0) {
                res1.deleteCharAt(res1.length() - 1);
            }
            return res1.toString();
        }
    } catch (Exception ex) {
    }
    return "02:00:00:00:00:00";
}

1
以上答案摘自以下博客文章:http://robinhenniges.com/en/android6-get-mac-address-programmatically - zerobandwidth

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接