你有几种实现方案Android 设备唯一标识?

Android 获取UUID两种方法 阅读详情

前言

项目开发中,多少会遇到这种需求:获得设备唯一标识DeviceId,用于:
1.标识一个唯一的设备,做数据精准下发或者数据统计分析;
2.账号与设备绑定;
3.....

分析

这类文章,网上有许多资料,例如:使用IMEI、MAC等作为设备标识使用。
不过,看过这些文章或者深入调研的同学应该都清楚,这些数据均存在缺陷:有的因为权限无法获取到,有的获取出来是重复的,有的完全获取不到,也就是说不能完美的解决设备唯一的问题。

那么,用什么数据才能表示设备唯一呢?

方案

方案1:UUID + SharePreference(存取)

APP首次使用时,创建UUID,并保存到SharePreference中。
以后再次使用时,直接从SharePreference取出来即可;

优点:数据唯一、不需要权限;
缺点:会随APP一起删除,即:重新安装APP,DeviceId值会改变(新UUID);

方案2:UUID + SD卡(存取)

APP首次使用时,创建UUID,并保存到SD卡中。
以后再次使用时,直接从SD卡取出来即可;
很多APP就是这么做的;

优点:数据唯一、不随APP一起删除;
缺点:需要SD卡读写权限;防不住用户手动删除SD卡的文件;

方案3:imei + android_id + serial + 硬件uuid(自生成)

如果,又想唯一,又不想因用户的删除而重新生成UUID,该怎么做呢?

不依赖随机的UUID,咱们根据硬件标识来创建唯一的数据;

我们可以将多个可获得的硬件标识拼接起来(尽可能不依赖权限),最大程度上降低重复性。
以imei、android_id、serial为例,如果能取到值,每个数据几乎可以代表唯一。
如果这些数据都能获取到,拼起来的数据重复性降到极低(UUID也存在重复性,重复性极低而已)

那么,哪些硬件标识合适呢?

AndroidId : 如:df176fbb152ddce,无需权限,极个别设备获取不到数据或得到错误数据;
serial:如:LKX7N18328000931,无需权限,极个别设备获取不到数据;
IMEI : 如:23b12e30ec8a2f17,需要权限;
Mac: 如:6e:a5:....需要权限,高版本手机获得数据均为 02:00.....(不可使用)
Build.BOARD  如:BLA  主板名称,无需权限,同型号设备相同
Build.BRAND  如:HUAWEI  厂商名称,无需权限,同型号设备相同
Build.HARDWARE  如:kirin970  硬件名称,无需权限,同型号设备相同
Build......更多硬件信息,略

分析了这么多硬件标识,我们就使用imei + android_id + serial + 硬件UUID(使用Build属性生成,如果硬件信息不变,则UUID值不变)。这是我们项目的实际方案,大家也可根据自己的需要自由组合硬件标识。

那么,问题又来了,不同设备的硬件标识长度不同,拼接处理的DeviceId字符串长度不同,怎么才能统一长度呢?

也很简单,我们先拼接好DeviceId数据,取其SHA1值,再转16进制即可(统一40位长度)

实现

import android.content.Context;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;

import java.security.MessageDigest;
import java.util.Locale;
import java.util.UUID;

/**
 * @author xc
 * @date 2018/11/16
 * @desc
 */
