唯一设备码

Android10(api29)

获取唯一设备码

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public static String getDeviceId(Context context) {
String deviceId = (String) SharedPreferencesUtil.getParam(SP_NAME_SYSTEM_INFO, SP_KEY_DEVICE_ID, "");
if (TextUtils.isEmpty(deviceId)) {
deviceId = getMD5(getDeviceInfo(context));
SharedPreferencesUtil.setParam(SP_NAME_SYSTEM_INFO, SP_KEY_DEVICE_ID, deviceId);
}
return deviceId;
}

/**
* deviceID的组成为:渠道标志+识别符来源标志+hash后的终端识别符
* 渠道标志为:
* andriod(a_)
* 识别符来源标志:
* 1, wifi mac地址(wifi_);
* 2, IMEI(imei_);
* 3, 序列号(sn_);
* 4, id:随机码。若前面的都取不到时,则随机生成一个随机码,需要缓存。
*
* @param context
* @return
*/
private static String getDeviceInfo(Context context) {
StringBuilder deviceId = new StringBuilder();
// 渠道标志
deviceId.append("a_");
try {
//wifi mac地址
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
String wifiMac = info.getMacAddress();
if (!TextUtils.isEmpty(wifiMac)) {
deviceId.append("wifi");
deviceId.append(wifiMac);
return deviceId.toString();
}
//IMEI(imei)
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String imei = tm.getDeviceId();
if (!TextUtils.isEmpty(imei)) {
deviceId.append("imei_");
deviceId.append(imei);
return deviceId.toString();
}
//AndroidID
if(!TextUtils.isEmpty(Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID))) {
return Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
}
//序列号(sn)
String sn = tm.getSimSerialNumber();
if (!TextUtils.isEmpty(sn)) {
deviceId.append("sn_");
deviceId.append(sn);
return deviceId.toString();
}
//如果上面都没有, 则生成一个id:随机码
String uuid = UUID.randomUUID().toString();
if (!TextUtils.isEmpty(uuid)) {
deviceId.append("id_");
deviceId.append(uuid);
return deviceId.toString();
}
} catch (Exception e) {
e.printStackTrace();
deviceId.append("id_").append(UUID.randomUUID().toString());
}
return deviceId.toString();
}


/**
* 获取String的MD5值
*
* @param info 字符串
* @return 该字符串的MD5值 返回值为十六进制的32位长度的字符串
*/
private static String getMD5(String info) {
try {
//获取 MessageDigest 对象,参数为 MD5 字符串,表示这是一个 MD5 算法(其他还有 SHA1 算法等):
MessageDigest md5 = MessageDigest.getInstance("MD5");
//update(byte[])方法,输入原数据
//类似StringBuilder对象的append()方法,追加模式,属于一个累计更改的过程
md5.update(info.getBytes("UTF-8"));
//digest()被调用后,MessageDigest对象就被重置,即不能连续再次调用该方法计算原数据的MD5值。可以手动调用reset()方法重置输入源。
//digest()返回值16位长度的哈希值,由byte[]承接
byte[] md5Array = md5.digest();
//byte[]通常我们会转化为十六进制的32位长度的字符串来使用,本文会介绍三种常用的转换方法
return new BigInteger(1, md5Array).toString(16);
} catch (NoSuchAlgorithmException e) {
return "";
} catch (UnsupportedEncodingException e) {
return "";
}
}

Android10 可以把设备码存储到“/data/local/tmp”(待验证)

认识OAID

移动安全联盟搞出来的这个OAID,其本质是一个设备唯一标识。

支持厂商

要实现设备唯一,必须是由厂商支持。华为、小米、OPPO、vivo、中兴、努比亚、魅族、联想、三星等均将逐步支持(一些老的设备且没有经过系统更新的不支持)

设备标识

该体系已拥有了四种设备标识

名称 生成时间 特性 重置 数据关联 适用对象
设备唯一标识符
UDID
设备生产时或调用时生成 不可逆、唯一性、封闭性、一致性、不可篡改性 无法重置,始终不变,除非硬件改变 全关联 用于设备的生产环境及合法性校验,不对外开放
匿名设备 标识符
OAID
系统首次启动后立即生成 可关闭性、连接性 用户手动重置、恢复出厂设置、设备商重置、被刷机等特殊情况重置 广告关联 可用于个性化推荐、广告等业务
开发者匿名设备标识符
VAID
可在应用安装时生成 设备、开发者、应用的几种情况 恢复出厂设置、卸载所有开发商应用、设备商重置、被刷机等特殊情况重置 开发者关联 可用于同一开发者不同应用之间的推荐等,对外开放
应用匿名设备标识符
AAID
可在应用安装时生成 匿名化、无隐私风险,设备、开发者、应用的几种情况 恢复出厂设置、卸载应用、清空应用手或设备商重置 单应用关联 可用于用户统计等

使用API

接口名称 函数 参数 返回 说明
补充设备标识状态获取接口 public static boolean isSupported() boolean: 是否支持补充设备标识符获取 true为支持,false为不支持
匿名设备标识符获取接口 public static String getOAID(Context context) Context:应用的Application Context String:返回匿名设备标识符或异常状态 匿名设备标识符最长64位,返回null表示不支持,异常状态包括网络异常、appid异常、应用异常等
开发者匿名设备标识符获取接口 public static String getVAID(Context context, String appid) Context:应用的Application Context String:返回开发者匿名设备符或异常状态 开发者匿名设备标识符最长64位,返回null表示不支持,异常状态包括网络异常、appid异常、应用异常等
应用匿名设备标识符获取接口 public static String getAAID(Context context, String appid) Context:应用的Application Context String:返回应用匿名设备标识符或异常状态 应用匿名设备标识符最长64位,返回null表示不支持,异常状态包括网络异常、appid异常、应用异常等

导入SDK后,通过isSupported()方法判断设备是否支持,支持后便可以通过相应方法获取对应设备标识。

具体的接入使用可以参考官方文档,下面给出移动安全联盟的官方地址和几个厂商的地址:
移动安全联盟-移动智能设备标识公共服务平台
VIVO-移动智能终端补充设备标识服务
华为-广告服务(OAID)
百度-Android OAID 接入