精华内容
下载资源
问答
  • 在app开发中接口经常需要客户端传一个唯一的设备ID,用于校验设备重复登录问题等等,我们常常是传Android手机的deviceid,也就是手机的IMEI,IMEI只有android手机才有,是一串15位的号码比如像这样353821030244632...

    转载自:https://www.jianshu.com/p/68839eaf7c72

    引言

    在app开发中接口经常需要客户端传一个唯一的设备ID,用于校验设备重复登录问题等等,我们常常是传Android手机的deviceid,也就是手机的IMEI码,IMEI只有android手机才有,是一串15位的号码比如像这样353821030244632,还有Android ID方案,甚至wlan蓝牙mac地址方案等等。

    获取手机的IMEI方案

     

    TelephonyManager TelephonyMgr = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
    
    String szImei = TelephonyMgr.getDeviceId();
    

    这个方法是Deprecated,后面用getImei替代了,当然最最重要的是需要权限,Android6.0上用户权限需要提示用户,通常用户会因为要一个权限而给你一个差评

    获取android ID

     

    String m_szAndroidID = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
    

    这个到不需求什么权限,但这个方法不靠谱,文档中明确说明当手机恢复出厂设置值就会改变。root手机也可以改变这个值当。

    获取wlan mac地址和蓝牙mac地址

     

    WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
    String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();
    
    BluetoothAdapter m_BluetoothAdapter = null;
    m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    String m_szBTMAC = m_BluetoothAdapter.getAddress();
    

    这两种方案同样是需要权限,特别是蓝牙mac方案如果你的app根本不需要蓝牙,而就因为这个而向用户获取了蓝牙权限,会给用户很可疑的感觉。wlan mac地址方案在没有Wi-Fi网络情况下是无法获取的

    推荐的方案

    Pseudo-Unique ID,API >=9:通过“Build.SERIAL”这个属性来保证ID的独一无二。

     

      String m_szDevIDShort = "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 {
        serial = android.os.Build.class.getField("SERIAL").get(null).toString();
       //API>=9 使用serial号
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    } catch (Exception exception) {
        //serial需要一个初始化
        serial = "serial"; // 随便一个初始化
    }
    //使用硬件信息拼凑出来的15位号码
    return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();

     

    展开全文
  • 本文介绍了浅谈android获取设备唯一标识完美解决方案,分享给大家,具体如下: /** * deviceID的组成为:渠道标志+识别符来源标志+hash后的终端识别符 * * 渠道标志为: * 1,andriod(a) * * 识别符来源...
  • 本文介绍了如何确定Android设备唯一标识 方向一:使用硬件标识 方向二:使用UUID 方向三: 趋于完美的方案

    本文为转载文章,原文链接如下。如有侵权,联系后删除。
    链接

    在这里插入图片描述
    唯一标识必须满足两个特性才能完美解决定位唯一设备的问题,但这个问题的解决却注定只能极限接近完美:
    (1)唯一性:标识必须在所有使用该应用的设备上保持唯一性
    (2)不变性:标识必须在同一设备上保持不变

    一. 方向一:使用硬件标识

    硬件标识实际上在硬件生产之时就被要求满足这两个特性(依然有人工生产的不确定性),但标识的获取趋于困难性,使得使用硬件标识作为唯一识别码的方案所能使用的范围越来越狭窄,不能作为全局方案使用。

    1. 使用 DEVICE_ID

    TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
    String deviceId = tm.getDeviceId();
    

    2. 使用 ANDROID_ID

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

    3. 使用 MAC ADDRESS

    通过获取蓝牙或wifi的Mac地址 作为唯一识别号

    wifiManager = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE));
    String macAddress = wifiManager.getConnectionInfo().getMacAddress();
    

    4. 使用 SERIAL NUMBER

    通过 android.os.Build.SERIAL来获取

    5. 硬件标识的优势与局限性

    优势:几乎完美满足唯一性与不变性

    劣势:
    在这里插入图片描述

    二. 方向二 使用UUID

    这也是官方推荐的生成的唯一标识码生成方式,有一点不同的时,官方方案(在这里)将生成的UUID存在应用内部存储当中,APP的卸载重装会导致发生更改;在实际使用当中我们可以存储到外部存储,除非人为的删除、损坏,这样它的不变性也得到了保障,而它的唯一性则由UUID来保证。

    UUID的实现原理简析:
    Wiki解释:通用唯一识别码(英语:Universally Unique Identifier,缩写:UUID)是用于计算机体系中以识别信息数目的一个128位标识符,还有相关的术语:全局唯一标识符(GUID)。根据标准方法生成,不依赖中央机构的注册和分配,UUID具有唯一性,这与其他大多数编号方案不同。重复UUID码概率接近零,可以忽略不计

    组成: 8-4-4-4-12 xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx M表示 UUID 版本,数字 N的一至三个最高有效位表示 UUID 变体

    UUID根据版本不同,依赖的组成有不同的变种,基于时间的UUID版本是通过计算当前时间戳、随机数和机器MAC地址得到 。UUID的核心算法保证了即使在多处理器同时生成的UUID重复性为0,因为他们所在的时间、空间(节点:通常是MAC地址)必然不一致。

    由于在算法中使用了MAC地址,这个版本的UUID可以保证在全球范围的唯一性。但与此同时,使用MAC地址会带来安全性问题,这就是这个版本UUID受到批评的地方。如果应用只是在局域网中使用,也可以使用退化的算法,以IP地址来代替MAC地址--Java的UUID往往是这样实现的(当然也考虑了获取MAC的难度)。

    String uniqueID = UUID.randomUUID().toString();
    

    三. 趋于完美的方案

    尽可能的获取硬件标识来满足两个特性,在有限制或其他因素的条件下,尽可能满足不变性,将UUID存储在外部环境来进行读写。

    (1)方案思路
    尽可能的获取硬件标识
    硬件标识为空,进行UUID的生成、存储

    (2)方案说明:
    需要在使用之前拿到设备信息权限(没有会导致DeviceID不可取,但仍然可用),外部存储读写权限(必须,否则不可用)
    最好在Application中使用,唯一标识在app与服务器直接交互很常用,放在全局统一的地方方便管理使用

    还有一种方案是拿到设备的某些唯一信息,生成特定的UUID,这样保持不变就可以跳过存储,但是既然拿到了唯一信息,那为啥还要生成UUID呢?

    public class UniqueIDUtils {
    
        private static final String TAG = "UniqueIDUtils";
        private static String uniqueID;
        private static String uniqueKey = "unique_id";
        private static String uniqueIDDirPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();
        private static String uniqueIDFile = "unique.txt";
    
    
        public static String getUniqueID(Context context) {
            //三步读取:内存中,存储的SP表中,外部存储文件中
            if (!TextUtils.isEmpty(uniqueID)) {
                Log.e(TAG, "getUniqueID: 内存中获取" + uniqueID);
                return uniqueID;
            }
            uniqueID = PreferenceManager.getDefaultSharedPreferences(context).getString(uniqueKey, "");
            if (!TextUtils.isEmpty(uniqueID)) {
                Log.e(TAG, "getUniqueID: SP中获取" + uniqueID);
                return uniqueID;
            }
            readUniqueFile(context);
            if (!TextUtils.isEmpty(uniqueID)) {
                Log.e(TAG, "getUniqueID: 外部存储中获取" + uniqueID);
                return uniqueID;
            }
            //两步创建:硬件获取;自行生成与存储
            getDeviceID(context);
            getAndroidID(context);
            getSNID();
            createUniqueID(context);
            PreferenceManager.getDefaultSharedPreferences(context).edit().putString(uniqueKey, uniqueID);
            return uniqueID;
        }
    
        @SuppressLint("MissingPermission")
        private static void getDeviceID(Context context) {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
                return;
            }
            String deviceId = null;
            try {
                deviceId = ((TelephonyManager) context.getSystemService(TELEPHONY_SERVICE)).getDeviceId();
                if (TextUtils.isEmpty(deviceId)) {
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            uniqueID = deviceId;
            Log.e(TAG, "getUniqueID: DeviceId获取成功" + uniqueID);
        }
    
        private static void getAndroidID(Context context) {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            String androidID = null;
            try {
                androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
                if (TextUtils.isEmpty(androidID) || "9774d56d682e549c".equals(androidID)) {
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            uniqueID = androidID;
            Log.e(TAG, "getUniqueID: AndroidID获取成功" + uniqueID);
        }
    
        private static void getSNID() {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            String snID = Build.SERIAL;
            if (TextUtils.isEmpty(snID)) {
                return;
            }
            uniqueID = snID;
            Log.e(TAG, "getUniqueID: SNID获取成功" + uniqueID);
        }
    
    
        private static void createUniqueID(Context context) {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            uniqueID = UUID.randomUUID().toString();
            Log.e(TAG, "getUniqueID: UUID生成成功" + uniqueID);
            File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
            if (!filesDir.exists()) {
                filesDir.mkdir();
            }
            File file = new File(filesDir, uniqueIDFile);
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            FileOutputStream outputStream = null;
            try {
                outputStream = new FileOutputStream(file);
                outputStream.write(uniqueID.getBytes());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    try {
                        outputStream.flush();
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        private static void readUniqueFile(Context context) {
            File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
            File file = new File(filesDir, uniqueIDFile);
            if (file.exists()) {
                FileInputStream inputStream = null;
                try {
                    inputStream = new FileInputStream(file);
                    byte[] bytes = new byte[(int) file.length()];
                    inputStream.read(bytes);
                    uniqueID = new String(bytes);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        public static void clearUniqueFile(Context context) {
            File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
            deleteFile(filesDir);
        }
    
        private static void deleteFile(File file) {
            if (file.isDirectory()) {
                for (File listFile : file.listFiles()) {
                    deleteFile(listFile);
                }
            } else {
                file.delete();
            }
        }
    }
    

    四.希望但又矛盾的完美方案

    硬件标识既然对获取方关闭,那提供基于硬件标识生成的标识(类似UUID)暴露给获取方,但Android10上对于设备隐私的控制又明确了Google是不想app能够长久定位同一台设备的。不过如果基于硬件标识及app包名来生成的呢?

    名词解释
    在这里插入图片描述

    展开全文
  • Android设备唯一识别码的获取

    千次阅读 2020-02-14 13:46:34
    应用设备唯一识别码解决方案 唯一标识必须满足两个特性才能完美解决定位唯一设备的问题,但这个问题的解决却注定只能极限接近完美 唯一性:标识必须在所有使用该应用的设备上保持唯一性 不变性:标识必须在同一...

    应用设备唯一识别码的解决方案
    设备唯一识别码.png
    唯一标识必须满足两个特性才能完美解决定位唯一设备的问题,但这个问题的解决却注定只能极限接近完美

    唯一性:标识必须在所有使用该应用的设备上保持唯一性
    不变性:标识必须在同一设备上保持不变
    方向一:使用硬件标识
    硬件标识实际上在硬件生产之时就被要求满足这两个特性(依然有人工生产的不确定性),但标识的获取趋于困难性,使得使用硬件标识作为唯一识别码的方案所能使用的范围越来越狭窄,不能作为全局方案使用。

    1. 使用 DEVICE_ID
      TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
      String deviceId = tm.getDeviceId();
    2. 使用 ANDROID_ID
      String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
    3. 使用 MAC ADDRESS
      通过获取蓝牙或wifi的Mac地址 作为唯一识别号

    wifiManager = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE));
    String macAddress = wifiManager.getConnectionInfo().getMacAddress();
    4. 使用 SERIAL NUMBER
    通过 android.os.Build.SERIAL来获取

    1. 硬件标识的优势与局限性
      优势:几乎完美满足唯一性与不变性

    劣势:

    硬件标识 局限
    DEVICE_ID - 适用 Android9以下设备,但需要申请Manifest.permission.READ_PHONE_STATE权限

    • 非手机设备不能使用: 如果只带有Wifi的设备或者音乐播放器没有通话的硬件功能的话就没有这个DEVICE_ID
    • 有bug:在少数的一些手机设备上,该实现有漏洞,会返回垃圾,如:zeros或者asterisks的产品
    • Android 10 设备上即使授予权限也会报错Process: com.sj.d_1_adaptiveversion, PID: 8768 java.lang.SecurityException: getUniqueDeviceId: The user 10285 does not meet the requirements to access device identifiers.
      ANDROID_ID - 厂商定制系统的Bug: 不同的设备可能会产生相同的ANDROID_ID:9774d56d682e549c;有些设备返回的值为null;
      适配局限(基本不考虑):在Android <=2.1 or Android >=2.3的版本是可靠、稳定的,但在2.2的版本并不是100%可靠的
      设备差异(不考虑):对于CDMA设备,ANDROID_ID和TelephonyManager.getDeviceId() 返回相同的值
      MAC ADDRESS - 硬件限制:并不是所有的设备都有WiFi和蓝牙硬件
    • 获取的限制:如果WiFi没有打开过,是无法获取其Mac地址的;而蓝牙是只有在打开的时候才能获取到其Mac地址
    • Android 6.0(API 级别 23)到 Android 9(API 级别 28)中,无法通过第三方 API 使用 Wi-Fi 和蓝牙等本地设备 Mac 地址。WifiInfo.getMacAddress() 方法和 BluetoothAdapter.getDefaultAdapter().getAddress() 方法都返回 02:00:00:00:00:00。
      SERIAL NUMBER 经常会返回Unknown
      方向二 使用UUID
      这也是官方推荐的生成的唯一标识码生成方式,有一点不同的时,官方方案(在这里)将生成的UUID存在应用内部存储当中,APP的卸载重装会导致发生更改;在实际使用当中我们可以存储到外部存储,除非人为的删除、损坏,这样它的不变性也得到了保障,而它的唯一性则由UUID来保证。

    UUID的实现原理简析:
    Wiki解释:通用唯一识别码(英语:Universally Unique Identifier,缩写:UUID)是用于计算机体系中以识别信息数目的一个128位标识符,还有相关的术语:全局唯一标识符(GUID)。根据标准方法生成,不依赖中央机构的注册和分配,UUID具有唯一性,这与其他大多数编号方案不同。重复UUID码概率接近零,可以忽略不计

    组成: 8-4-4-4-12 xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx M表示 UUID 版本,数字 N的一至三个最高有效位表示 UUID 变体

    UUID根据版本不同,依赖的组成有不同的变种,

    基于时间的UUID版本是通过计算当前时间戳、随机数和机器MAC地址得到 。UUID的核心算法保证了即使在多处理器同时生成的UUID重复性为0,因为他们所在的时间、空间(节点:通常是MAC地址)必然不一致。

    由于在算法中使用了MAC地址,这个版本的UUID可以保证在全球范围的唯一性。但与此同时,使用MAC地址会带来安全性问题,这就是这个版本UUID受到批评的地方。如果应用只是在局域网中使用,也可以使用退化的算法,以IP地址来代替MAC地址--Java的UUID往往是这样实现的(当然也考虑了获取MAC的难度)。

    String uniqueID = UUID.randomUUID().toString();
    趋于完美的方案
    尽可能的获取硬件标识来满足两个特性,在有限制或其他因素的条件下,尽可能满足不变性,将UUID存储在外部环境来进行读写。

    方案思路
    尽可能的获取硬件标识
    硬件标识为空,进行UUID的生成、存储

    方案说明:

    需要在使用之前拿到设备信息权限(没有会导致DeviceID不可取,但仍然可用),外部存储读写权限(必须,否则不可用)
    最好在Application中使用,唯一标识在app与服务器直接交互很常用,放在全局统一的地方方便管理使用
    还有一种方案是拿到设备的某些唯一信息,生成特定的UUID,这样保持不变就可以跳过存储,但是既然拿到了唯一信息,那为啥还要生成UUID呢?

    public class UniqueIDUtils {
        private static final String TAG = "UniqueIDUtils";
        private static String uniqueID;
        private static String uniqueKey = "unique_id";
        private static String uniqueIDDirPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();
        private static String uniqueIDFile = "unique.txt";
    
    
        public static String getUniqueID(Context context) {
            //三步读取:内存中,存储的SP表中,外部存储文件中
            if (!TextUtils.isEmpty(uniqueID)) {
                Log.e(TAG, "getUniqueID: 内存中获取" + uniqueID);
                return uniqueID;
            }
            uniqueID = PreferenceManager.getDefaultSharedPreferences(context).getString(uniqueKey, "");
            if (!TextUtils.isEmpty(uniqueID)) {
                Log.e(TAG, "getUniqueID: SP中获取" + uniqueID);
                return uniqueID;
            }
            readUniqueFile(context);
            if (!TextUtils.isEmpty(uniqueID)) {
                Log.e(TAG, "getUniqueID: 外部存储中获取" + uniqueID);
                return uniqueID;
            }
            //两步创建:硬件获取;自行生成与存储
            getDeviceID(context);
            getAndroidID(context);
            getSNID();
            createUniqueID(context);
            PreferenceManager.getDefaultSharedPreferences(context).edit().putString(uniqueKey, uniqueID);
            return uniqueID;
        }
    
        @SuppressLint("MissingPermission")
        private static void getDeviceID(Context context) {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
                return;
            }
            String deviceId = null;
            try {
                deviceId = ((TelephonyManager) context.getSystemService(TELEPHONY_SERVICE)).getDeviceId();
                if (TextUtils.isEmpty(deviceId)) {
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            uniqueID = deviceId;
            Log.e(TAG, "getUniqueID: DeviceId获取成功" + uniqueID);
        }
    
        private static void getAndroidID(Context context) {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            String androidID = null;
            try {
                androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
                if (TextUtils.isEmpty(androidID) || "9774d56d682e549c".equals(androidID)) {
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            uniqueID = androidID;
            Log.e(TAG, "getUniqueID: AndroidID获取成功" + uniqueID);
        }
    
        private static void getSNID() {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            String snID = Build.SERIAL;
            if (TextUtils.isEmpty(snID)) {
                return;
            }
            uniqueID = snID;
            Log.e(TAG, "getUniqueID: SNID获取成功" + uniqueID);
        }
    
    
        private static void createUniqueID(Context context) {
            if (!TextUtils.isEmpty(uniqueID)) {
                return;
            }
            uniqueID = UUID.randomUUID().toString();
            Log.e(TAG, "getUniqueID: UUID生成成功" + uniqueID);
            File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
            if (!filesDir.exists()) {
                filesDir.mkdir();
            }
            File file = new File(filesDir, uniqueIDFile);
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            FileOutputStream outputStream = null;
            try {
                outputStream = new FileOutputStream(file);
                outputStream.write(uniqueID.getBytes());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    try {
                        outputStream.flush();
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        private static void readUniqueFile(Context context) {
            File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
            File file = new File(filesDir, uniqueIDFile);
            if (file.exists()) {
                FileInputStream inputStream = null;
                try {
                    inputStream = new FileInputStream(file);
                    byte[] bytes = new byte[(int) file.length()];
                    inputStream.read(bytes);
                    uniqueID = new String(bytes);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        public static void clearUniqueFile(Context context) {
            File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
            deleteFile(filesDir);
        }
    
        private static void deleteFile(File file) {
            if (file.isDirectory()) {
                for (File listFile : file.listFiles()) {
                    deleteFile(listFile);
                }
            } else {
                file.delete();
            }
        }
    }
    

    希望但又矛盾的完美方案
    硬件标识既然对获取方关闭,那提供基于硬件标识生成的标识(类似UUID)暴露给获取方,但Android10上对于设备隐私的控制又明确了Google是不想app能够长久定位同一台设备的。不过如果基于硬件标识及app包名来生成的呢?

    名词解释
    设备码缩写(全称) 定义
    IMEI(International Mobile Equipment Identity) 国际移动电话设备识别码:由15位数字组成的"电子串号",它与每台手机一一对应,而且该码是全世界唯一的
    UUID(Universally Unique Identifier) 全局唯一标识符:指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的,由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得)
    MEID(Mobile Equipment IDentifier ) 是全球唯一的56bit CDMA制式移动终端标识号。标识号会被烧入终端里,并且不能被修改。可用来对CDMA制式移动式设备进行身份识别和跟踪
    IMEI是手机的身份证,MEID是CDMA制式(电信运营的)的专用身份证;IMEI是15位,MEID是14位
    DEVICE_ID Android系统为开发者提供的用于标识手机设备的串号 ; 它根据不同的手机设备返回IMEI,MEID或者ESN码 ;它返回的是设备的真实标识(因此Android10上更新的隐私保护上无法对它进行正常获取了)
    ANDROID_ID 在设备首次启动时,系统会随机生成一个64位的数字,并把这个数字以16进制字符串的形式保存下来 。 当设备被wipe后该值会被重置 (wipe:手机恢复出厂设置、刷机或其他类似操作)
    Serial Number SN码是Serial Number的缩写,有时也叫SerialNo,也就是产品序列号,产品序列是为了验证“产品的合法身份”而引入的一个概念,它是用来保障用户的正版权益,享受合法服务的;一套正版的产品只对应一组产品序列号。SN码别称:机器码、认证码、注册申请码等
    MAC ADDRESS 媒体访问控制地址,也称为局域网地址(LAN Address),以太网地址(Ethernet Address)或物理地址(Physical Address),它是一个用来确认网络设备位置的地址。 在OSI模型中,第三层网络层负责IP地址,第二层数据链接层则负责MAC地址。MAC地址用于在网络中唯一标示一个网卡,一台设备若有一或多个网卡,则每个网卡都需要并会有一个唯一的MAC地址。详细参考WIKI百科
    ESN码 (Electronic Serial Number ) 美国联邦通信委员会规定的,每一台移动设备(例如移动电话、智能手机、平板电脑等)独有的参数,其长度为32位
    ESN码一开始使用于AMPS和D-AMPS手机上,当前则于CDMA手机上最为常见;IMEI则最常使用在GSM制式的手机上

    展开全文
  • 获取手机唯一识别码IMEI

    万次阅读 2017-07-28 11:45:00
    1. 前言获取IMEI相信大家非常...IMEI国际移动设备识别码(IMEI:International Mobile Equipment Identification Number)是区别移动设备的标志,储存在移动设备中,可用于监控被窃或无效的移动设备。目前GSM和WCDMA
    1. 前言

    获取IMEI相信大家非常熟悉,但是项目中使用时,发现当手机卡为电信的时候,获取的并不是IMEI,而是MEID,什么是MEID,为什么会出现这种情况呢?
    IMEI国际移动设备识别码(IMEI:International Mobile Equipment Identification Number)是区别移动设备的标志,储存在移动设备中,可用于监控被窃或无效的移动设备。目前GSM和WCDMA手机终端需要使用IMEI号码
    MEID移动设备识别码(Mobile Equipment Identifier)是CDMA手机的身份识别码,也是每台手机有唯一的识别码。通过这个识别码,网络端可以对该手机进行跟踪和监管。用于CDMA制式的手机。MEID的数字范围是十六进制的,和IMEI的格式类似。

    2.使用方法

    为什么会出现获取的不是IMEI,而是MEID呢,继续往下看。
    一般情况下,大家获取imei号,通过以下两个步骤实现。
    1)添加读取权限:

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    

    2)获取设备imei号

    public static String getImei(Context context) {
            TelephonyManager telephonyMgr = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
            String imei = telephonyMgr.getDeviceId();
            return imei ;
    }
    

    很明显,通过调用getDeviceId()希望获取IMEI,但是得到的却是MEID,定位到getDeviceId()的源码,如下:

    /**
         * 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.
         *
         * <p>Requires Permission:
         *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
         */
        public String getDeviceId() {
            try {
                ITelephony telephony = getITelephony();
                if (telephony == null)
                    return null;
                return telephony.getDeviceId(mContext.getOpPackageName());
            } catch (RemoteException ex) {
                return null;
            } catch (NullPointerException ex) {
                return null;
            }
        }
    

    注释很明显了,CDMA手机返回的是MEID或者ESN,也就是电信卡返回的是MEID,到这里我们发现了问题所在,那么如何解决呢,浏览源码,我们发现,有个隐藏的(hide)方法,如下:

     /**
         * Returns the IMEI. Return null if IMEI is not available.
         *
         * <p>Requires Permission:
         *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
         */
        /** {@hide} */
        public String getImei() {
            return getImei(getDefaultSim());
        }
    

    这个方法可以获取IMEI,但是由于是hide方法,不能直接调用,所以我们只能通过反射调用该方法。

    3.通过反射获取IMEI

    代码很简单,如下所示:

    public static String getMachineImei(Context context) {
            TelephonyManager manager = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
            Class clazz = manager.getClass();
            String imei = "";
            try {
                Method getImei=clazz.getDeclaredMethod("getImei",int.class);//(int slotId)
                getImei.setAccessible(true);
                imei = (String) getImei.invoke(manager);
            } catch (Exception e) {
            }
            return imei;
        }
    

    通过上述反射调用getImei(),则可以在电信卡手机成功获取IMEI号,当前前提是存在IMEI号。


    如有错误欢迎指出来,一起学习。
    在这里插入图片描述

    展开全文
  • 如何确定Android设备唯一识别码

    千次阅读 2020-01-14 10:55:08
    文章目录应用设备唯一识别码解决方案方向一:使用硬件标识1. 使用 DEVICE_ID2. 使用 ANDROID_ID3. 使用 MAC ADDRESS4. 使用 SERIAL NUMBER5. 硬件标识的优势与局限性方向二 使用UUID趋于完美的方案希望但又矛盾的...
  • 通用唯一识别码: UUID

    2018-12-01 16:26:29
    UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。其目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不...
  • 应用设备唯一识别码解决方案 设备唯一识别码.png 唯一标识必须满足两个特性才能完美解决定位唯一设备的问题,但这个问题的解决却注定只能极限接近完美 唯一性:标识必须在所有使用该应用的设备上保持唯一性 ...
  • Android设备获取唯一识别码

    千次阅读 2016-09-20 14:25:53
    在以前,我们的Android设备是手机,这个DEVICE_ID可以同通过TelephonyManager.getDeviceId()获取,它根据不同的手机设备返回IMEI,MEID或者ESN,但它在使用的过程中会遇到很多问题: 非手机设备: ...
  • 参考:http://www.cnblogs.com/xiaowenji/archive/2011/01/11/1933087.html http://www.cnblogs.com/lqminn/p/4204855.html1. DEVICE_ID...它根据不同的手机设备返回IMEI,MEID或者ESN,但它在使用的过程中会遇到很
  • 在Android开发中想要获取手机唯一标识符可能...结合实际需求不亦探索出了比较合理的解决方式。 1、获取设备ID(IMEI) 2、不经过授权获取唯一标识符 3、权限请求 4、绕过默认权限请求 查看App支持的API版本 5、参考文献
  • 1 引言 近年来,钱币、特别是纸币被抢劫事件不断发生,严重影响了社会治安...另外,由于纸币号码的唯一性,通过识别纸币上的号码,可以帮助识别假币。国外有一种验钞打号机,可以对典型的纸币,比如美元、英镑等进行自
  • 前言 今天一天都在下雨 仿佛和我心情对照 早上...一开始 进入虹软人脸识别获取数据的时候 没有再次 去请求权限 理由是:登录的时候 请求过了 因为出现了摄像头黑屏 我以为是权限的问题 结果又请求一遍 CAMERA 结果:
  • Android唯一识别码

    千次阅读 2013-11-20 10:57:58
    我们在项目过程中或多或少会使用到设备的唯一识别码,我们希望能够得到一个稳定、可靠的设备唯一识别码。今天我们将介绍几种方式。  1. DEVICE_ID 假设我们确实需要用到真实设备的标识,可能就需要用到...
  • Android手机唯一识别IMSI

    千次阅读 2015-03-03 10:16:31
    以前在开发APP的时候使用的是手机的IMEI作为唯一表示机器 ,但是当刷机、系统还原出厂设置 这2种情况下,手机的IMEI都会改变,所以有时候回出现以前绑定的IMEI在服务 数据库对应的用户移动设备,当用户刷机、还原...
  • 先来看一个问题:假设一个网络系统每秒钟需要保存数十万来自用户提交的信息,并分配一个id给每条信息用于以后唯一标识它,那么怎么产生这个id呢?不能重复又要足够快以支持高并发,有这么强大的单台服务器吗?即便有...
  • IOS 第一帖关于无法拿到唯一识别码的方法这一贴是证明我已经从一个android工程师,成功转型为一个iOS工程师,在客户端开发的路上越走越远这次遇到的问题是,上线的iOS版本仿制被刷稍微入行的都知道现在iOS是拿不到...
  • 人脸识别技术原理及解决方案

    万次阅读 2018-08-10 17:00:48
    人脸识别系统的研究始于20世纪60年代,80年代后随着计算机技术和光学成像技术的发展得到提高,而真正进入初级的应用阶段则在 90年后期,以美国、德国和日本的技术实现为主。 人脸识别技术是基于人的脸部特征,对...
  • 最近做的几个项目都用到了软件加密问题,使用加密狗控制软件使用和安装就会碰到一个问题:就是如何识别客户端电脑的唯一性?  网上查了一下,有这么几种解决方案:  1、通过硬盘出厂编号;  (缺点是:有...
  • Android 唯一识别码

    2012-08-11 22:51:12
    我们在项目过程中或多或少会使用到设备的唯一识别码,我们希望能够得到一个稳定、可靠的设备唯一识别码。今天我们将介绍几种方式。  1. DEVICE_ID 假设我们确实需要用到真实设备的标识,可能就需要用到DEVICE...
  • 最近在做一个OA考勤项目,里面有个需求是一个账号只允许绑定一台设备, 这就需要将设备唯一标识与账号绑定在一起,咋一听 这还不So Easy啊,直接获取deviceID 不就好了。。。 问题 private String getSerial() { ...
  • 解决这一难题的唯一出路在于采用生物识别技术进行身份认证,而语音生物特征(声纹)识别唯一可用于非接触式、通过电话网络远程安全控制的生物识别方法。  语音生物特征识别,又称说话人识别,俗称声纹识别,是...
  • 安卓/iOS获取唯一标识

    千次阅读 2016-11-03 14:47:17
    苹果生成唯一标识UDID是Unique Device Identifier的缩写,中文意思是设备唯一标识. 在很多需要限制一台设备一个账号的应用中经常会用到,在Symbian时代,我们是使用IMEI作为设备的唯一标识的,可惜的是Apple官方不...
  • 因为需要在项目中需要获得一个稳定、可靠的设备唯一识别码,因此搜了一些网上的资料。今天我们将介绍几种方式。  1. DEVICE_ID  假设我们确实需要用到真实设备的标识,可能就需要用到DEVICE_ID。在以前,我们的...
  • 有很多场景和需求你需要用到手机设备的唯一标识符。在Android中,有以下几种方法获取这样的ID。 The IMEI: 仅仅只对Android手机有效: public String getIMEI() { TelephonyManager TelephonyMgr = ...
  • 有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一识别码。虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。而通过其他...
  • 获取Android设备唯一标识

    千次阅读 2017-03-20 11:36:58
    有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一识别码。虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。而通过其他...
  • 公司开发的游戏需要对用户设备进行标识,获得一个稳定可靠并且唯一识别码,来作游客登录。并考虑后续玩家从游客换成账户登录数据要同步过来。 虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、...
  • 最近做的一个项目中需要用到Android设备唯一码(UUID)来标识一台设备, Android中设备唯一码有很多,如:MAC地址、IMEI号(DeviceId)、IMSI号、ANDROID_ID、序列号(SerialNumber)等, 但并不是所有设备上都能...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 101,333
精华内容 40,533
关键字:

怎么解决识别唯一码