前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Android 上关于设备唯一标识的调研

Android 上关于设备唯一标识的调研

作者头像
用户1269200
发布于 2018-12-29 02:03:52
发布于 2018-12-29 02:03:52
3.5K00
代码可运行
举报
文章被收录于专栏:刘望舒刘望舒
运行总次数:0
代码可运行

作者:千山万水迷了鹿 https://www.jianshu.com/p/fd34fa2ddcd9

一、先来明白几个概念:

什么是IMEI? IMEI(International Mobile Equipment Identity)是国际移动设备身份码的缩写,国际移动装备辨识码,是由15位数字组成的"电子串号",它与每台手机一一对应,而且该码是全世界唯一的。每一部手机在组装完成后都将被赋予一个全球唯一的一组号码,这个号码从生产到交付使用都将被制造生产的厂商所记录。IMEI码由GSM(全球移动通信协会)统一分配,授权BABT(英国通信认证管理委员会)审受。 IMEI组成为: 1、前6位数(TAC,Type ApprovalCode)是"型号核准号码",一般代表机型。 2、接着的2位数(FAC,Final Assembly Code)是"最后装配号",一般代表产地。 3、之后的6位数(SNR)是"串号",一般代表生产顺序号。 4、最后1位数(SP)通常是"0",为检验码,备用。 一般在Android手机上可以在关于手机里面查看到 什么是IMSI? 国际移动用户识别码(IMSI:International Mobile Subscriber Identification Number)是区别移动用户的标志,储存在SIM卡中,可用于区别移动用户的有效信息。其总长度不超过15位,同样使用0~9的数字。 什么是ICCID? ICCID:Integrate circuit card identity 集成电路卡识别码(固化在手机SIM卡中),简单来说就是SIM卡序列号,它拥有独一无二的特性,类似于手机的序列号,仅仅指向一张手机卡。共有20位数字组成,不同运营商编码格式不一样。并且前六位数字为运营商代码:比如中国移动的为:898600;中国联通的为:898601,中国电信的为:898603。

简而言之:IMEI / MEID 是和设备相关的,移动设备的唯一标志码;而IMSI 和 ICCID 是和手机卡相关的,信息存储到手机卡上,没有安装手机卡的手机,上面获取这两个值为null。

二、TelephonyManager 相关
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//注意代码使用需要在Manifest配置权限
// <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
//在API 23(Android6.0 )及其以上版本phone组权限需要动态申请
TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);  
String deviceid = tm.getDeviceId();   //取 IMEI或者MEID
String tel = tm.getLine1Number();     //取出用户手机号码,手机没有安装SIM卡,值为null
String imsi =tm.getSubscriberId();     //取出IMSI,手机没有安装SIM卡,值为null
String imei =tm.getSimSerialNumber();  //取出ICCID,手机没有安装SIM卡,值为null

其实上面的信息分开来看总共分为两部分,一部分是设备相关的信息,一部分是SIM卡相关的信息。关于SIM卡相关的信息,一般来说没有办法标志设备,因为手机可以任意替换SIM卡,而且现在手机都是双卡双待的,关于双卡手机获取和手机卡相关的信息参考这篇文章 我们这里主要关心设备ID(IMEI或者MEID),解释下这两个东西:IMEI是国际移动设备识别码的简称,而MEID是 动设备识别码的简称,一般IMEI是所有设备都有,而MEID一般只在只有支持CDMA制式的设备才有的。 OPPO 手机:进入手机设置--常规--关于手机--状态信息--IMEI即可看到。 小米手机: 设置--我的设备--全部参数--状态信息---IMEI信息 华为手机:设置---关于手机

注意:平板没有imei号

三、设备唯一ID

1. IMEI或者MEID

Android系统关于双卡的支持的知识需要知道一些,在Android4.x及其以下版本的时候,原生Android是不支持双卡的,在5.x左右开始支持,但是api是隐藏的,在Android 6.0 才开始公开开放双卡的API。

来看下我们获取IMEI或者MEID的基本方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//注意动态权限申请
TelephonyManager telephonyManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
String imei = telephonyManager.getDeviceId();

