整理文:Android设备唯一码

整理来源链接
https://www.cnblogs.com/xd502djj/p/8137204.html
https://blog.csdn.net/sunsteam/article/details/73189268

1.MAC地址:

通过Android官方的WifiManager类获取

/**
 *需要添加权限
 *< uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
 */
public String getMacAddress() {
     String macAddress = null ;
     WifiManager wifiManager =(WifiManager)MyApplication.getContext().getSystemService(Context.WIFI_SERVICE);
     WifiInfo info = ( null == wifiManager ? null : wifiManager.getConnectionInfo());
     macAddress = info.getMacAddress();
     return macAddress;
}

缺点:
这种方法虽然能在当前Wifi状态为关闭的情况下获取到MAC地址,但前提是在手机开机后要打开过一次Wifi,如果在某次开机后没打开过Wifi就调用这段代码,获取地址也是为空。
网上给出的解释是:WiFi的Mac address是一个被动资讯。一般在开机后,不会主动上报到系统裡。要待WiFi硬件启动后,才会把有关Mac address资料记载入系统去。

2.IMEI

最常用的IMEI,android系统中通常用下面这段代码获取

/**
  * 获取手机IMEI号
  * 需要动态权限: android.permission.READ_PHONE_STATE
  */
public static String getIMEI(Context context) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
        String imei = telephonyManager.getDeviceId();
        return imei;
    }

缺点:
1.在6.0+系统中是需要动态申请的。如果需求要求App启动时上报设备标识符的话,那么第一会影响初始化速度,第二还有可能被用户拒绝授权。
2.android系统碎片化严重,有的手机可能拿不到DeviceId,会返回null或者000000。
3.IMEI号(国际移动设备身份码)、IMSI号(国际移动设备识别码)这两个是有电话功能的移动设备才具有,也就是说某些没有电话功能的平板是获取不到IMEI和IMSI号的。且在某些设备上getDeviceId()会返回垃圾数据

3.ANDROID_ID

ANDROID_ID 是设备首次启动时由系统随机生成的一串64位的十六进制数字。

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

缺点:
1.设备刷机wipe数据或恢复出厂设置时ANDROID_ID值会被重置。
2.现在网上已有修改设备ANDROID_ID值的APP应用。
3.某些厂商定制的系统可能会导致不同的设备产生相同的ANDROID_ID。
4.某些厂商定制的系统可能导致设备返回ANDROID_ID值为空。
5.CDMA设备,ANDROID_ID和DeviceId返回的值相同

4.序列号SerialNumber

从Android 2.3开始,通过android.os.Build.SERIAL方法可获取到一个序列号。没有电话功能的设备也都需要上给出此唯一的序列号。

String SerialNumber = android.os.Build.SERIAL; 

5.其他方法

1.SimSerialNum – 显而易见,只能用在插了Sim的设备上,通用性不好。而且需要android.permission.READ_PHONE_STATE权限
2.极光推送的设备唯一性标识 RegistrationID

总结

综上述,AndroidId 和 Serial Number 的通用性都较好,并且不受权限限制,如果刷机和恢复出厂设置会导致设备标识符重置这一点可以接受的话,那么将他们组合使用时,唯一性就可以应付绝大多数设备了。

String androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
String id = androidID + Build.SERIAL;

但还可以优化一下。直接暴露用户的设备信息并不是一个好的选择,既然我需要的只是一个唯一标识,那么将他们转化成Md5即可,格式也更整齐。

public class DeviceUtils {
    public static String getUniqueId(Context context){
        String androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
        String id = androidID + Build.SERIAL;
        try {
            return toMD5(id);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return id;
        }
    }
    private static String toMD5(String text) throws NoSuchAlgorithmException {
        //获取摘要器 MessageDigest
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        //通过摘要器对字符串的二进制字节数组进行hash计算
        byte[] digest = messageDigest.digest(text.getBytes());
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < digest.length; i++) {
            //循环每个字符 将计算结果转化为正整数;
            int digestInt = digest[i] & 0xff;
            //将10进制转化为较短的16进制
            String hexString = Integer.toHexString(digestInt);
            //转化结果如果是个位数会省略0,因此判断并补0
            if (hexString.length() < 2) {
                sb.append(0);
            }
            //将循环结果添加到缓冲区
            sb.append(hexString);
        }
        //返回整个结果
        return sb.toString();
    }
}

你可能感兴趣的:(整理文:Android设备唯一码)