讨论android的设备唯一码

讨论android的设备唯一码

设备唯一码:是用一串字符或者号码来映射唯一的硬件设备。

有啥子用?

  • 统计
    用来统计用户行为,设置大数据标签。一般情况下都是用应用账号作为唯一码,但是只能适合部分强登录应用,对于那种非强登录的app而言,比如购物类,看房类app而言,设备唯一码是用来做大数据统计的唯一选择了。
  • 风控
    防止羊毛党重复注册、重复撸羊毛、恶意访问安全等问题。风控则是最需要稳定可靠的设备唯一码了。
  • 推送
    保证推送唯一性和准确性
  • 错误回传
    统计当前设备错误日志,当指定某用户发生重大崩溃,需要统计该设备崩溃信息,做补救措施。比如单一补丁包或者后端特殊处理。

怎么获取?

有很多特征值都能被当做设备唯一码去使用,但是可靠性和稳定性多多少少有点不符合最好的预期效果。

  • IMEI
    国际移动设备身份码 ,具有GSM/WCDMA/LTE功能的手机才拥有IMEI号,双卡双待手机会有2个IMEI号,可拨号 *#06# 查看。
    具备设备唯一性,不会因为恢复出厂设置和刷机等操作改变,是理想的设备ID 。
    但是在android6.0以后的手机,必须要获取READ_PHONE_STATE权限才能获取到IMEI号,在合规改造的趋势下,这种权限用户不一定会赋予。
    而且在ANDROID 10.0后,即使拥有该权限也不能获取IMEI。
    各大厂的app已经放弃使用IMEI号作为设备唯一码了,都开始设计自己的方案去代替IMEI号了,同时也需要做好设备唯一码迁移适配工作。

获取代码如下,记得加权限

TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        //不同的手机设备返回IMEI,MEID或者ESN码
        String deviceId = tm.getDeviceId();
        //返回IMEI
        String imei = tm.getImei();
        //返回MEID
        String meid = tm.getMeid();
        //手机SIM卡唯一标识
        String simSerialNumber = tm.getSimSerialNumber();
        //返回例如独特的用户ID,一个GSM手机的号码。
        String subscriberId = tm.getSubscriberId();
        //手机号码
        String line1Number = tm.getLine1Number();
  • ANDROID_ID
    设备首次启动时会分配一个64位的数字,并把这个数字以16进制字符串的形式保存下来,这个16进制的字符串就是ANDROID_ID。相对而言,如果不是购物支付类的应用,基本上够用了。
    ANDROID_ID注意以下存在状况:
    厂商定制的系统可能存在ANDROID_ID再不同设备上是一样的,也有可能为null。刷机或者恢复出厂设置就重新分配新的ANDROID_ID了
    如果用户设备是8.0以下,后来卸载了,升级到8.0之后又重装了应用,ANDROID_ID也不一样
 String ANDROID_ID = Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID);
String androidID = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
  • MAC
    获取MAC物理地址,适配性很差。
    6.0以下获取方法(不包括6.0)
//必须的权限  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
      WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
        WifiInfo winfo = wifi.getConnectionInfo();
        String mac =  winfo.getMacAddress();

6.0至7.0获取方法如下(包括6.0,不包括7.0)

private static String getMacAddress() {
    String WifiAddress = "02:00:00:00:00:00";
    try {
        WifiAddress = new BufferedReader(new FileReader(new File("/sys/class/net/wlan0/address"))).readLine();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return WifiAddress;
}

7.0以后获取方法

//需要android.permission.INTERNET权限
  List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

                byte[] macBytes = nif.getHardwareAddress();
                if (macBytes == null) {
                    return null;
                }

                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();
            }

说不定以后再升个级,又要适配。还有就是权限依赖问题导致获取不稳定。
google不推荐使用MAC
https://developer.android.com/training/articles/user-data-ids#java

需求要啥?

往往需求决定你的设备唯一码是在那个纬度上,是应用安装生成纬度,启动纬度,物理设备映射纬度等,选择合适你的方案作为设备唯一码,在保证需求同时稳定性也不错。可以参照国家标准:

中国信息通信研究院所给规范

标识符全称中文
IMEIInternational Mobile Equipment Identity国际移动设备识别码
UDIDUnique Device Identifier设备唯一标识符
OAIDOpen Anonymous Device Identifier匿名设备标识符
VAIDOpen Anonymous Device Identifier开发者匿名设备标识符
AAIDApplication Anonymous Device Identifier应用匿名设备标识符

设备唯一标识符: 是指设备唯一硬件标识,设备生产时根据特定的硬件信息生成,可用于设备的生产环境及合法性校验。
匿名设备标识符: 是可以连接所有应用数据的标识符,移动智能终端系统首次启动后立即生成,可用于广告业务。
开发者匿名设备标识符: 是指用于开放给开发者的设备标识符,可在应用安装时产生,可用于同一开 发者不同应用之间的推荐。
应用匿名设备标识符: 是指第三方应用获取的匿名设备标识,可在应用安装时产生,可用于用户统计等。

