Android关于设备唯一标识符的获取,适配Android10
Posted 陳英傑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android关于设备唯一标识符的获取,适配Android10相关的知识,希望对你有一定的参考价值。
1、IMEI
获取IMEI是通过TelephonyManager对象,TelephonyManager对象的获取方式是通过context.getSystemService(),传入不同的值获取到的Manager对象不同。
TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
主要分以下几种情况:
android 6.0
以下,无需权限
获取方式:tm.getDeviceId();
Android 6.0 - Android 8.0
,需要READ_PHONE_STATE
权限,如果用户拒绝权限会抛出SecurityException
异常。
获取方式:tm.getDeviceId();
Android 8.0 - Android 10
,需要READ_PHONE_STATE
权限,如果用户拒绝权限会抛出SecurityException
异常。
获取方式:tm.getImei();
但是此方法获取的imei只有一个,如果手机是双卡的是有两个imei值的,可以使用动态调用的方式都获取到:
public static String getIMEI(Context context)
TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
try
Method method = manager.getClass().getMethod("getImei", int.class);
String imei1 = (String) method.invoke(manager, 0);
String imei2 = (String) method.invoke(manager, 1);
return imei1;// 根据需求返回
catch (Exception e)
e.printStackTrace();
return "";
Android 10
以上,即使你申请了READ_PHONE_STATE
权限,依然会抛出异常,所以IMEI不能用了。
2、序列号
序列号也和Android版本有关,不同版本获取方式不同,主要分以下情况:
Android 8.0
以下,不需要权限,可以通过android.os.Build.SERIAL
获取。Android 8.0 - Android 10
,通过以上方式获取到的是unknown
,此方式已废弃;需要READ_PHONE_STATE
权限,通过android.os.Build.getSerial()
获取,如果用户拒绝了,抛出SecurityException
异常。Android 10
以上,即使有READ_PHONE_STATE
权限也会抛出SecurityException
异常,和imei一样,Android10以上不能获取了。
3、Mac地址
mac地址分以下几种情况:
Android 6.0
以下,需要ACCESS_WIFI_STATE
权限,通过以下方式获取:
private String getMacAddress(Context context)
WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
return manager.getConnectionInfo().getMacAddress();
Android 6.0
以后,上面方法获取的结果都是02:00:00:00:00:00
,用读取系统文件方式获取:
/**
* Android 6.0 - Android 7.0(不包含)
* @return
*/
private static String getMacAddress()
String macSerial = null;
String str = "";
InputStreamReader ir = null;
LineNumberReader input = null;
try
Process pp = Runtime.getRuntime().exec("cat /sys/class/net/wlan0/address");
ir = new InputStreamReader(pp.getInputStream(), StandardCharsets.UTF_8);
input = new LineNumberReader(ir);
for (; null != str; )
str = input.readLine();
if (str != null)
macSerial = str.trim();
break;
catch (IOException ex)
ex.printStackTrace();
finally
close(input);
close(ir);
return macSerial;
private static void close(Closeable closeable)
if (closeable != null)
try
closeable.close();
catch (Throwable e)
e.printStackTrace();
但是此方法在Android 7.0
以后也不能用了,会抛出FileNotFoundException异常,取而代之的是通过扫描所有网络接口来获取:
private static String getAddressMacByInterface()
try
List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : all)
if (nif.getName().equalsIgnoreCase("wlan0"))
byte[] macBytes = nif.getHardwareAddress();
if (macBytes == null)
return "";
StringBuilder res1 = new StringBuilder();
for (byte b : macBytes)
res1.append(String.format("%02X:", b));
if (res1.length() > 0)
res1.deleteCharAt(res1.length() - 1);
return res1.toString();
catch (Exception e)
e.printStackTrace();
return "";
此方式也是目前获取mac最稳定的方式,但是Android 10
加入了mac地址随机化特性,目前市面上大部分手机不支持此特性,需要在开发者选项中设置,普通用户一般连开发者模式都是关闭的,所以暂时可以放心使用,但是随着Android版本的迭代,不排除Google官方把此特性默认设置为打开的。
4、ANDROID_ID
android_id是设备的系统首次启动生成的一串字符,基本可以保证唯一性,获取方式:
String androidId = Settings.System.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
与上面的几种相比,android_id获取比较简单,没有权限限制,也不会抛出异常,但是root、刷机或恢复出厂设置都会导致设备的ANDROID_ID重置。
总结:
总的来说,为设备添加唯一标识可以参照以下优先级:
1、ANDROID_ID:系统首次启动生成,获取方式安全,但是不稳定。
2、MAC地址:获取方式不安全,比较稳定。
由于Android 10的发布,序列号和IMEI基本可以放弃使用了;
3、Android还提供了一个生成id的工具类UUID,可以生成一串随机字符,保存到本地来使用。
4、使用移动安全联盟提供的方法(未尝试过)。
反正由于Android的碎片化,需要开发者不断的适配、更新,如果长时间不适配,说不定哪天系统更新了你的应用就崩了。
关于以上方法的工具类下载。
以上是关于Android关于设备唯一标识符的获取,适配Android10的主要内容,如果未能解决你的问题,请参考以下文章