Android 10(Api 29)新特性适配 - 设备硬件标识符访问限制

设备硬件标识符访问限制

限制应用访问不可重设的设备识别码,如 IMEI、序列号等,系统应用不受影响。

原来的做法

1
2
3
4
5
6
7
8
// 在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,抛异常:

1
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不同。恢复出产设置或升级系统没测。

1
2
3
// 返回:496836e3a48d2d9d
String androidId = Settings.System.getString(context.getContentResolver(),
Settings.Secure.ANDROID_ID);

(2)方案二

通过硬件信息拼接,缺点是还是不能保证唯一。
经测试:似乎与方案一比更稳定,不受密钥影响,但非官方建议,没安全感。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* 获取设备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();
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :