Android 10(Api 29)新特性适配 – 设备硬件标识符访问限制
设备硬件标识符访问限制
限制应用访问不可重设的设备识别码,如 IMEI、序列号等,系统应用不受影响。
原来的做法
// 在Android Q上以下方法都会有问题
// 返回:866976045261713
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
tm.getDeviceId();
tm.getSubscriberId();
tm.getDeviceId(TelephonyManager.PHONE_TYPE_NONE);
//返回:66J0218B19000977
Build.getSerial();
(1)在低于Android Q的系统上没问题
(2)在Android Q及以上的系统上运行时:
-
如
targetSdkVersion<Q
,返回null或“unknown” -
如
targetSdkVersion>=Q
,抛异常:
SecurityException: getDeviceId: The user 10196 does not meet the requirements to access device identifiers.
(3)受影响的方法
Build
-
getSerial()
-
TelephonyManager
-
getImei()
-
getDeviceId()
-
getMeid()
-
getSimSerialNumber()
-
getSubscriberId()
-
替代方案
(1)方案一
使用AndroidId代替,缺点是应用签署密钥或用户(如系统恢复出产设置)不同返回的Id不同。与实际测试结果相符。
经实际测试:相同签名密钥的不同应用AndroidId相同,不同签名的应用AndroidId不同。恢复出产设置或升级系统没测。
// 返回:496836e3a48d2d9d
String androidId = Settings.System.getString(context.getContentResolver(),
Settings.Secure.ANDROID_ID);
(2)方案二
通过硬件信息拼接,缺点是还是不能保证唯一。
经测试:似乎与方案一比更稳定,不受密钥影响,但非官方建议,没安全感。
/**
* 获取设备ID
* @param context
* @return
*/
public static String getDeviceId(Context context) {
String deviceId = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
deviceId = Md5Util.md5(getUniqueID(context), Crypto.getSecret());
} else {
String imei = getIMEI(context);
String androidId = getAndroidId(context);
String deviceSerial = getSerialNo();
NLog.i(TAG, "IMEI: " + imei + ", AndroidID: " + androidId + ", DeviceSerial: " + deviceSerial);
deviceId = Md5Util.md5(imei + androidId + deviceSerial, Crypto.getSecret());
}
return deviceId;
}
public static String getUniqueID(Context context) {
String id = null;
final String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
if (!TextUtils.isEmpty(androidId) && !"9774d56d682e549c".equals(androidId)) {
try {
UUID uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
id = uuid.toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
if (TextUtils.isEmpty(id)) {
id = getUUID(context);
}
return TextUtils.isEmpty(id) ? UUID.randomUUID().toString() : id;
}
private static String getUUID(Context context) {
String serial = null;
String devIDShort = "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) {
if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
return new UUID(devIDShort.hashCode(), System.currentTimeMillis()).toString();
}
serial = android.os.Build.getSerial();
} else {
serial = Build.SERIAL;
}
//API>=9 使用serial号
return new UUID(devIDShort.hashCode(), serial.hashCode()).toString();
} catch (Exception exception) {
return new UUID(devIDShort.hashCode(), System.currentTimeMillis()).toString(); //默认初始化
}
//使用硬件信息拼凑出来的15位号码
//return new UUID(devIDShort.hashCode(), serial.hashCode()).toString();
}
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/18/android-10-api-29-new-feature-adaptation-device-hardware-identifier-access-restrictions/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论