IMEI(International Mobile Equipment Identity)是国际移动设备识别码的缩写,由15-17位数字组成,与手机是一一对应的关系。无论刷机还是恢复出厂设置,该设备标识码都不会改变,所以在广告和流量统计等方面特别好用,备受开发者的青睐。
但自从android29之后,通android api的TelephonyManager提供的getImei方法已经无法获取到手机的imei了,那我们又该如何获取的手机的唯一设备标识符呢?
Android开发者文档提供的方式是Android Id,这种获取的方式在大多时候确实是有效的,能满足常规的广告统计需要,但如果遇到手机刷机、系统升级或者恢复出厂后,这个id就会被重置,所以在某些业务场景下(例如要将设备标识作为用户唯一id),就显得捉襟见肘了。
网上有一些解决方案,大多是用mac地址,UUid,或者针对特定的手机厂商去生成唯一标识,那我们真的在android 10系统中就拿不到手机的imei了吗?答案是否定的,例如在root权限下,我们就可以绕过android的api,直接拿到手机的imei。
笔者假设用户的手机已经root,并且已经将手机用android调试桥连接到电脑上去,那我们在电脑终端输入adb命令,便可将手机的imei打印出来:
adb shell service call iphonesubinfo 1
我们不妨通过正则表达式,将获取到的imei匹配出来:
adb shell service call iphonesubinfo 3 i32 1 | awk -F "'" '{print $2}' | sed '1 d' | tr -d '.' | awk '{print}' ORS=
既然我们在终端中可以获取到imei,那我们只需要把这个命令作为shell,在代码里运行即可,但是需要su的权限,不然也获取不到imei:
public static String getImeiByShell(){
try {
String shell = "service call iphonesubinfo 3 i32 1 | awk -F \"'\" '{print $2}' | sed '1 d' | tr -d '.' | awk '{print}' ORS=";
Process p=Runtime.getRuntime().exec(new String[]{"su","-c",shell});
BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));
String readLine=br.readLine();
while(readLine!=null){
Log.d("execShell",readLine);
return readLine.trim();
}
if(br!=null){
br.close();
}
p.destroy();
p=null;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
如此,我们便可以获取到手机的imei。
作者:凌塘
链接:https://juejin.cn/post/6953079991303143432
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。