android获取设备mac地址(兼容6.0+版本)

最近接手一个新项目,该项目中一直使用getMacAddress获取设备的mac地址。我在实际测试中发现,小米4的手机该方法一直返回02:00:00:00:00:00

查阅资料得知,android 6.0之后,官方加强了对访问硬件信息的管控。

To provide users with greater data protection, starting in this release, Android removes programmatic access to the device’s local hardware identifier for apps using the Wi-Fi and Bluetooth APIs. The WifiInfo.getMacAddress() and the BluetoothAdapter.getAddress() methods now return a constant value of 02:00:00:00:00:00.
To access the hardware identifiers of nearby external devices via Bluetooth and Wi-Fi scans, your app must now have the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions.

解决方法

使用Java获取设备网络设备信息的API:NetworkInterface.getNetworkInterfaces() 间接地获取到MAC地址。
具体代码如下:

public static String getLocalMacAddress(Context context) {
        String mac;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mac = getMachineHardwareAddress();
        } else {
            WifiManager wifi = (WifiManager) context
                    .getSystemService(Context.WIFI_SERVICE);
            WifiInfo info = wifi.getConnectionInfo();
            mac = info.getMacAddress().replace(":", "");
        }
        
        return mac;
}
    
    /**
     * 获取设备的mac地址和IP地址(android6.0以上专用)
     * @return
     */
    public static String getMachineHardwareAddress(){
        Enumeration<NetworkInterface> interfaces = null;
        try {
            interfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        String hardWareAddress = null;
        NetworkInterface iF = null;
        while (interfaces.hasMoreElements()) {
             iF = interfaces.nextElement();
            try {
                hardWareAddress = bytesToString(iF.getHardwareAddress());
                if(hardWareAddress == null) continue;
            } catch (SocketException e) {
                e.printStackTrace();
            }
        }
        if(iF != null && iF.getName().equals("wlan0")){
            hardWareAddress = hardWareAddress.replace(":","");
        }
        return hardWareAddress ;
    }   

    /***
     * byte转为String
     * @param bytes
     * @return
     */
    private static String bytesToString(byte[] bytes){
        if (bytes == null || bytes.length == 0) {
            return null ;
        }
        StringBuilder buf = new StringBuilder();
        for (byte b : bytes) {
            buf.append(String.format("%02X:", b));
        }
        if (buf.length() > 0) {
            buf.deleteCharAt(buf.length() - 1);
        }
        return buf.toString();
    }

在搜索资料时,还看到一篇博客通过执行shell命令来获取mac地址。可供大家参考,网站地址:
http://blog.csdn.net/zhaohaiyan629/article/details/51122344

但是在实际测试中,出现了一个兼容性问题。在华为荣耀8手机,android 7.0系统运行该代码出现如下异常。

运行异常日志.png

该手机直接执行“adb shell cat /sys/class/net/wlan0/address”提示Permission Denied。找另外的小米手机6.0及7.0均可以执行该命令,且可以通过代码获取到Mac地址。到这里可以总结出因为华为荣耀8的7.0系统修改了要访问的文件权限,导致该错误。而通过Runtime执行su命令也会提示权限不足。

这种场景下,建议通过本文中提到的NetworkInterface.getNetworkInterfaces方法获取Mac地址。

执行shell脚本获取mac的主要代码如下:

/** 
* 获取手机的MAC地址 
* @return 
*/  
public String getMac(){  
        String str="";  
        String macSerial="";  
        try {  
            Process pp = Runtime.getRuntime().exec(  
                    "cat /sys/class/net/wlan0/address ");  
            InputStreamReader ir = new InputStreamReader(pp.getInputStream());  
            LineNumberReader input = new LineNumberReader(ir);  
  
            for (; null != str;) {  
                str = input.readLine();  
                if (str != null) {  
                    macSerial = str.trim();// 去空格  
                    break;  
                }  
            }  
        } catch (Exception ex) {  
            ex.printStackTrace();  
        }  
        if (macSerial == null || "".equals(macSerial)) {  
            try {  
                return loadFileAsString("/sys/class/net/eth0/address")  
                        .toUpperCase().substring(0, 17);  
            } catch (Exception e) {  
                e.printStackTrace();  
                  
            }  
              
        }  
        return macSerial;  
} 

public static String loadFileAsString(String fileName) throws Exception {  
            FileReader reader = new FileReader(fileName);    
            String text = loadReaderAsString(reader);  
            reader.close();  
            return text;  
}  

public static String loadReaderAsString(Reader reader) throws Exception {  
            StringBuilder builder = new StringBuilder();  
            char[] buffer = new char[4096];  
            int readLength = reader.read(buffer);  
            while (readLength >= 0) {  
                builder.append(buffer, 0, readLength);  
                readLength = reader.read(buffer);  
            }  
            return builder.toString();  
}  

推荐阅读更多精彩内容