Android 11及以上无法通过getHardwareAddress()获取MAC地址求解决方案
Android 11+ 适配MAC地址获取方案
你的代码在Android 11及以上失效的核心原因是:Android 11(API 30)开始严格限制了网络隐私权限,系统不再允许普通应用通过NetworkInterface获取真实的WiFi硬件MAC地址,调用getHardwareAddress()会返回null或者固定占位值02:00:00:00:00:00,这是系统层面的隐私保护机制,无法绕过。
以下是几种可行的替代方案,根据你的业务场景选择:
方案1:使用Android ID作为唯一设备标识
Android ID是系统分配给每个应用的唯一字符串,除非用户恢复出厂设置或清除应用数据,否则不会变更,可作为设备唯一标识的替代方案:
import android.provider.Settings; public String getAndroidID(Context context) { return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); }
注意:
- 不同应用的Android ID是独立的
- 若用户重置设备,该值会改变
方案2:局域网场景下获取网络连接的MAC(仅WiFi连接时有效)
如果你的需求是在局域网内识别设备(比如智能家居、局域网通信),可以通过当前WiFi连接的InetAddress获取对应的MAC地址,这个地址是设备在当前局域网内的标识:
import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Collections; public String getLanMacAddress() { try { // 获取本地IP对应的InetAddress InetAddress inetAddress = InetAddress.getByName(getLocalIpAddress()); if (inetAddress == null) { return null; } NetworkInterface networkInterface = NetworkInterface.getByInetAddress(inetAddress); if (networkInterface == null) { return null; } byte[] macBytes = networkInterface.getHardwareAddress(); if (macBytes == null) { return null; } StringBuilder sb = new StringBuilder(); for (byte b : macBytes) { sb.append(String.format("%02X:", b)); } if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } catch (UnknownHostException | SocketException e) { e.printStackTrace(); return null; } } // 辅助方法:获取本地IP地址 private String getLocalIpAddress() { try { for (NetworkInterface intf : Collections.list(NetworkInterface.getNetworkInterfaces())) { for (InetAddress addr : Collections.list(intf.getInetAddresses())) { if (!addr.isLoopbackAddress() && addr.getAddress().length == 4) { return addr.getHostAddress(); } } } } catch (SocketException e) { e.printStackTrace(); } return null; }
注意:
- 仅当设备连接到WiFi网络时才能获取到值
- 该MAC是设备在当前局域网的网络标识,并非硬件原始MAC
方案3:使用IMEI(仅手机设备,需特殊权限)
如果你的应用仅面向手机设备,且能获取到READ_PHONE_STATE权限,可以使用IMEI作为唯一标识:
import android.content.Context; import android.telephony.TelephonyManager; public String getIMEI(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (telephonyManager == null) { return null; } // Android 10及以上需要Manifest.permission.READ_PRIVILEGED_PHONE_STATE权限,普通应用无法获取 // 仅系统应用或拥有特殊权限的应用才能调用 try { return telephonyManager.getImei(); } catch (SecurityException e) { e.printStackTrace(); return null; } }
注意:
- Android 10(API 29)及以上,普通应用无法获取IMEI,只有系统应用或拥有特殊权限的应用才能访问
- 平板等无蜂窝网络的设备没有IMEI
内容的提问来源于stack exchange,提问作者It Solution
相关产品推荐
相关产品推荐

