Android|Android 10 使用getDeviceId()和getIMEI()的问题及方案
问题背景:
应用升级了targetSDKVersion 到api 29,也就是Android 10,之前一些应用内用到getDeviceId
和getIMEI
就出了问题,但是调用这些api的时候,都进行了try catch,但是在小米9手机上还是会崩溃:
AndroidRuntime: FATAL EXCEPTION: Thread-4326我猜测和小米的room有关,在这先不进一步讨论了
E AndroidRuntime: Process: xxx, PID: 13895
E AndroidRuntime:java.lang.SecurityException: getDeviceId: The user 10222 does not meet the requirements to access device identifiers.
E AndroidRuntime: at android.os.Parcel.createException(Parcel.java:2074)
E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2042)
E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:1990)
E AndroidRuntime: at com.android.internal.telephony.ITelephonyProxy.getDeviceId(ITelephony.java:10389)
E AndroidRuntime: at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java:1629)
问题原因 从 Android 10 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可重置标识符(包含 IMEI 和序列号)。
注意:从 Google Play 商店安装的第三方应用无法声明特许权限。受影响的方法包括:
-
Build
getSerial()
-
TelephonyManager
getImei()
getDeviceId()
getMeid()
getSimSerialNumber()
getSubscriberId()
- 如果应用以 Android 10 或更高版本为目标平台,则会发生
SecurityException
。 - 如果应用以 Android 9(API 级别 28)或更低版本为目标平台,则相应方法会返回
null
或占位符数据(如果应用具有READ_PHONE_STATE
权限)。否则,会发生SecurityException
。
READ_PHONE_STATE
权限即可访问不可重置的设备标识符。此外,如果您的应用具有特殊运营商权限,则无需任何权限即可访问这些标识符。许多使用场景都不需要不可重置的设备标识符。例如,如果您的应用将不可重置的设备标识符用于广告跟踪或用户分析目的,请为这些特定使用场景使用 Android 广告 ID。要了解详情,请参阅唯一标识符的最佳做法。
具体可以参考这篇文章:android 10 的隐私权和位置信息
解决方案 代码:
public static String getIMEIDeviceId(Context context) {String deviceId;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
} else {
final TelephonyManager mTelephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
return "";
}
}
assert mTelephony != null;
if (mTelephony.getDeviceId() != null)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
deviceId = mTelephony.getImei();
}else {
deviceId = mTelephony.getDeviceId();
}
} else {
deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
}
}
Log.d("deviceId", deviceId);
return deviceId;
}
参考链接:
1.https://stackoverflow.com/questions/55173823/i-am-getting-imei-null-in-android-q
2.https://source.android.com/devices/tech/config/uicc
【Android|Android 10 使用getDeviceId()和getIMEI()的问题及方案】有些文章是从developer cp而来,怕一些同学没有梯子看不到,所以就直接粘贴了
推荐阅读
- android第三方框架(五)ButterKnife
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- Android中的AES加密-下
- 带有Hilt的Android上的依赖注入
- iOS中的Block
- Linux下面如何查看tomcat已经使用多少线程