networkinterface.gethardwareaddress() 在 android 多数场景下返回 null,因系统自 6.0 起限制普通应用访问硬件地址,子用户、未开 wifi 或非系统签名时均被内核或 selinux 过滤;推荐组合使用 wifi 接口获取、网卡遍历及系统文件读取等替代方案。

直接调用 NetworkInterface.getHardwareAddress() 获取 MAC 地址,在多数 Android 场景下会返回 null,不是代码写错了,而是系统有意限制——尤其在非主用户、非系统签名、未开启 WiFi 或目标网卡不可见时。
为什么经常返回 null?
这个方法底层依赖 Linux 的 getifaddrs() 和 netlink 通信,但 Android 从 6.0(API 23)起加强隐私管控:
- 普通应用默认无权读取硬件地址,即使声明了
ACCESS_WIFI_STATE也不够 - 子用户(如访客模式、工作资料)中,
eth0、wlan0等接口的 MAC 地址被内核层过滤,getHardwareAddress()拿不到原始数据 - 设备未连接 WiFi 时,
WifiManager.getConnectionInfo().getMacAddress()也返回"02:00:00:00:00:00"或空字符串 - Android 10+ 默认禁用
android.permission.ACCESS_FINE_LOCATION关联的硬件标识权限,影响底层网络接口枚举
更稳妥的替代方案
不依赖单一 API,组合判断可提升成功率:
PyCharm 2026.2.0.1 Mac版提供 JetBrains 官方 2026.2.0.1 版本安装包,适合在macOS系统上进行 Python 项目开发、运行、调试和测试。
-
优先尝试 WiFi 接口:确保 WiFi 已开启且已连接,再调用
WifiManager.getConnectionInfo().getMacAddress(),需声明ACCESS_WIFI_STATE -
遍历可用网卡并过滤:用
NetworkInterface.getNetworkInterfaces()枚举所有接口,跳过isLoopback()、isVirtual()、!isUp()的项,对每个接口调用getHardwareAddress(),取首个非 null 结果 -
读取系统文件(需 root 或调试权限):如
/sys/class/net/wlan0/address或/proc/net/arp(后者只含已通信过的设备 MAC,非本机) -
系统级适配(仅限系统应用):若为 system/priv-app,可在 manifest 中添加
android:sharedUserId="android.uid.system"并通过 SELinux 策略放开net_admin权限,绕过 bionic 层的用户隔离限制
简单可用的 Java 示例
以下代码兼顾兼容性与健壮性,适用于 Android 5.0+:
public static String getMacAddress(Context context) {
// 方式1:WiFi 连接时获取
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifi != null && wifi.isWifiEnabled()) {
WifiInfo info = wifi.getConnectionInfo();
if (info != null && info.getMacAddress() != null) {
String mac = info.getMacAddress().trim();
if (!"02:00:00:00:00:00".equals(mac) && !mac.isEmpty()) {
return mac;
}
}
}
// 方式2:遍历网卡
try {
Enumeration<networkinterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) continue;
byte[] mac = ni.getHardwareAddress();
if (mac != null && mac.length == 6) {
return String.format("%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
}
} catch (Exception ignored) {}
return "unknown";
}
</networkinterface>
特别注意子用户场景
在 userId ≠ 0 的子用户中(如企业工作资料、儿童模式),即使你是系统应用,getHardwareAddress() 仍大概率返回 null。根本原因在于 bionic 的 ifaddrs.cpp 在构造地址列表时,按用户命名空间过滤了 AF_PACKET 类型地址。此时唯一可靠路径是:
- 由主用户进程通过 Binder 提供 MAC 查询服务(跨用户通信)
- 或改用蓝牙地址(
BluetoothAdapter.getAddress())、Android ID、Advertising ID 等可替代的设备标识










