个人浅谈 Android设备唯一识别方案(待续~)

说明

在项目中,为了统计用户登录设备数以及日活,获取设备的惟一标识是一个很常见的需求,以前常用的一种方式是通过获取当前设备的device_id。

但是这种方式存在一些问题。首先它是需要权限的,所有很多时候,你可能会获取不到 device_id。特别是在 Android 6.0 后,在很大国产的 ROM 里,

都可以在系统设置里,修改相关的权限,来禁止应用程序获取 device_id,Android Q以后只允许系统签名的应用获取device_id

  1. 现有方案
    现在我们的应用通过强制授权的方式获取中device_id作为设备标识符,这个device_id保存在App应用内 ,device_id不会随着设备重置发生变化。

    device_id 通过 TelephonyManager.getDeviceId()获取,获取前必须先申请 READ_PHONE_STATE 权限。

  2. Android Q对现方案的影响
    Android Q开始 新增了权限READ_PRIVILEGED_PHONE_STATE并且删除了READ_PHONE_STATE,应用必须拥有 READ_PRIVILEGED_PHONE_STATE才能获取device_id;

    而这个权限普通应用是获取不到的,这个权限只开放给系统级应用如果没有该权限但却尝试去获取这些标识符的话,根据应用目标版本的不同会有所不同:

    应用的目标版本为 Android Q(targetSdkVersion = Q),会抛出 SecurityException ,这是一个运行时异常,会导致应用崩溃;

    应用的目标版本为 Android 9.0 或更低(targetSdkVersion < Q),如果应用拥有 READ_PHONE_STATE权限,会返回 null 或占位符数据(比如 Unknown),否则的话也会抛出 SecurityException。

  3. 关于android_id
    android_id是当设备在第一次启动时,系统会随机产生一个64位的数字,然后以16进制的形式保存在设备上,系统API提供了获取这一参数的方法:

    Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);

    android_id存在的一些问题:

    • 当设备刷机android_id会被重置
    • 不同的设备可能会产生相同的android_id
    • 对于CDMA的设备,android_id和device_id的值相同
    • 有极少部分国产定制ROM有可能获取android_id值为null的情况
  4. 最终方案
    通过以上知道android device_id 在Android Q上面是无法获取的,我们在App启动的时候判断当前系统的版本号,当前系统版本号 < Q时

    走授权询问READ_PHONE_STATE权限,获取device_id保存本地,若deviceId为空或者当前系统版本号>=Q时,通过系统API获取android_id,判断android_id是否为空,

    不为空保存在本地,供全局使用,为空本地生成UUID并且在头部拼上UUID标识

方案的影响:
Android Q以下还是老的设备唯一识别方案device id,若用户通过OTA升级到Android Q,若程序不卸载重装的或者不通过系统设置清除应用数据,

方案不变使用device id,反之获取android id,android id为空则使用本地生成的uuid并且拼上相关标识

方案流程图参考下方:

个人浅谈 Android设备唯一识别方案(待续~)