Android 10(Api 29)新特性适配 – 设备硬件标识符访问限制

设备硬件标识符访问限制

限制应用访问不可重设的设备识别码,如 IMEI、序列号等,系统应用不受影响。

原来的做法

// 在Android Q上以下方法都会有问题
// 返回:866976045261713
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
tm.getDeviceId();
tm.getSubscriberId();
tm.getDeviceId(TelephonyManager.PHONE_TYPE_NONE);
//返回:66J0218B19000977
Build.getSerial();

(1)在低于Android Q的系统上没问题

(2)在Android Q及以上的系统上运行时:

  • targetSdkVersion<Q,返回null或“unknown”

  • targetSdkVersion>=Q,抛异常:

SecurityException: getDeviceId: The user 10196 does not meet the requirements to access device identifiers.

(3)受影响的方法

  • Build
      • getSerial()
  • TelephonyManager
      • getImei()
      • getDeviceId()
      • getMeid()
      • getSimSerialNumber()
      • getSubscriberId()

替代方案

(1)方案一

使用AndroidId代替,缺点是应用签署密钥或用户(如系统恢复出产设置)不同返回的Id不同。与实际测试结果相符。
经实际测试:相同签名密钥的不同应用AndroidId相同,不同签名的应用AndroidId不同。恢复出产设置或升级系统没测。

// 返回:496836e3a48d2d9d
String androidId = Settings.System.getString(context.getContentResolver(),
        Settings.Secure.ANDROID_ID);

(2)方案二

通过硬件信息拼接,缺点是还是不能保证唯一。
经测试:似乎与方案一比更稳定,不受密钥影响,但非官方建议,没安全感。

/**
 * 获取设备ID
 * @param context
 * @return
 */
public static String getDeviceId(Context context) {
    String deviceId = "";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        deviceId = Md5Util.md5(getUniqueID(context), Crypto.getSecret());
    } else {
        String imei = getIMEI(context);
        String androidId = getAndroidId(context);
        String deviceSerial = getSerialNo();
        NLog.i(TAG, "IMEI: " + imei + ", AndroidID: " + androidId + ", DeviceSerial: " + deviceSerial);
        deviceId = Md5Util.md5(imei + androidId + deviceSerial, Crypto.getSecret());
    }
    return deviceId;
}

public static String getUniqueID(Context context) {
    String id = null;
    final String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
    if (!TextUtils.isEmpty(androidId) && !"9774d56d682e549c".equals(androidId)) {
        try {
            UUID uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
            id = uuid.toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    if (TextUtils.isEmpty(id)) {
        id = getUUID(context);
    }

    return TextUtils.isEmpty(id) ? UUID.randomUUID().toString() : id;
}

private static String getUUID(Context context) {
    String serial = null;

    String devIDShort = "35" +
            Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +

            Build.CPU_ABI.length() % 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 位

    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                return new UUID(devIDShort.hashCode(), System.currentTimeMillis()).toString();
            }
            serial = android.os.Build.getSerial();
        } else {
            serial = Build.SERIAL;
        }
        //API>=9 使用serial号
        return new UUID(devIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        return new UUID(devIDShort.hashCode(), System.currentTimeMillis()).toString(); //默认初始化
    }

    //使用硬件信息拼凑出来的15位号码
    //return new UUID(devIDShort.hashCode(), serial.hashCode()).toString();
}

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/18/android-10-api-29-new-feature-adaptation-device-hardware-identifier-access-restrictions/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Android 10(Api 29)新特性适配 – 设备硬件标识符访问限制
设备硬件标识符访问限制 限制应用访问不可重设的设备识别码,如 IMEI、序列号等,系统应用不受影响。 原来的做法 // 在Android Q上以下方法都会有问题 // 返……
<<上一篇
下一篇>>
文章目录
关闭
目 录