Android关于设备唯一标识符的获取,适配Android10

1、IMEI

获取IMEI是通过TelephonyManager对象,TelephonyManager对象的获取方式是通过context.getSystemService(),传入不同的值获取到的Manager对象不同。

TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);

主要分以下几种情况:

  • Android 6.0以下,无需权限
    获取方式:tm.getDeviceId();
  • Android 6.0 - Android 8.0,需要READ_PHONE_STATE权限,如果用户拒绝权限会抛出SecurityException异常。
    获取方式:tm.getDeviceId();
  • Android 8.0 - Android 10,需要READ_PHONE_STATE权限,如果用户拒绝权限会抛出SecurityException异常。
    获取方式:tm.getImei();
    但是此方法获取的imei只有一个,如果手机是双卡的是有两个imei值的,可以使用动态调用的方式都获取到:
public static String getIMEI(Context context) {
	TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    try {
         Method method = manager.getClass().getMethod("getImei", int.class);
         String imei1 = (String) method.invoke(manager, 0);
         String imei2 = (String) method.invoke(manager, 1);
         return imei1;// 根据需求返回
     } catch (Exception e) {
         e.printStackTrace();
     }
	return "";
}
  • Android 10 以上,即使你申请了READ_PHONE_STATE权限,依然会抛出异常,所以IMEI不能用了。
2、序列号

序列号也和Android版本有关,不同版本获取方式不同,主要分以下情况:

  • Android 8.0以下,不需要权限,可以通过android.os.Build.SERIAL获取。
  • Android 8.0 - Android 10,通过以上方式获取到的是unknown,此方式已废弃;需要READ_PHONE_STATE权限,通过android.os.Build.getSerial()获取,如果用户拒绝了,抛出SecurityException异常。
  • Android 10以上,即使有READ_PHONE_STATE权限也会抛出SecurityException异常,和imei一样,Android10以上不能获取了。
3、Mac地址

mac地址分以下几种情况:

  • Android 6.0以下,需要ACCESS_WIFI_STATE权限,通过以下方式获取:
private String getMacAddress(Context context) {
    WifiManager manager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    return manager.getConnectionInfo().getMacAddress();
}
  • Android 6.0以后,上面方法获取的结果都是02:00:00:00:00:00,用读取系统文件方式获取:
	/**
     * Android 6.0 - Android 7.0(不包含)
     * @return
     */
    private static String getMacAddress() {
        String macSerial = null;
        String str = "";
        InputStreamReader ir = null;
        LineNumberReader input = null;
        try {
            Process pp = Runtime.getRuntime().exec("cat /sys/class/net/wlan0/address");
            ir = new InputStreamReader(pp.getInputStream(), StandardCharsets.UTF_8);
            input = new LineNumberReader(ir);
            for (; null != str; ) {
                str = input.readLine();
                if (str != null) {
                    macSerial = str.trim();
                    break;
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            close(input);
            close(ir);
        }
        return macSerial;
    }

    private static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }

但是此方法在Android 7.0以后也不能用了,会抛出FileNotFoundException异常,取而代之的是通过扫描所有网络接口来获取:

	private static String getAddressMacByInterface() {
        try {
            List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (nif.getName().equalsIgnoreCase("wlan0")) {
                    byte[] macBytes = nif.getHardwareAddress();
                    if (macBytes == null) {
                        return "";
                    }
                    StringBuilder res1 = new StringBuilder();
                    for (byte b : macBytes) {
                        res1.append(String.format("%02X:", b));
                    }
                    if (res1.length() > 0) {
                        res1.deleteCharAt(res1.length() - 1);
                    }
                    return res1.toString();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

此方式也是目前获取mac最稳定的方式,但是Android 10加入了mac地址随机化特性,目前市面上大部分手机不支持此特性,需要在开发者选项中设置,普通用户一般连开发者模式都是关闭的,所以暂时可以放心使用,但是随着Android版本的迭代,不排除Google官方把此特性默认设置为打开的。

4、ANDROID_ID

android_id是设备的系统首次启动生成的一串字符,基本可以保证唯一性,获取方式:

String androidId = Settings.System.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

与上面的几种相比,android_id获取比较简单,没有权限限制,也不会抛出异常,但是root、刷机或恢复出厂设置都会导致设备的ANDROID_ID重置。

总结:

总的来说,为设备添加唯一标识可以参照以下优先级:
1、ANDROID_ID:系统首次启动生成,获取方式安全,但是不稳定。
2、MAC地址:获取方式不安全,比较稳定。
由于Android 10的发布,序列号和IMEI基本可以放弃使用了;
3、Android还提供了一个生成id的工具类UUID,可以生成一串随机字符,保存到本地来使用。
4、使用移动安全联盟提供的方法(未尝试过)。

反正由于Android的碎片化,需要开发者不断的适配、更新,如果长时间不适配,说不定哪天系统更新了你的应用就崩了。
关于以上方法的工具类下载

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值