这个方法在4.x及其以下版本的时候,运行这个方法是没有问题的,因为4.x是不支持双卡的,也就是说4.x的手机要么是GSM要么是CDMA制式的。所以,getDeviceId的文档这样写道:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * Returns the unique device ID, for example, the IMEI for GSM and the MEID
     * or ESN for CDMA phones. Return null if device ID is not available.
     * 翻译过来就是:这个方法会返回唯一的设备id,
     * 比如在GSM的手机上返回的是IMEI,而在CDMA 手机上返回的是MEID或者ESN。
     * 如果设备id不可读取,那么返回null。
     */

但是这种情况到了Android 6.0 (先不考虑5.x 那个版本不稳定)上就不一样了,6.0支持双卡,也就是说手机上不可以能只有一个IMEI或者MEID,这个时候就需要根据手机卡槽获取了,这个卡槽里面装的是什么制式的卡,那么对于下标获取的就是IMEI或者MEID:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public void onClick(View view) {

        TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);

        Log.d("Q_M", "meid:" + tm.getDeviceId());
        Log.d("Q_M", "meid:" + tm.getDeviceId(0));
        Log.d("Q_M", "meid:" + tm.getDeviceId(1));

    }

测试结果来自网络,我没有验证(我对不插卡的情况存在疑问): 我的两张联通卡分别获取的是imei1和imei2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    1、不插卡(或两张卡都是GSM卡)

      getDeviceId()  返回 imei1
      getDeviceId(0) 返回 imei1
      getDeviceId(1) 返回 imei2

      2、卡1CDMA卡,卡2不插卡(或卡2GSM卡)

      getDeviceId()   返回 meid
      getDeviceId(0) 返回 meid
      getDeviceId(1) 返回 imei2

      3、卡1不插卡(或卡1GSM卡)卡2CDMAgetDeviceId()   返回 imei1
      getDeviceId(0) 返回 imei1
      getDeviceId(1) 返回 meid

后来到了Android 8.0 ,方法控制更为精细了,所以这个getDeviceId 方法就被废弃了,不再推荐使用。而推荐使用 getImei和getMeid 同时这两个方法支持传入卡槽的下标来确定要读取那个卡对应的值。在8.0 及其以上的手机上可以这么严重:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public void onClick(View view) {

        TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);

        //手机上存在两个imei值,分配给两个卡槽
        Log.d("Q_M", "imei:" + tm.getImei());
        Log.d("Q_M", "imei0:" + tm.getImei(0));
        Log.d("Q_M", "imei1:" + tm.getImei(1));

        //手机上只会存在一个meid,两个卡槽获取的一样
        Log.d("Q_M", "meid:" + tm.getMeid());
        Log.d("Q_M", "meid0:" + tm.getMeid(0));
        Log.d("Q_M", "meid1:" + tm.getMeid(1));
    }

最后来看一眼友盟的代码里面获取 Imei 的方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static String getImeiNew(Context var0) {
        String var1 = null;

        try {
            if(var0 != null) {
                TelephonyManager var2 = (TelephonyManager)var0.getSystemService("phone");
                if(var2 != null && checkPermission(var0, "android.permission.READ_PHONE_STATE")) {
                    if(VERSION.SDK_INT >= 26) {
                        try {
                            Method var3 = var2.getClass().getMethod("getImei", new Class[0]);
                            var3.setAccessible(true);
                            var1 = (String)var3.invoke(var2, new Object[0]);
                        } catch (Exception var4) {
                            ;
                        }

                        if(TextUtils.isEmpty(var1)) {
                            var1 = var2.getDeviceId();
                        }
                    } else {
                        var1 = var2.getDeviceId();
                    }
                }
            }
        } catch (Exception var5) {
            if(AnalyticsConstants.UM_DEBUG) {
                MLog.w("No IMEI.", var5);
            }
        }

        return var1;
    }

2. ANDROIDID 在设备首次启动时,系统会随机生成一个64位的数字,并把这个数字以16进制字符串的形式保存下来,这个16进制的字符串就是ANDROID_ID,当设备被wipe后该值会被重置。设备恢复出厂设置,这个值也会改变。如果设备被root,这个值可以任意改变。 String androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);

3. Serial Number (设备序列号) 这个东西理论上来说是来自硬件,出厂是就设置好了,但是有些设备厂商会随便写一个值 Build.SERIAL 在 api>=26的时候 可以这么获取 Build.getSerial();

