UniApp跨Android版本获取MAC地址实战:从6.0以下到高版本的兼容性策略

张开发
2026/4/14 16:30:05 15 分钟阅读

分享文章

UniApp跨Android版本获取MAC地址实战:从6.0以下到高版本的兼容性策略
1. 为什么Android不同版本获取MAC地址这么麻烦第一次在UniApp里尝试获取设备MAC地址时我完全没料到会踩这么多坑。明明在Android 5.1上跑得好好的代码到了Android 9上突然返回02:00:00:00:00:00这种假地址。后来才发现从Android 6.0API 23开始Google对硬件标识符的访问权限做了重大调整。这就像你去小区物业要业主联系方式以前报房号就能拿到Android 6.0之前后来必须业主本人带着身份证现场确认Android 6.0的运行时权限再后来物业干脆不给真实号码了Android 10的随机MAC。理解这个背景很重要否则你永远在奇怪为什么代码时灵时不灵。最让人头疼的是不同厂商的ROM还有各种魔改。比如某些华为设备在Android 8.0就提前禁用了传统获取方式而小米的部分机型需要特殊文件路径。我在实际项目中遇到过一台OPPO设备必须同时检查wlan0和eth0两个接口才能拿到真实MAC。2. Android 6.0以下的传统获取方案2.1 通过WifiManager直取MAC在Android 6.0之前的日子真是美好时光获取MAC地址只需要三行代码WifiInfoMac: function() { var Context plus.android.importClass(android.content.Context); var WifiManager plus.android.importClass(android.net.wifi.WifiManager); var wifiManager plus.android.runtimeMainActivity().getSystemService(Context.WIFI_SERVICE); var WifiInfo plus.android.importClass(android.net.wifi.WifiInfo); var wifiInfo wifiManager.getConnectionInfo(); return wifiInfo.getMacAddress(); }这个方法直接调用系统级API不需要任何权限声明是的连uses-permission都不用。但要注意几个坑点设备必须开启WiFi不需要连接AP在部分冷门机型上可能返回null华为EMUI系统可能需要额外检查WifiInfo的toString()实测发现有些厂商会在这里返回全大写字母的MAC如AA:BB:CC:DD:EE:FF而有些是小写字母。如果要做设备唯一标识建议统一toLowerCase()处理。2.2 备用方案读取系统文件当WifiManager方案失效时可以尝试读取网络接口的系统文件ReaderMac: function() { try { var BufferedReader plus.android.importClass(java.io.BufferedReader); var FileReader plus.android.importClass(java.io.FileReader); var file new FileReader(/sys/class/net/wlan0/address); var reader new BufferedReader(file, 256); var address reader.readLine(); reader.close(); return address; } catch (error) { this.NetworkMac(); return 02:00:00:00:00:00; } }文件路径可能有这些变体/sys/class/net/wlan0/address/proc/net/arp/sys/class/net/eth0/address建议用try-catch包裹因为某些定制ROM会修改这些路径。我遇到过最奇葩的情况是某款中兴设备需要读取/proc/mac_addr。3. Android 6.0-9.0的过渡期方案3.1 必须申请的运行时权限从Android 6.0开始访问MAC地址需要危险权限uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION/ uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE/注意这两个细节需要动态申请权限即使manifest里声明了用户拒绝后返回的可能是随机化MAC建议在调用前检查权限状态function checkPermission() { var main plus.android.runtimeMainActivity(); var Permission plus.android.importClass(android.content.pm.PackageManager); return main.checkSelfPermission(android.permission.ACCESS_FINE_LOCATION) Permission.PERMISSION_GRANTED; }3.2 NetworkInterface方案这是Android官方推荐的获取方式NetworkMac: function() { var NetworkInterface plus.android.importClass(java.net.NetworkInterface); var networkInterface NetworkInterface.getByName(eth1); if (networkInterface null) { networkInterface NetworkInterface.getByName(wlan0); } if (networkInterface null) { this.isWifi(); return 02:00:00:00:00:00; } var mac networkInterface.getHardwareAddress(); var macArr []; for (var i in mac) { macArr.push(this.format(mac[i])); } return macArr.join(:); }这里有几个关键点先尝试eth1某些4G设备再尝试wlan0getHardwareAddress()返回的是byte数组需要转换格式化时注意处理负值Java的byte是有符号的4. Android 10的最新挑战4.1 随机MAC地址问题从Android 10开始默认返回的MAC都是随机化的02:00:00:00:00:00。要获取真实MAC需要满足以下条件应用是设备所有者应用Device Owner拥有系统签名权限设备未启用MAC随机化功能对于普通应用来说官方建议改用Android ID或Advertising ID。但如果你确实需要真实MAC可以尝试这个方案function getPermanentMac() { var Settings plus.android.importClass(android.provider.Settings); var Secure plus.android.importClass(android.provider.Settings.Secure); var mac Secure.getString( plus.android.runtimeMainActivity().getContentResolver(), android_id ); return mac || unknown; }4.2 厂商特殊API部分厂商提供了自己的API华为的HMS Core有设备标识服务小米的MiAd SDK包含设备信息接口OPPO/Vivo需要申请企业资质这些方案需要集成各家的SDK可能会增加包体积。建议根据实际用户群体选择性地集成。5. UniApp中的完整兼容方案5.1 版本判断与路由逻辑综合前面的方法完整的版本适配逻辑应该是MACaddress: function() { var Build plus.android.importClass(android.os.Build); if (Build.VERSION.SDK_INT 23) { return this.WifiInfoMac(); // Android 6.0以下 } else if (Build.VERSION.SDK_INT 23 Build.VERSION.SDK_INT 29) { return this.NetworkMac(); // Android 6.0-9.0 } else { return this.getPermanentMac(); // Android 10 } }5.2 错误处理与降级方案在实际项目中我建议增加这些容错措施多方案fallback机制主方案失败自动尝试备选方案本地缓存避免频繁请求用户引导提示开启WiFi等例如function safeGetMac() { var mac this.MACaddress(); if(mac 02:00:00:00:00:00) { plus.nativeUI.toast(请检查WiFi是否开启); this.isWifi(); } return mac; }6. 实战中的血泪经验在给某医疗设备开发配套App时我们遇到过这样的问题同一批设备在出厂测试时MAC获取正常但医院现场部署后部分设备返回假地址。最终发现是医院WiFi的某些安全策略导致的。解决方案是增加5秒超时机制离线模式下改用蓝牙地址作为备用标识在设备首次激活时预存MAC到本地数据库另一个坑是Android 11的包可见性限制。即使你有权限直接调用某些API也可能失败。需要在manifest添加queries intent action android:nameandroid.settings.WIFI_SETTINGS / /intent /queries最后给个忠告千万别把MAC地址当作唯一设备标识现在的Android设备可能有多个MACWiFi、蓝牙、以太网且都可能变化。推荐使用ANDROID_ID Build.SERIAL的组合方案。

更多文章