按照上面的划分,知道你的需求需要哪一种标识,用相应的标识,当然其方案也不一样,实现的难度也会不一样。

方案选择?

最直接的方案,当然选择中国信息通信研究院所给的sdk,直接去使用就行了。
根据“移动智能终端补充设备标识体系”技术要求,华为、小米、OPPO、vivo、中兴、努比亚、魅族、联想、三星等设备厂商均将逐步实现本标识体系,联盟计划开发并发布支持多厂商的统一的补充设备标识调用SDK,协助移动应用开发者更便捷的访问移动智能终端补充设备标识体系,推进相关业务。
先给出地址大家看下
移动安全联盟
vivo开发平台移动设备标识服务
小米移动设备标示服务

能用官方的方案当然很好,但其实也有很多兼容性问题。很多厂商合作进入体系毕竟晚,导致部分旧机型可能获取不到上面的标识。所以也可以用自己的方案,当然没有官方的稳定可靠。
这里说几个常用的方案:

  • 方案一
    直接获取ANDROID_ID后,再使用UUID去格式化一次。
String androidID = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
UUID deviceUuid = new UUID(androidID.hashCode(), ((long)androidID.hashCode() << 32));

如果用户体量不大,可以当成设备唯一标识符,但是androidid的问题还是会存在。

  • 方案二

安装时生成随机的randomUUID,存储在本地,UUID.randomUUID()对于体量小用户重复概率忽略不计。作为开发者匿名设备标识符是能满足的。

 String randomUUID = UUID.randomUUID().toString();
        //存储在本地
  • 方案三

获取mac地址、imei地址(有就有,无则空)、设备硬件信息、ANDROID_ID等数据后去拼接生成一个新的设备id。当有新的信息变动时候,可以追加为同一设备下的设备id,意思就是说有imei号的生成的设备id和没imei号的生成设备id都视为同一设备id。
有几个核心产数一起拼接作为设备id,去传给后端,不同的策略去处理。
wifiMac为设备mac地址
imeiId 为imei号,如果不能获取到,则拼接0000000000000000的md5值去拼接,后端处理策略会判断ime的值是否存在
deviceBuildID 为不可变的设备参数,比如分辨率(有的机型可以自己改变分辨率,可加可不加)、cpu核心数、cpu型号、屏幕尺寸、内存总大小等参数,这个值很稳定不会变化,但是会重复。可作为imei号没有取到的情况下,作为辅助判断。
deviceBuildIDChange 是刷机会改变的参数,可以作为开发者匿名设备标识符,也可以配合其他参数作为设备唯一码。

 /**
     * 返回一个xx..16位..xx-xx..16位..xx-xx..16位..xx的id
     * 使用md5加密 16位
     * @return
     */
    public String  getDeviceId(){
        StringBuilder sbDeviceId = new StringBuilder();
        //mac地址 如果mac == 02:00:00:00:00:0 视为未获取到
        String wifiMac = md5Decode16(getWifiMac()).toUpperCase();
        sbDeviceId.append(wifiMac);
        sbDeviceId.append("-");


        //imei地址 如果imeiId == "" 视为未获取到
        String imeiId = md5Decode16(getImeiId());
        sbDeviceId.append(imeiId);
        sbDeviceId.append("-");


        //几个核心硬件参数生成的uuid  分辨率 cpu核心数 cpu型号 屏幕尺寸 存储
        //这些是不会随刷机或者返厂设置而改变 但是这些参数单独作为设备id 会大量重复
        String deviceBuildID = md5Decode16(getBuildUUid());
        sbDeviceId.append(deviceBuildID);
        sbDeviceId.append("-");


        //型号 制造商 版本号 android_id
        //会随刷机放生变化
        String deviceBuildIDChange = md5Decode16(getBuildUUidTwo());
        sbDeviceId.append(deviceBuildIDChange);

        return sbDeviceId.toString();

        /**
         * 区分几个纬度,来定义你的需求(假设 wifiMac 和 imeiId 正常获取下 )
         *      如果deviceBuildIDChange 改变 ,而 imeiId deviceBuildID没发生改变
         *      是不是可判断 同一用户下该设备刷机了,视为同一用户,羊毛党屏蔽掉
         *
         *      如果 imeiId 发生改变,换手机了(imeiId 还是作为比较强的 设备映射)
         *
         *      各种策略都可以自己后端定制
         */
        
    }

后面优化,可以加上前端与后端的同步,更加的稳定。
可能上述方案也是有缺陷的,但是当前设备唯一码的现状就是这样。也算上android走向合规、安全的见证人吧。也希望国内的统一方案能解决更多的机型适配问题,这样我们也好偷懒了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值