一. 因
Android Q
也就是 Andriod 10
, 对应的api为29
为了更好保护用户隐私,谷歌对安卓Q系统中所有获取设备识别码的接口都增加了新的权限控制:READ_PRIVILEGED_PHONE_STATE
,该权限需要系统签名的应用才能申请。同时,系统默认WiFi Mac
地址随机化,当设备连上不同的WiFi网络时随机生成Mac地址
二. 果
通过READ_PHONE_STATE
权限获取Device ID
的应用以及将设备WiFi Mac
地址作为设备唯一标志符的应用将受影响
对于TargetSdkVersion<Q
且没有申请READ_PHONE_STATE
权限的应用和TargetSdkVersion>=Q
的全部应用,获取Device ID
会抛异常SecurityException
。
对于 TargetSdkVersion<Q
且申请了READ_PHONE_STATE
权限的应用,通过getDeviceId
接口读取的值为Null
。
当设备连接到不同的 Wi-Fi
网络时,系统会随机生成不同的 MAC
地址,将无法作为用户唯一标志
三. 解决办法
1. 接入设备厂商提供的ID
此方法比较麻烦
以下是vivo开放平台的通知,可以参见官方SDK文档
类似的,设备厂商华为为开发者提供ODID接口来帮助开发者适配该变更
2. 用硬件信息拼出来一个ID
此比较方便,唯一性不能百分百确保,亲测可用
public static String getUUID()
{
String serial = null;
String m_szDevIDShort = "35" +
Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +
Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 +
Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 +
Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 +
Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 +
Build.TAGS.length() % 10 + Build.TYPE.length() % 10 +
Build.USER.length() % 10; //13 位
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
serial = android.os.Build.getSerial();
} else {
serial = Build.SERIAL;
}
//API>=9 使用serial号
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
} catch (Exception exception) {
//serial需要一个初始化
serial = "serial"; // 随便一个初始化
}
//使用硬件信息拼凑出来的15位号码
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}
测试