Android|Android 10 使用getDeviceId()和getIMEI()的问题及方案

问题背景: 应用升级了targetSDKVersion 到api 29,也就是Android 10,之前一些应用内用到getDeviceIdgetIMEI就出了问题,但是调用这些api的时候,都进行了try catch,但是在小米9手机上还是会崩溃:

AndroidRuntime: FATAL EXCEPTION: Thread-4326
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)
我猜测和小米的room有关,在这先不进一步讨论了
问题原因 从 Android 10 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可重置标识符(包含 IMEI 和序列号)。
注意:从 Google Play 商店安装的第三方应用无法声明特许权限。
受影响的方法包括:
  • Build
    • getSerial()
  • TelephonyManager
    • getImei()
    • getDeviceId()
    • getMeid()
    • getSimSerialNumber()
    • getSubscriberId()
如果您的应用没有该权限,但您仍尝试查询不可重置标识符的相关信息,则平台的响应会因目标 SDK 版本而异:
  • 如果应用以 Android 10 或更高版本为目标平台,则会发生 SecurityException
  • 如果应用以 Android 9(API 级别 28)或更低版本为目标平台,则相应方法会返回 null 或占位符数据(如果应用具有 READ_PHONE_STATE 权限)。否则,会发生 SecurityException
注意:如果您的应用是设备所有者或资料所有者应用,那么即使您的应用以 Android 10 或更高版本为目标平台,您也只需 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而来,怕一些同学没有梯子看不到,所以就直接粘贴了

    推荐阅读