如何在Android 10/11/12中代码获取IMEI?解决SecurityException问题
嘿,我来帮你梳理下在Android 10、11、12里获取IMEI的正确姿势,还有你遇到的那个java.lang.SecurityException的解决办法——本质都是Google从Android 10开始逐步收紧设备标识符访问权限导致的,咱们一步步说:
Android 10 (API 29) & Android 11 (API 30) 的IMEI获取规则
从Android 10开始,Google就把IMEI这类敏感设备标识符的访问权限锁得很死了:
- 普通第三方应用完全拿不到IMEI:哪怕你申请了
READ_PHONE_STATE权限也没用,这个权限现在只能用来获取一些非敏感的电话状态信息,比如通话状态。 - 只有少数特殊应用能获取:
- 带系统签名的系统应用
- 设备所有者(Device Owner)或配置文件所有者(Profile Owner)应用(比如企业管理类APP)
- 运营商官方的应用(需要运营商授予的特殊权限)
- 如果你的应用属于上述特殊范畴,代码可以这么写:
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if (checkSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { String imei = telephonyManager.getImei(); // 后续处理IMEI逻辑 }
注意:READ_PRIVILEGED_PHONE_STATE是系统级权限,普通APP在Google Play上根本申请不到,只能通过厂商签名或者设备所有者模式才能拿到。
Android 12 (API 31) 的权限收紧与报错解决
你碰到的getSerial: The user 10034 does not meet the requirements to access device identifiers报错,是因为Android 12把权限限制又提了一个等级:
- 哪怕你拿到了
READ_PRIVILEGED_PHONE_STATE权限,也得满足以下条件之一才能调用getImei()、getSerial()这类方法:- 应用是系统应用
- 应用是设备所有者/配置文件所有者
- 应用拥有
ACCESS_FINE_LOCATION权限,且是专门的通话类应用(比如拨号器、通话记录APP)——这个限制也非常严格,普通APP基本碰不到 - 应用是运营商授权的官方应用
对普通第三方应用的解决方案
如果你的APP是普通的第三方应用,别再纠结IMEI了——Google的隐私政策就是不让你拿,硬要碰只会报错。推荐用这些替代方案:
- 广告ID(Advertising ID):适合广告追踪、用户识别场景,不需要特殊权限,代码示例:
try { AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext()); String advertisingId = adInfo.getId(); boolean isLimitAdTracking = adInfo.isLimitAdTrackingEnabled(); // 广告ID逻辑处理 } catch (IOException | GooglePlayServicesNotAvailableException | GooglePlayServicesRepairableException e) { e.printStackTrace(); }
注意:需要依赖Google Play Services,而且用户可以随时重置或关闭广告ID,所以不能用来做永久唯一标识。
- 自定义唯一标识符:自己生成一个UUID,存在SharedPreferences或者本地文件里,应用卸载后会消失,但足够满足大多数普通APP的用户识别需求:
SharedPreferences prefs = getSharedPreferences("MyAppPrefs", Context.MODE_PRIVATE); String uniqueDeviceId = prefs.getString("UniqueDeviceId", null); if (uniqueDeviceId == null) { uniqueDeviceId = UUID.randomUUID().toString(); prefs.edit().putString("UniqueDeviceId", uniqueDeviceId).apply(); } // 用这个uniqueDeviceId来做用户识别
- Android ID:这是设备首次启动时生成的64位字符串,除非恢复出厂设置否则不会变。不过要注意,Android 8.0及以上,每个APP拿到的Android ID都是独立的,不同APP之间不共享:
String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
总结一下
Android 10及以上,普通第三方APP获取IMEI的路基本被堵死了——这是Google为了保护用户隐私制定的规则,没办法绕开。如果你的应用不是系统/运营商/设备所有者类APP,老老实实用替代方案才是正途,既符合规范,也能满足业务需求。
内容的提问来源于stack exchange,提问作者Aakarsh Rai
相关产品推荐
相关产品推荐