4. Mac地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!--访问WIFI的权限-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> 

Mac地址,在6.0以上不能按正常方式获取,7.0以上很难获取,并且Mac地址也不一定唯一。

4.1 在6.0 以下后去mac地址方式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo winfo = wifi.getConnectionInfo();
String mac =  winfo.getMacAddress();

4.2 在6.0 及其以上8.0以下 上面的方法在7.0 的设备获取的永远是02:00:00:00:00:00

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 通过网络接口取
     * 记得添加网络权限
     * <uses-permission android:name="android.permission.INTERNET" />
     *
     * @return mac 地址字符串
     */
    private static String getNewMac() {
        try {
            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();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

注:通过adb命令行可以查看手机mac地址,不过需要root手机:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ adb shell 
$ su 
$ cat /sys/class/net/wlan0/address

【参考文章】 http://www.cnblogs.com/sfbrzkh/p/5165873.html https://developer.android.com/training/articles/user-data-ids https://blog.csdn.net/yangbin0513/article/details/68490291

— — — END — — —

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 刘望舒 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2022最新手机设备标识码(IMEI、MEID、UDID、UUID、ANDROID_ID、GAID、IDFA等)教程
(International Mobile Equipment Identity) 是国际移动设备身份码的缩写,国际移动装备辨识码,只有Android手机才获取的到,是由15位数字组成的"电子串号",比如像这样 359881030314356,它与每台移动电话机一一对应,而且该码是全世界唯一的。
iOS Magician
2023/03/21
4.9K0
2022最新手机设备标识码(IMEI、MEID、UDID、UUID、ANDROID_ID、GAID、IDFA等)教程
2022最新手机设备标识码(IMEI、MEID、UDID、UUID、ANDROID_ID、GAID、IDFA等)教程
(International Mobile Equipment Identity) 是国际移动设备身份码的缩写,国际移动装备辨识码,只有Android手机才获取的到,是由15位数字组成的"电子串号",比如像这样 359881030314356,它与每台移动电话机一一对应,而且该码是全世界唯一的。
爱学iOS的小麦子
2023/05/09
4.3K0
Android 获取MEID以及IMEI
只需要五行代码 不过要注意加权限 <!-- 允许程序读写手机状态和身份 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 代码如下 //实例化TelephonyManager对象 TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); M
longzeqiu
2019/08/14
5.7K1
Android 设备唯一标识(适配Android版本)
  相信在看这篇文章之前你已经看过一些类似的文章了,那么你肯定知道自己想要的是什么。
晨曦_LLW
2020/12/16
4.6K0
Android 设备唯一标识(适配Android版本)
Android笔记: 获取手机的品牌、型号、Android系统版本号、IMEI、当前系统语言等工具类
最近在开发中,需要用到一些系统信息,这里我把这些方法写成一个工具类方便以后复用,该工具类有以下6个功能:
程思扬
2022/01/10
2.4K0
获取Android设备DeviceId与反Xposed Hook技术
APP开发中常需要获取设备的DeviceId,以应对刷单,目前常用的几个设备识别码主要有IMEI(国际移动设备身份码 International Mobile Equipment Identity)或者MEID(Mobile Equipment IDentifier),这两者也是常说的DeviceId,不过Android6.0之后需要权限才能获取,而且,在Java层这个ID很容易被Hook,可能并不靠谱,另外也可以通过MAC地址或者蓝牙地址,序列号等,暂列如下:
看书的小蜗牛
2018/06/29
2.8K0
android获取设备唯一标示
概述 有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码。虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。而通过其他硬件信息标识也因为系统版本、手机硬件等限制存在不同程度的问题。 下面收集了一些“有能力”或“有一定能力”作为设备标识的串码。 DEVICE_ID 这是Android系统为开发者提供的用于标识手机设备的串号,也是各种方法中普适性较高的,可以说几乎所有的设备都可以返回这个串号,并且唯一性
xiangzhihong
2018/01/30
7.1K0
羊皮书APP(Android版)开发系列(十)Android开发常用工具类
Android开发过程中,我们需要的很多代码都是重复多次使用的,写成工具类是一个比较好的做法,下面是我常用的几个工具类,也希望对你有所帮助。分别是:日期格式化工具、转换图片颜色工具、app启动引导页控制工具、Intent 工具、手机信息采集工具、存储和访问SharedPreferences工具、正则表达式工具、SD卡片工具、Toast信息工具、app版本工具、错误信息反馈工具、类型转换工具。 大家可到github上下载代码AndroidUtils。 日期格式化工具 package cn.studyou
热心的程序员
2018/08/30
9040
Android开发笔记(一百二十八)手机制式适配
虽然现在4G网络很普及了,但是我国幅员辽阔,4G信号在某些地方接收不良,手机连接很容易掉到3G甚至2G网络。为了让用户在低速环境也能使用App的基础功能,而不至于还在老牛破车地缓慢下载大图,App就得判断当前所处的网络环境,从而针对不同的网络连接提供相应的访问模式;比如在4G网络下默认完整模式,在2G/3G网络下默认切换到极简模式。 查看网络类型等信息,用到了电话管理器TelephonyManager,它的对象从系统服务TELEPHONY_SERVICE中获取,相关方法说明如下: getNetworkOperator : 获取运营商代码。返回五位数字的字符串,前三位表示移动国家代码(Mobile Country Code,简称MCC),后两位表示移动网络代码(Mobile Network Code,简称MNC)。 getNetworkOperatorName : 获取运营商名称。如中国移动、中国联通、中国电信等等。 getPhoneType : 获取电话类型。返回1表示GSM,2表示CDMA,3表示SIP。 getNetworkType : 获取网络类型。这个网络类型包含每代网络的细分类型,可表示GPRS、CDMA、EvDo、HSPA、LTE等等。 getNetworkTypeName : 获取网络类型的名称。隐藏方法,需使用反射机制调用。 getNetworkClass : 获取网络分代。隐藏方法,需使用反射技术调用。返回1表示2G,返回2表示3G,返回3表示4G。 下面是查看具体手机上网络类型的截图,第一张图片为使用移动号码的网络信息,第二张图片为使用联通号码的网络信息。
aqi00
2019/01/18
2.2K0
项目实战工具类(一):PhoneUtil(手机信息相关)
可以使用的功能: 1、获取手机系统版本号 2、获取手机型号 3、获取手机宽度 4、获取手机高度 5、获取手机imei串号 ,GSM手机的 IMEI 和 CDMA手机的 MEID. 6、获取手机sim卡号 7、获取手机号 8、判断sd卡是否挂载 9、获取sd卡剩余空间的大小 10、获取sd卡空间的总大小 11、判断是否是平板 12、判断一个apk是否安装 13、拨打电话 14、打开网页 15、获取应用权限 名称列表 16、获取手机内安装的应用 17、获取手机安装非系统应用 18、获取安装应
听着music睡
2018/06/08
7750
一行代码帮你检测Android模拟器
博客:https://www.jianshu.com/p/434b3075b5dd
陈宇明
2020/12/15
4.3K0
一行代码帮你检测Android模拟器
Android加密解析
编码.数字摘要.加密.解密 UrlEncoder /Urldecoder String str = "http://www.baidu.com?serach = 哈哈"; String
六月的雨
2022/01/12
5240
Android加密解析
android 单点登录功能
很多伙伴在开发自己公司产品的时候,一般都会考虑用户账号安全 ,或者用户账号功能使用限制等问题。这时候我们就会考虑到单点登录这个功能。
再见孙悟空_
2023/02/10
5810
android 监听网络状态的变化及实战
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/53008266
程序员徐公
2018/09/17
4.8K0
android 监听网络状态的变化及实战
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名......) 获取设备id 获取ip地址 获取设备名称 获取设备型号 获取设备处理器 获取设备品牌 获取设备制造商 获取设备oaid 获取设备识别码 获取mac地址 获取应用包名 获取应用签名 获取app版本 获取版本号 获取分辨率 获取国家码 获取系统语言 获取设备网络代码 获取设备网络类型 获取android版
是阿超
2021/12/30
5.5K0
推荐阅读
相关推荐
2022最新手机设备标识码(IMEI、MEID、UDID、UUID、ANDROID_ID、GAID、IDFA等)教程
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档