今天在撸代码时发现,之前能获取mac地址的方法在nexus 6上返回了“02:00:00:00:00:00”,进入设置查看mac地址,结果不相同,肯定有问题,于是就开始上网查资料一探究竟。
原先获取mac地址的代码段:
6.0之前获取mac地址方法
对于在Android Mashmallow返回地址“02:00:00:00:00:00”,官方其实是有说明的:“保护用户隐私数据”。
android 官方说明
然后就找到了这篇文章,里面详细的介绍了一种方法获取。用Java获取设备网络设备信息的API——NetworkInterface.getNetworkInterfaces()——仍然可以间接地获取到MAC地址。
NetworkInterface.getNetworkInterfaces
注意:在使用上述代码时,记得添加以下权限:
使用NetworkInterface.getNetworkInterfaces在手机上的输出结果为:
猜想wlan0对应的mac地址应该就是我们要找的。既然NetworkInterface可以正常获取,那得好好看看它在 Android framework 中的实现源码:
原来MAC地址是直接从"/sys/class/net/" + name + "/address"文件中读取的!
这个name是什么呢?
继续翻源码:
可以看出/sys/class/net目录下的一个文件夹即对应一个NetworkInterface的name。
从路由器上在线设备的MAC地址列表,可以验证我这台设备Wifi的name是wlan0
那么读取文件/sys/class/net/wlan0/address就轻松得到了这台设备的MAC地址:
不出所料!
进而,问题又变成如何获取设备的Wifi的interface name?
回到开头,我们是通过context.getSystemService(Context.WIFI_SERVICE)获取的WifiManager。而WifiManager肯定是与远程系统服务的IBinder在交互,而系统服务都是在SystemServer.run()中被启动的。在SystemServer.java中搜索关键字”WIFI_SERVICE”,很容易便找到mSystemServiceManager.startService(WIFI_SERVICE_CLASS);顺藤摸瓜,又找到系统服务实现类com.android.server.wifi.WifiService,WifiService中的逻辑很简单,构造真正的实现类com.android.server.wifi.WifiServiceImpl对象并注册到系统服务中:
WifiService.java
打开WifiServiceImpl.java,从构造方法处,一眼就看到了关键代码:mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
如此这般终于找到定义设备的Wifi的interface name的地方:SystemProperties
通过adb可以很容易得到这个属性值:adb shell getprop wifi.interface
那么在我们应用里可以通过Java的反射获取SystemProperties,进而调用静态方法get即可拿到Wifi的interface name。
如果是系统应用,可以直接添加下面的权限,之前的方法仍旧可以返回正确的mac地址: