java.lang.SecurityException: getImeiForSlot: The user 10282 does not meet the requirement

项目场景:

这两天项目升级Android 编译版本,将build.gradle 中的 compileSdkVersion 升级到 29后,发现APP在Android 10 及Android 11设备上在调用获取设备信息的时候崩溃了。


问题描述:

Android 编译版本升级为29后,在Android 10 和Android 11 手机上获取设备信息崩溃,报错
java.lang.SecurityException: getImeiForSlot: The user 10282 does not meet the requirements to access device identifiers.
在这里插入图片描述

Caused by: java.lang.SecurityException: getImeiForSlot: The user 10282 does not meet the requirements to access device identifiers.
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2376)
        at android.os.Parcel.createException(Parcel.java:2360)
        at android.os.Parcel.readException(Parcel.java:2343)
        at android.os.Parcel.readException(Parcel.java:2285)
        at com.android.internal.telephony.ITelephony$Stub$Proxy.getImeiForSlot(ITelephony.java:11511)
        at android.telephony.TelephonyManager.getImei(TelephonyManager.java:2060)
        at android.telephony.TelephonyManager.getImei(TelephonyManager.java:2015)
        at com.bthvi.myapplication.PhoneStateHelper.getDeviceId(PhoneStateHelper.kt:82)

原因分析:

首先,贴下我的代码:

 val telephonyManager = context.getSystemService(Activity.TELEPHONY_SERVICE) as TelephonyManager
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          telephonyManager.imei
     } else {
          telephonyManager.deviceId
     }

这里崩溃是发生在获取 IMEI ,其实获取 deviceId 也是会崩溃的。

通过查看 Google Android开发者官方文档《唯一标识符最佳做法》发现
自 Android 10(API 级别 29)起,您的应用必须是设备或个人资料所有者应用,具有特殊运营商许可,或具有 READ_PRIVILEGED_PHONE_STATE 特权,才能访问不可重置的设备标识符。
在这里插入图片描述


解决方案:

1、降低targetSdkVersion版本

我们可以将支持版本降低到 29 一下,也就是 targetSdkVersion=28 这样就可以解决问题了。但是这种做法不建议,毕竟后面还是要升级到新版本的。

2、使用官方推荐方法

也就是我们前面在文档中看到的,使用SSAID,实例ID、广告ID,随机生成的ID等。具体可以看下文档,这里贴出我的改造方案。

if (context.applicationInfo.targetSdkVersion >= 29 && Build.VERSION.SDK_INT >= 29 ){
		//大于等于29使用特殊方法
      getUniqueID(context);
 }
  private fun getUniqueID(context: Context): String? {
    var id: String? = null
    val androidId = Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
    if (!Tool.isEmpty(androidId) && "9774d56d682e549c" != androidId) {
      try {
        val uuid = UUID.nameUUIDFromBytes(androidId.toByteArray(charset("utf8")))
        id = uuid.toString()
      } catch (e: Exception) {
        e.printStackTrace()
      }
    }
    if (Tool.isEmpty(id)) {
      id = getUUID()
    }
    return if (Tool.isEmpty(id)) UUID.randomUUID().toString() else id
  }
  private fun getUUID(): String? {
    var serial: String? = null
    val m_szDevIDShort = "35" + Build.BOARD.length % 10 + Build.BRAND.length % 10 + (if (null != Build.CPU_ABI) Build.CPU_ABI.length else 0) % 10 + Build.DEVICE.length % 10 + Build.DISPLAY.length % 10 + Build.HOST.length % 10 + Build.ID.length % 10 + Build.MANUFACTURER.length % 10 + Build.MODEL.length % 10 + Build.PRODUCT.length % 10 + Build.TAGS.length % 10 + Build.TYPE.length % 10 + Build.USER.length % 10 //13 位
    if (Build.VERSION.SDK_INT <= 29) {
      try {
        serial = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
          Build.getSerial()
        } else {
          Build.SERIAL
        }
        //API>=9 使用serial号
        return UUID(m_szDevIDShort.hashCode().toLong(), serial.hashCode().toLong()).toString()
      } catch (exception: java.lang.Exception) {
        serial = "serial" // 随便一个初始化
      }
    } else {
      serial = Build.UNKNOWN // 随便一个初始化
    }

    //使用硬件信息拼凑出来的15位号码
    return UUID(m_szDevIDShort.hashCode().toLong(), serial.hashCode().toLong()).toString()
  }
紫雾凌寒 CSDN认证博客专家 Android Flutter 数据结构及算法
一个有态度的一直在努力的95后程序员。擅长Android,Flutter,数据结构及算法等方面的知识。
路漫漫其修远兮,吾将上下而求索。
欢迎关注我的公众号:紫雾凌寒。
相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页