public class DeviceIdUtil {
    /**
     * 获得设备硬件标识
     *
     * @param context 上下文
     * @return 设备硬件标识
     */
    public static String getDeviceId(Context context) {
        StringBuilder sbDeviceId = new StringBuilder();

        //获得设备默认IMEI(>=6.0 需要ReadPhoneState权限)
        String imei = getIMEI(context);
        //获得AndroidId(无需权限)
        String androidid = getAndroidId(context);
        //获得设备序列号(无需权限)
        String serial = getSERIAL();
        //获得硬件uuid(根据硬件相关属性,生成uuid)(无需权限)
        String uuid = getDeviceUUID().replace("-", "");

        //追加imei
        if (imei != null && imei.length() > 0) {
            sbDeviceId.append(imei);
            sbDeviceId.append("|");
        }
        //追加androidid
        if (androidid != null && androidid.length() > 0) {
            sbDeviceId.append(androidid);
            sbDeviceId.append("|");
        }
        //追加serial
        if (serial != null && serial.length() > 0) {
            sbDeviceId.append(serial);
            sbDeviceId.append("|");
        }
        //追加硬件uuid
        if (uuid != null && uuid.length() > 0) {
            sbDeviceId.append(uuid);
        }

        //生成SHA1,统一DeviceId长度
        if (sbDeviceId.length() > 0) {
            try {
                byte[] hash = getHashByString(sbDeviceId.toString());
                String sha1 = bytesToHex(hash);
                if (sha1 != null && sha1.length() > 0) {
                    //返回最终的DeviceId
                    return sha1;
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        //如果以上硬件标识数据均无法获得,
        //则DeviceId默认使用系统随机数,这样保证DeviceId不为空
        return UUID.randomUUID().toString().replace("-", "");
    }

    //需要获得READ_PHONE_STATE权限,>=6.0,默认返回null
    private static String getIMEI(Context context) {
        try {
            TelephonyManager tm = (TelephonyManager) 
context.getSystemService(Context.TELEPHONY_SERVICE);
            return tm.getDeviceId();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获得设备的AndroidId
     *
     * @param context 上下文
     * @return 设备的AndroidId
     */
    private static String getAndroidId(Context context) {
        try {
            return Settings.Secure.getString(context.getContentResolver(), 
Settings.Secure.ANDROID_ID);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获得设备序列号(如:WTK7N16923005607), 个别设备无法获取
     *
     * @return 设备序列号
     */
    private static String getSERIAL() {
        try {
            return Build.SERIAL;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获得设备硬件uuid
     * 使用硬件信息,计算出一个随机数
     *
     * @return 设备硬件uuid
     */
    private static String getDeviceUUID() {
        try {
            String dev = "3883756" +
                    Build.BOARD.length() % 10 +
                    Build.BRAND.length() % 10 +
                    Build.DEVICE.length() % 10 +
                    Build.HARDWARE.length() % 10 +
                    Build.ID.length() % 10 +
                    Build.MODEL.length() % 10 +
                    Build.PRODUCT.length() % 10 +
                    Build.SERIAL.length() % 10;
            return new UUID(dev.hashCode(), 
Build.SERIAL.hashCode()).toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
    }

    /**
     * 取SHA1
     * @param data 数据
     * @return 对应的hash值
     */
    private static byte[] getHashByString(String data)
    {
        try{
            MessageDigest  messageDigest = MessageDigest.getInstance("SHA1");
            messageDigest.reset();
            messageDigest.update(data.getBytes("UTF-8"));
            return messageDigest.digest();
        } catch (Exception e){
            return "".getBytes();
        }
    }

    /**
     * 转16进制字符串
     * @param data 数据
     * @return 16进制字符串
     */
    private static String bytesToHex(byte[] data){
        StringBuilder sb = new StringBuilder();
        String stmp;
        for (int n = 0; n < data.length; n++){
            stmp = (Integer.toHexString(data[n] & 0xFF));
            if (stmp.length() == 1)
                sb.append("0");
            sb.append(stmp);
        }
        return sb.toString().toUpperCase(Locale.CHINA);
    }
}

调用

String deviceId = DeviceIdUtil.getDeviceId(application);

结果输出:FE00DDE9298310CDFEEFE69229B8DB248534710F

总结

方案1局限性较大,不建议使用;
方案2是很多软件采用的方案,因很少有人删除SD卡文件;但需要注意权限;
方案3相较于前两种方案,限制性较小,只要硬件信息不变结果就不变。而且该方案可自行定制组合。
究竟哪种方案合适,大家应根据自己的项目需求,合理选择才是。

Android获取设备唯一标识 一、IMEI:国际移动设备识别码的缩写,其总长为15位,每位数字仅使用0~9的数字。 双卡双待会有两个IMEI值,并且在Android10以后就无法获取到了,而且在模拟器中是可以修改的,所以该值无法作为识别设备唯一的标识。(如果只带有Wifi的设备或者音乐播放器没有通话的硬件功能的话就没有这个IMEI值) IMEI的获取方式: 1、Android6.0以前,无需任何权限通过getDeviceId()方法获取到IMEI码; 2、Android6.0-Android8.0之间,需要申请READ_PHONE_ST 阅读详情

相关推荐

Unity获取手机设备唯一标识-方案探讨

讲解当前环境下 获取安卓手机设备唯一标识的可行方案, 分析优劣势以及容易踩的坑. 前言 公司开发的游戏需要对用户设备进行标识,获得一个稳定可靠并且唯一的识别码,来作游客登录。并考虑后续玩家从游客换成账户登录数据要同步过来。 虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。而通过其他硬件信息标识也因为系统版本、手机硬件等限制存在不同程度的问题。 下面汇总了一些能作为设备唯一标识的方案。 方案 方案大致分为三个方向 安卓系统原生

weixin_44186849的博客 6216

iOS上架之android设备uuid、udid使用教程

而uuid除了表达硬件的唯一标识,还能用来标识软件的标识,比如手机上不同的app的UUID是互斥的。然而随着Android版本的升级,获取设备ID却越来越难了。IMEI本该最理想的设备ID,具备唯一性,恢复出厂设置不会变化(真正的设备相关),可通过拨打*#06# 查询手机的imei码。第一,如果用户安装APP设备是8.0以下,后来卸载了,升级到8.0之后又重装了应用,Android ID不一样;Android ID 是获取门槛最低的,不需要任何权限,64bit 的取值范围,唯一性算是很好的了。

不写代码没饭吃的博客 4842

Android 设备唯一标识(适配Android版本)

首先是一个知识清单:(对于现在的Android及移动互联网来说,我们需要掌握的技术)泛型原理丶反射原理丶Java虚拟机原理丶线程池原理丶注解原理丶注解原理丶序列化Activity知识体系(Activity的生命周期丶Activity的任务栈丶Activity的启动模式丶View源码丶Fragment内核相关丶service原理等)代码框架结构优化(数据结构丶排序算法丶设计模式)APP性能优化(用户体验优化丶适配丶代码调优)热修复丶热升级丶Hook技术丶IOC架构设计。

2401_87034185的博客 2300

在Android中获取手机的唯一标识码的方法

在Android中获取手机的唯一标识码的方法

baidu_38317922的博客 6307

Android唯一标识生成方案

友盟有个统计功能,每当你的App在新的设备上安装过,友盟的后台就能统计到新增设备。 当你卸载程序,再次安装。友盟后台却能分辨出你这不是一台新的设备。 这个到底是怎么做到的,首先让我想到的是获取手机的唯一标识IMEI,并上传到服务器,对比判断是不是新的设备 Android设备唯一标识生成方案

专注Android的老王 9120

Android生成唯一标识符UUID(完全替代IMEI)

Android生成唯一标识符UUID(完全替代IMEI),项目真实有效。

安卓唯一标识:IMEI,MEID,MAC地址,Android_id,UUID,OAID

安卓设备的唯一标识,获取的目的在于数据统计,广告归因分析等用途。常用作唯一标识的有IMEI,MEID,MAC地址,Android_id,UUID,OAID等。国际移动设备识别码(International Mobile Equipment Identity,IMEI),即通常所说的手机序列号、手机“串号”,用于在移动电话网络中识别每一部独立的手机等移动通信设备,相当于移动电话的身份证。序列号共有15~17位数字,前8位(TAC)是型号核准号码(早期为6位),是区分手机品牌和型号的编码。

2万+

ArcGIS Pro 3.0 加载天地图WMTS服务,解决偏移问题的保姆级教程(附最新Key申请流程)

本文详细介绍了在ArcGIS Pro 3.0中精准加载天地图WMTS服务的全流程,包括最新Key申请流程、解决地图偏移问题的关键配置步骤以及常见问题排查方法。通过设置`esri`参数和统一坐标参考,确保地理数据与天地图底图精确匹配,提升GIS空间分析的准确性。

weixin_28713947的博客 302

获取Android设备唯一标识码

有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码。虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。而通过其他硬件信息标识也因为系统版本、手机硬件等限制存在不同程度的问题。下面收集了一些“有能力”或“有一定能力”作为设备标识的串码。

木牛的博客 5689

SRC漏洞挖掘实战指南:从零入门到月入过万的网络安全副业

网络安全的核心在于识别和修复系统缺陷,其中逻辑漏洞与信息泄露是常见的安全风险。其原理在于应用程序在业务逻辑设计或数据处理过程中存在缺陷,导致未授权访问或敏感数据暴露。掌握这些技术对于构建安全的应用体系至关重要,不仅能有效防范攻击,也为安全研究人员提供了将技术能力变现的合法途径。在漏洞赏金(Bug Bounty)和SRC(安全应急响应中心)等应用场景中,白帽子通过系统化的测试方法,挖掘此类漏洞,既能获得经济回报,又能积累宝贵的实战经验。本文聚焦于逻辑漏洞与信息泄露的实战挖掘技巧,为初学者提供清晰的入门路径和效

weixin_28568819的博客 346

树莓派4B没有serial0或ttyS0,serial0没有映射到ttyS0,serial0和serial1调换映射

环境: 树莓派4B,ubuntu mate20 现象 终端输入ls -l /dev,发现只有serial1->ttyAMA0,没有serial0页没有ttyS0,更没有二者的映射。网上很多方法都是树莓派3B和3B+的,我自己试过,不太适用于4B,下面的方法是4B的,我自己用是成功的。 解决方法 cd /boot/firmware sudo gedit config.txt 注意不是/boot下的config,而是/boot/firmware下的config 打开文件后,找到enable_uart=0

qq_41208487的博客 7890

android byte转string_你有几种实现方案Android 设备唯一标识?

前言项目开发中,多少会遇到这种需求:获得设备唯一标识DeviceId,用于:1.标识一个唯一的设备,做数据精准下发或者数据统计分析;2.账号与设备绑定;3.....分析这类文章,网上有许多资料,例如:使用IMEI、MAC等作为设备标识使用。不过,看过这些文章或者深入调研的同学应该都清楚,这些数据均存在缺陷:有的因为权限无法获取到,有的获取出来是重复的,有的完全获取不到,也就是说不能完美的解决设备唯...

weixin_39774556的博客 239

Ubuntu服务器通过IPV6端口转发搭建幻兽帕鲁私服实战

本文详细介绍了在Ubuntu服务器上通过IPV6端口转发搭建幻兽帕鲁私服的完整教程。针对只有公网IPV6地址的服务器环境,提供了从硬件检查、端口转发工具配置到游戏服务器安装的全流程解决方案,帮助玩家轻松实现多人联机游戏体验。

weixin_30652491的博客 490

android byte[] 转string 好多问号_你有几种实现方案Android 设备唯一标识?

前言项目开发中,多少会遇到这种需求:获得设备唯一标识DeviceId,用于:1.标识一个唯一的设备,做数据精准下发或者数据统计分析;2.账号与设备绑定;3.....分析这类文章,网上有许多资料,例如:使用IMEI、MAC等作为设备标识使用。不过,看过这些文章或者深入调研的同学应该都清楚,这些数据均存在缺陷:有的因为权限无法获取到,有的获取出来是重复的,有的完全获取不到,也就是说不能完美的解决设备唯...

weixin_33860377的博客 176

基于 STM32 的智慧农业温室控制系统设计与实现

本文提出一种基于 STM32 微控制器的智慧农业温室控制系统设计方案,通过集成多类型环境传感器、执行机构及无线通信模块,实现对温室内温湿度、光照、土壤湿度等参数的实时监测与自动调控。文中详细阐述硬件选型、电路连接及软件实现流程,并附关键代码示例,为智慧农业领域提供低成本、高可靠性的温室控制解决方案。

weixin_42300449的博客 1923

Win7 x64位系统下几乎完美使用安装RTX3050 6G显卡驱动详细教程

RTX3050 6G显卡驱动安装指南:由于该显卡发布时间晚于驱动,需手动修改安装文件。首先在NVIDIA官网下载驱动并解压,通过设备管理器获取硬件ID(PCI\VEN_10DE&DEV_2584),然后在解压目录的.inf文件中添加对应的设备标识。安装完成后可能出现设备管理器感叹号问题,推荐通过命令提示符启用测试模式(bcdedit /set testsigning on)解决,此方法无需每次启动按F8,但会显示测试模式水印。文中提供了详细的图文操作步骤和两种解决方案。

m0_67194883的博客 2886

android 16进制 全透明_你有几种实现方案Android 设备唯一标识?

前言项目开发中,多少会遇到这种需求:获得设备唯一标识DeviceId,用于:1.标识一个唯一的设备,做数据精准下发或者数据统计分析;2.账号与设备绑定;3.....分析这类文章,网上有许多资料,例如:使用IMEI、MAC等作为设备标识使用。不过,看过这些文章或者深入调研的同学应该都清楚,这些数据均存在缺陷:有的因为权限无法获取到,有的获取出来是重复的,有的完全获取不到,也就是说不能完美的解决设备唯...

weixin_39609500的博客 163

Spring Boot集成ShardingSphere实现数据加密及数据脱敏 | Spring Cloud 48

利用ShardingSphere实现: - 数据加密 - 数据脱敏

gmHappy 1万+

Android 设备唯一标识(多种实现方案)

前言 项目开发中,多少会遇到这种需求:获得设备唯一标识DeviceId,用于: 1.标识一个唯一的设备,做数据精准下发或者数据统计分析; 2.账号与设备绑定; 3..... 分析 这类文章,网上有许多资料,例如:使用IMEI、MAC等作为设备标识使用。 不过,看过这些文章或者深入调研的同学应该都清楚,这些数据均存在缺陷:有的因为权限无法获取到,有的获取出来是重复的,有的完全获取不到,也就是说不能完美的解决设备唯一的问题。 那么,用什么数据才能表示设备唯一呢? 方案 方案1:UUID + Sh

Venus 的博客 6399

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

获取安卓设备唯一标识方法总结

安卓设备的唯一标识的方法并不唯一,也没有哪种方法能够适用于所有的Android设备,下面列出几种常见的方式,可以根据需要选择。 1.IMEI 码 IMEI(国际移动设备识别码)唯一编号,用于识别 GSM,WCDMA手机以及一些卫星电话(移动设备识别码)全球唯一编号,用于识别CDMA移动电台设备的物理硬件,MEID出现的目的是取代ESN号段(电子序列号)(电子序列号)唯一编号,用于识别CDM...

Sindyue的博客 1万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

android获取设备唯一标识完美解决方案

转自:https://blog.csdn.net/aa1733519509/article/details/50053553 有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码。虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。而通过其他硬件信息标识也因为系统版本、手机硬件等限制存在不同程度的...

auccy的博客 3万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【亲测免费】 Android_CN_OAID: 安卓设备唯一标识解决方案教程

--- ## 项目介绍 **Android_CN_OAID** 是一个专为安卓开发者设计的库,旨在提供一种便捷的方式来获取多种设备标识,特别是针对国内手机厂商的开放匿名标识(OAID)和海外设备的安卓广告标识(AAID)。此项目是为了替代那些企业级、需要特定资质的统一SDK,如移动安全联盟(MSA)提供的闭源方案。它不仅包含了OAID和AAID的获取,还兼容了IMEI、MEID、Android...

gitblog_00301的博客 1936

Android设备唯一标识(终极方案!)

Android设备唯一标识 背景 Android系统中并没有可靠获取所有厂商设备唯一ID的方法,各个方法都有自己的使用范围和局限性,这也是目前流行的Android系统版本过多,设备也是来自不同厂商,且没有统一标准等原因造成的。 常规方案 DEVICE_ID MAC ADDRESS 设备序列号Serial Number ANDROID_ID 手机硬件信息 DEVICE_ID DEVICE_ID可以同通过getSystemService(Context.TELEPHONY_SERVICE).getDevic

feipengwang的博客 2万+

php 手机设备标识,Android 获取设备唯一标识的几种方案

Android 获取设备唯一标识的几种方案Android获取设备号,Android设备标识,Android获取唯一标识2018-04-17 09:57:36在项目中,获取设备的惟一标识是一个很常见的需求,比较早的一种方式是调用 TelephonyManager.getDeviceId() 方法来获取 Device Id。但是这种方式还是存在一些问题。首先它是需要权限的,所有很多时候,你可能会获取不...

weixin_32386693的博客 881

android获取设备唯一标识

这里列举了获取所有可以获取到的设备唯一识别码:getDeviceId()。 我的设备是TV,获取不到IMEI,但是有以太网口,所以最好的办法是获取以太网mac作为唯一标识。 public class MobileInfoUtil { private static String wifiTag = "wlan0";//无线标志,关闭wifi开关后获取不到 private stati...

MR CUI的专栏 3385
上一篇: Android一行解决所有双击优化的问题
下一篇: 重磅来袭:Android UI 线程更新UI也会崩溃???
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值