目录
-
- 概述
- IMEI详解
- ANDROID_ID详解
-
- 什么是ANDROID_ID
- 特点
- 获取方式
- [Android 8.0重要变更说明](#Android 8.0重要变更说明)
- OAID详解
- 获取失败的情况
- 业务场景选择
- 常见问题解答
-
- [Q1: 为什么有时候获取不到设备ID?](#Q1: 为什么有时候获取不到设备ID?)
- [Q2: IMEI、ANDROID_ID和OAID哪个更好?](#Q2: IMEI、ANDROID_ID和OAID哪个更好?)
- [Q3: 卸载重装应用后,ANDROID_ID会改变吗?](#Q3: 卸载重装应用后,ANDROID_ID会改变吗?)
- [Q4: OAID卸载重装会变吗?](#Q4: OAID卸载重装会变吗?)
- [Q5: 如何确保设备标识的稳定性?](#Q5: 如何确保设备标识的稳定性?)
- [Q6: 在接口传参中应该使用哪个?](#Q6: 在接口传参中应该使用哪个?)
- [Q7: OAID需要Android 10以上才能获取吗?](#Q7: OAID需要Android 10以上才能获取吗?)
- 总结
概述
在Android开发中,设备标识符是重要的技术概念,主要用于用户识别、设备绑定、数据统计等场景。本文档详细对比了IMEI、ANDROID_ID和OAID三种主要的设备标识符,帮助非技术人员理解其差异和使用场景
(ps:经常有各个职能的同事来向我咨询这些标识符的意义作用、唯一性、稳定性、区别、是否存在可能拿不到的情况,以及什么情况下会拿不到标识符等问题。因此,我觉得系统整理一下还是很有意义的)。
IMEI详解
什么是IMEI
IMEI(International Mobile Equipment Identity)是国际移动设备识别码,是手机的唯一硬件标识符。
特点
- 设备级别唯一:每台设备都有唯一的IMEI
- 硬件级别持久:不会因应用卸载重装而改变
- 需要权限 :需要
READ_PHONE_STATE
权限 - 版本限制:Android 10+普通应用无法获取
权限要求
xml
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
获取方式
java
// 需要动态申请权限(Android 6.0+)
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String imei = tm.getDeviceId(); // Android 10以下
String imei = tm.getImei(); // Android 10+
ANDROID_ID详解
什么是ANDROID_ID
ANDROID_ID是Android系统为每个应用生成的唯一标识符,由系统自动管理。
特点
- 应用级别唯一:每个应用都有独立的ANDROID_ID
- 无需权限:不需要任何权限即可获取
- 隐私友好:不会泄露用户个人信息
- Android版本差异 :
- Android 8.0以下:卸载重装后会改变
- Android 8.0及以上 :基于应用签名生成,相同签名的应用卸载重装后不会改变
获取方式
java
// 无需权限,直接获取
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
Android 8.0重要变更说明
Android 8.0 (API 26) 对ANDROID_ID的重大改变:
在Android 8.0之前,ANDROID_ID是设备级别的,所有应用获取到的值都相同,卸载重装后会改变。
从Android 8.0开始,ANDROID_ID的生成规则变为:
java
// Android 8.0+ ANDROID_ID生成规则(伪代码)
ANDROID_ID = hash(应用签名密钥 + 用户ID + 设备唯一标识)
这意味着:
- 不同应用:即使在同一设备上,不同签名的应用获取到不同的ANDROID_ID
- 相同应用:相同签名的应用,在同一用户下,获取到相同的ANDROID_ID
- 卸载重装:使用相同签名的应用重装后,ANDROID_ID保持不变
- 多用户:同一应用在不同用户下,获取到不同的ANDROID_ID
验证代码:
java
/**
* 验证ANDROID_ID的Android 8.0行为变更
*/
public static void verifyAndroidIdBehavior(Context context) {
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
Log.d("AndroidId", "当前ANDROID_ID: " + androidId);
Log.d("AndroidId", "Android版本: " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.i("AndroidId", "Android 8.0+: ANDROID_ID基于应用签名生成,卸载重装后不变");
} else {
Log.i("AndroidId", "Android 8.0以下: ANDROID_ID设备级别,卸载重装后会改变");
}
// 获取应用签名信息
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
String signature = packageInfo.signatures[0].toCharsString();
Log.d("AndroidId", "应用签名: " + signature.substring(0, 16) + "...");
} catch (Exception e) {
Log.e("AndroidId", "获取应用签名失败", e);
}
}
OAID详解
什么是OAID
OAID(Open Anonymous Device Identifier)是中国移动安全联盟(MSA)推出的开放匿名设备标识符,旨在替代IMEI等传统设备标识符。
特点
- 设备级别唯一:与设备绑定,卸载重装应用后保持不变
- 无需权限:不需要特殊权限即可获取
- 隐私友好:用户可在系统设置中重置
- 厂商支持:主要支持国内主流厂商设备
- 版本兼容:不依赖Android系统版本,主要看厂商实现
支持的厂商
- 华为:EMUI 9.0/10.0及以上
- 小米:MIUI 10及以上
- OPPO:ColorOS 6.0及以上
- vivo:FuntouchOS 9.0及以上
- 三星:OneUI 2.0及以上
- 魅族:Flyme 7.0及以上
获取方式
java
// 使用MSA SDK获取OAID
MdidSdkHelper.InitSdk(context, true, new IIdentifierListener() {
@Override
public void OnSupport(boolean support, IdSupplier extra) {
if (support) {
String oaid = extra.oaid; // 获取到的OAID
}
}
});
厂商特定获取方式(华为示例)
java
// 华为HMS Core方式获取OAID
AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
String oaid = adInfo.getId();
获取失败的情况
IMEI获取失败的原因
-
权限问题
- 缺少
READ_PHONE_STATE
权限 - 用户拒绝权限申请
- Android 6.0+未动态申请权限
- 缺少
-
版本限制
- Android 9+普通应用无法获取
- 需要系统级权限
READ_PRIVILEGED_PHONE_STATE
-
设备问题
- 无SIM卡设备(平板、WiFi设备)
- 模拟器环境
- 硬件故障
-
系统限制
- 厂商定制ROM限制
- 企业级设备管理
- 安全沙箱环境
ANDROID_ID获取失败的原因
-
系统问题
- 系统异常
- 某些设备返回固定无效值
-
应用问题
- 应用权限被系统限制
- 系统级应用冲突
OAID获取失败的原因
-
厂商支持问题
- 设备厂商未实现OAID
- 系统版本过低,厂商未提供OAID支持
- 小众厂商或海外设备
-
用户设置问题
- 用户启用了"限制广告追踪"
- 用户在系统设置中重置了广告标识符
- 隐私设置限制了标识符获取
-
系统问题
- 系统异常或MSA服务未正常运行
- 某些定制ROM可能限制OAID获取
-
应用问题
- 未正确集成MSA SDK
- SDK版本过旧或兼容性问题
业务场景选择
适合使用IMEI的场景
- ✅ 需要跨应用卸载重装的设备绑定
- ✅ 用户身份识别
- ✅ 需要长期稳定的设备标识
- ✅ 反作弊、风控等安全场景
适合使用ANDROID_ID的场景
- ✅ 应用内用户行为追踪
- ✅ 需要相对稳定的设备标识(Android 8.0+)
- ✅ 注重隐私保护的场景
- ✅ 无需申请权限的场景
- ⚠️ Android 8.0以下系统的临时标识场景
适合使用OAID的场景
- ✅ 国内应用市场,特别是广告相关业务
- ✅ 需要设备级别唯一标识但无法获取IMEI的场景
- ✅ 符合国内隐私政策要求的场景
- ✅ 需要跨应用卸载重装保持一致的设备标识
对比表
特性 | IMEI | ANDROID_ID | OAID |
---|---|---|---|
唯一性级别 | 设备级别 | 应用级别 | 设备级别 |
持久性 | 高(硬件级别) | 中(应用级别,Android 8.0+基于签名) | 高(设备级别) |
卸载重装后 | 不变 | Android 8.0+不变,8.0以下会改变 | 不变 |
需要权限 | ✅ 需要 | ❌ 无需 | ❌ 无需 |
隐私安全 | ❌ 可能泄露设备信息 | ✅ 隐私友好 | ✅ 隐私友好 |
版本兼容性 | ❌ Android 10+受限 | ✅ 全版本支持 | ✅ 厂商支持即可 |
获取成功率 | 中(受权限影响) | 高(无需权限) | 中(受厂商支持影响) |
国内支持 | ✅ 全设备支持 | ✅ 全设备支持 | ✅ 主流厂商支持 |
海外支持 | ✅ 全设备支持 | ✅ 全设备支持 | ❌ 主要支持国内 |
常见问题解答
Q1: 为什么有时候获取不到设备ID?
A: 主要原因包括:
- 缺少必要权限(IMEI需要
READ_PHONE_STATE
权限) - 用户拒绝权限申请
- Android版本限制(Android 10+普通应用无法获取IMEI)
- 设备硬件问题(无SIM卡、模拟器等)
- 厂商不支持OAID(OAID主要支持国内主流厂商)
Q2: IMEI、ANDROID_ID和OAID哪个更好?
A: 各有优势,需要根据业务场景选择:
- OAID:国内应用推荐,设备级别唯一,无需权限,卸载重装不变
- IMEI:适合需要长期稳定标识的场景,但需要权限且Android 10+受限
- ANDROID_ID:适合应用内标识,无需权限,但卸载重装会改变
Q3: 卸载重装应用后,ANDROID_ID会改变吗?
A: 取决于Android版本:
- Android 8.0 (API 26) 及以上 :不会改变。ANDROID_ID基于应用签名密钥、用户和设备生成,相同签名的应用重装后获得相同的ANDROID_ID
- Android 8.0以下:会改变。卸载应用时会被清除,重装时重新生成
这是Android 8.0的重要变更,目的是为应用提供更稳定的标识符。
Q4: OAID卸载重装会变吗?
A: 大多数情况下不会变。OAID是设备级别的标识符,与设备绑定而非应用绑定。但在以下情况下可能会变化:
- 用户主动在系统设置中重置广告标识符
- 系统大版本更新后厂商重新生成OAID
- 用户修改了隐私设置
Q5: 如何确保设备标识的稳定性?
A: 建议采用多重备选方案:
- 优先使用OAID(国内设备推荐)
- 备选使用ANDROID_ID(无需权限)
- 最后使用UUID(随机生成)
- 在本地存储中缓存结果
Q6: 在接口传参中应该使用哪个?
A: 建议根据业务需求选择:
- 国内应用:优先使用OAID,备选ANDROID_ID
- 海外应用:使用ANDROID_ID
- 用户识别场景:优先使用OAID,备选ANDROID_ID
- 应用内统计:使用ANDROID_ID即可
- 跨应用场景:必须使用OAID
- 隐私敏感场景:优先使用OAID或ANDROID_ID
- 用到IMEI的场景:仅开发系统app,定制ROM可使用。
Q7: OAID需要Android 10以上才能获取吗?
A: 不需要。OAID的获取主要取决于设备厂商的实现,而非Android系统版本。许多厂商在Android 8.0、9.0系统上也实现了OAID支持。
总结
设备标识符的选择需要综合考虑业务需求、权限要求、版本兼容性、隐私保护和地域特点等因素。对于国内应用,推荐优先使用OAID;对于海外应用,推荐使用ANDROID_ID。
关键要点:
- OAID是国内应用的最佳选择,设备级别唯一且无需权限
- IMEI需要权限,但设备级别唯一,Android 10+受限
- ANDROID_ID在Android 8.0+卸载重装后不会改变(重要更新)
- ANDROID_ID无需权限,Android 8.0+基于应用签名生成,具有较好的稳定性
- 建议结合多种方案实现稳定的设备标识
- 注意Android版本的兼容性问题,特别是8.0的重大变更