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

2023-05-16

安卓设备的唯一标识的方法并不唯一,也没有哪种方法能够适用于所有的Android设备,下面列出几种常见的方式,可以根据需要选择。

1.IMEI 码

IMEI(国际移动设备识别码)唯一编号,用于识别 GSM,WCDMA手机以及一些卫星电话(移动设备识别码)全球唯一编号,用于识别CDMA移动电台设备的物理硬件,MEID出现的目的是取代ESN号段(电子序列号)(电子序列号)唯一编号,用于识别CDMA手机(国际移动用户识别码)与所有GSM和UMTS网络手机用户相关联的唯一识别编号如需要检索设备的ID,在项目中要使用以下代码:

/**
 * 获取手机IMEI号
 * 
 * 6.0 以上需要动态权限: 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;
}

它有3个缺点:

1)需要android.permission.READ_PHONE_STATE权限,它在6.0+系统中是需要动态申请的。如果需求要求App启动时上报设备标识符的话,那么第一会影响初始化速度,第二还有可能被用户拒绝授权。

2)android系统碎片化严重,有的手机可能拿不到DeviceId,会返回null或者000000。

3)这个方法是只对有电话功能的设备有效的,在pad上不起作用。 可以看下方法注释

/**
 * 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;
	}
}

2.AndroidId

在设备首次启动时,系统会随机生成一个64位的数字,并把这个数字以16进制字符串的形式保存下来。不需要权限,平板设备通用。获取成功率也较高,缺点是设备恢复出厂设置会重置。另外就是某些厂商的低版本系统会有bug,返回的都是相同的AndroidId。
厂商定制系统的Bug:不同的设备可能会产生相同的ANDROID_ID:9774d56d682e549c。
厂商定制系统的Bug:有些设备返回的值为null。
设备差异:对于CDMA设备,ANDROID_ID telephonyManager.getDeviceId() 返回相同的值。
它在Android <=2.1 or Android >=2.3的版本是可靠、稳定的,但在2.2的版本并不是100%可靠的。
通常被认为不可信,因为它有时为null。开发文档中说明了:这个ID会改变如果进行了出厂设置。并且,如果某个Andorid手机被Root过的话,这个ID也可以被任意改变。获取方式如下:

public static String getAndroidId (Context context) {
    String ANDROID_ID = Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);
    return ANDROID_ID;
}

3.Serial Number

Android系统2.3版本以上可以通过下面的方法得到Serial Number,且非手机设备也可以通过该接口获取。不需要权限,通用性也较高,但有些手机显示异常,也不一定靠谱。

String SerialNumber = android.os.Build.SERIAL; 

4.Mac地址

可以使用手机Wifi或蓝牙的MAC地址作为设备标识。
属于Android系统的保护信息,高版本系统获取的话容易失败,返回0000000

硬件限制:并不是所有的设备都有Wifi和蓝牙硬件,硬件不存在自然也就得不到这一信息。
添加权限:ACCESS_WIFI_STATE
获取到的,不是一个真实的地址,而且这个地址能轻易地被伪造。wLan不必打开,就可读取些值。

public static String getMac (Context context) {
    //wifi mac地址
    WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    WifiInfo info = wifi.getConnectionInfo();
    String wifiMac = info.getMacAddress();
    if(!isEmpty(wifiMac)){
        return wifiMac;
    }
    return "";
}

5.SimSerialNum

显而易见,只能用在插了Sim的设备上,通用性不好。而且需要android.permission.READ_PHONE_STATE权限

6.生成UUID,并保存至系统数据库中

如果上述方式都不能获取到唯一编码,可尝试使用UUID将其保存到系统数据库中,这样卸载之后,这个值还在;但6.0 以后需要动态申请权限,慎用。

/**
 * 得到全局唯一UUID,保存数据到系统数据库中:Settings.System
 */
public static String getUUID(Context context) {
	String uniqueIdentificationCode = "";
	//首先判断系统版本,高于6.0,则需要动态申请权限
	if (Build.VERSION.SDK_INT >= 23) {
		if (!Settings.System.canWrite(context)) {
			Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
					Uri.parse("package:" + getPackageName()));
			context.startActivity(intent);
		} else {
			uniqueIdentificationCode = Settings.System.getString(context.getContentResolver(), "uniqueIdentificationCode");
		}
	} else {
		//获取系统配置文件中的数据,第一个参数固定的,但是需要上下文,第二个参数是之前保存的Key,第三个参数表示如果没有这个key的情况的默认值
		uniqueIdentificationCode = Settings.System.getString(context.getContentResolver(), "uniqueIdentificationCode");
	}

	if (TextUtils.isEmpty(uniqueIdentificationCode)) {
		uniqueIdentificationCode = System.currentTimeMillis() + UUID.randomUUID().toString().substring(20).replace("-", "");
		//设置系统配置文件中的数据,第一个参数固定的,但是需要上下文,第二个参数是保存的Key,第三个参数是保存的value
		Settings.System.putString(context.getContentResolver(), "uniqueIdentificationCode", uniqueIdentificationCode);
	}
	Log.i("getDeviceUuidId", "getDeviceUuidId: uniqueIdentificationCode = " + uniqueIdentificationCode);

	return uniqueIdentificationCode;
}

总结

综上述,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();
    }
}

参考博文:https://blog.csdn.net/sunsteam/article/details/73189268
https://blog.csdn.net/jiangtea/article/details/72889018

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

获取安卓设备唯一标识方法总结 的相关文章

  • ubuntu 出现 core dump 和 segment fault 错误

    在Linux环境下执行程序的时候 xff0c 有的时候会出现段错误 xff08 segment fault xff09 xff0c 同时显示core dumped 就像下面这样 xff1a 1 15428 segmentation faul
  • Linux实现文件定期本地备份/异地备份/删除备份的脚本

    一 背景 1 总会出出现环境上的数据丢失 xff0c 在没有备份的情况下会非常的被动 xff0c 不管是由于病毒还是人为的原因造成的程序 数据被删除 xff0c 有时候后悔已经来不及 xff0c 不如提前做到数据的备份 xff0c 而异地备
  • strace -f strace ls 引发的问题

    strace 是Linux下常用的跟踪程序系统调用的工具 strace简介 可使用 strace lt cmd gt 来跟踪 cmd 所使用的系统调用 xff0c 原理是 strace 进程 fork 一个子进程并使用 ptrace 系统调
  • Ubuntu22.04搭建Pytorch框架深度学习环境+安装Miniconda+安装CUDA与cuDNN

    Linux搭建深度学习环境 以Ubuntu为例 xff0c 从零搭建Pytorch框架深度学习环境 1 Ubuntu安装 1 1 系统下载 访问地址ubuntu官网 1 2 启动盘制作 访问ultraiso官网 1 2 1打开镜像 1 2
  • ARM 立即寻址之立即数的形成 —— 如何判断有效立即数

    依据指令中给出的操作数的不同格式 xff0c ARM 指令系统具有 8 种常见的寻址方式 我们这次就来讨论一下立即寻址 文章目录 立即寻址的特点立即数形式合法立即数立即寻址机器指令格式指令解析判断方法例子 0x0000f200例子 0x23
  • 调用函数返回一个场景renderer并实现多场景在同一窗口显示

    问题 xff1a 函数调用想要返回renderer场景 智能指针类型同样也可以作为函数的返回值 正确的写法类似 xff1a vtkSmartPointerMyFunction vtkSmartPointer myObject 61 vtkS
  • 完美解决Python与anaconda之间的冲突问题,你值得拥有

    anaconda指的是一个开源的Python发行版本 xff0c 其包含了conda Python等180多个科学包及其依赖项 因为包含了大量的科学包 xff0c Anaconda 的下载文件比较大 xff08 约 515 MB xff09
  • win10和linux关闭端口的命令

    win10的相关命令 1 查 xff1a netstat ano findstr 8080 2 杀 xff1a taskkill PID 5616 F 也可以使用netstat ano 查看所有的端口 netstat命令详解 xff1a n
  • nmap

    nmap nmap 简介 xff1a namp也称Network Mapper 是一款多平台的网络连接扫描软件 xff0c 可以探测计算机网络上的主机和服务 在渗透初期为了绘制目标网络拓扑图 xff0c 需要到Nmap对目标网络发送特定的数
  • 日期和时间格式

    时间和日期格式 span class token keyword import span java span class token punctuation span util span class token punctuation sp
  • JDBC优化

    三层架构 JDBC事务 DBUtils 今日内容 1 三层架构 2 三层架构结合事务 3 ThreadLocal解决事务问题 4 DAO通用封装方法 5 DbUtils的使用 ooOoo o8888888o 88 34 34 88
  • 关于x86_64和x32和x86和-386和32位还是64位的区分 指令集的学习

    这里写自定义目录标题 一 xff0c 查到的知识查看linux内核信息查看linux版本信息查看当前的系统位数其他搜索到的信息 指令集和指令集架构的区分 关于x86 64和x32和x86和 386和32位还是64位的区分 一 xff0c 查
  • C++并发编程

    C 43 43 11多线程 xff1a 1 多线程概念 C 43 43 11新增了对多线程的支持 xff0c 提供了 lt atomic gt lt mutex gt 和 lt thread gt 初步支持 xff0c 但仍不完美 使用并发
  • go语言入门二 代码试验 api在线编程

    试验 一个试验代码 span class token comment 要求开发一个hello go程序 span span class token keyword package span main span class token key
  • vscode go 2022-3-20最新测试的插件安装失败的解决办法

    前期准备工作 可以直接看最下面 xff0c 我有把bin中的exe文件放到网盘 tools文件也放网盘了 伸手党请帮忙点个赞 环境变量的配置 xff0c 直接上图吧 xff0c 今天配置这玩意太心累了 高级系统设置 环境变量的配置 还有一个
  • go语言import报错处理

    import 认识 go的import有两种形式 第一种是GOPATH下项目文件管理 第二种是Go Modules 初学状态我用的vscode 在两个文件夹中调用全局变量 在地址引用时出现错误 通过查询知道了两种方法之间的区别就在与GO11
  • MYSQL多表查询面试题三

    1 显示所有员工的姓名 xff0c 部门号和部门名称 span class token keyword SELECT span e span class token punctuation span last name span class
  • 学习日志以及日志的前世今生

    先看这个链接 https www cnblogs com lalalazar p 15694889 html 提到log4j就不得不提其主要贡献者 xff0c ceki gulcu 从1996年开始出来日志 简单总结 log4j 最早出现
  • 理解匿名内部类和lambda表达式和stream流的使用方法

    1 概念 我这里理解的来源1 韩顺平老师的30天学java的课件中的概念 一个类的内部又完整的嵌套了另一个类结构 xff0c 被嵌套的类策划归纳为内部类 xff08 inner class xff09 嵌套其他类的类称为外部类 xff08

随机推荐

  • nginx安装 nginx安装报403错误

    致敬 xff01 第二次安装nginx 第一次安装后 xff0c 放入页面 xff0c 前端图片总是不出来 经过多次配置nginx conf文件还是不出来 xff0c 只得放弃make编译安装形式 xff0c 从新安装 先卸载上次安装 xf
  • 3D slicer编译(Windows)

    3D slicer编译 xff08 Windows xff09 1 安装依赖2 设置源文件目录和构建目录3 配置和构建slicer4 调试参考资料 1 安装依赖 我的安装依赖 xff1a Git version xff1a 2 33 1 Q
  • Cityscapes数据集转换成COCO类型和VOC类型

    本来想用本数据集拿来做基线测试 xff0c 突然发现gtFine里面没有适合我小白看的xml或txt 十分痛苦 看了许多帖子 终于找到一位好心博主整理的内容 按照流程应该最后成功了 想必从coco转成其他数据类型 脚本应该很多了 在此附上某
  • 虚拟机Linux磁盘扩容

    按照该方式 xff0c 虚拟机磁盘成功扩容 注意 xff1a 有快照的虚拟机无法直接扩容 xff0c 建议先备份 xff0c 再删除快照 xff0c 进行扩容 xff0c 以防万一 xff01 xff01 xff01 1 关闭虚拟机 xff
  • 单片机利用Proteus进行仿真点亮一个LED灯(C语言和汇编语言)

    Proteus仿真图 xff1a c语言程序 xff1a span class token macro property span class token directive keyword include span span class
  • 搭建hadoop开源版本分布式集群(无高可用)

    搭建hadoop开源版本分布式集群 xff08 无高可用 xff09 在搭建之前需要安装jdk xff0c 并设置环境变量 最低要求版本jdk1 8 1 修改各个节点名称 vim etc hostname 修改之后reboot重启生效 2
  • visual studio2019+vcpkg管理第三方库(含使用Git管理工具下载vcpkg方法,已解决)

    问题简述 通常在使用vs做项目的时候要用到一些第三方库 xff0c 我在学习Eigen的过程中由于没有安装第三方库便遇到了这样的一个问题 xff1a 无法打开源文件 34 eigen3 Eigen Dense 34 如图1所示 xff1a
  • 【更新多方案】青龙面版解决服务异常,请手动执行ql check检查服务状态

    有问题可以加群讨论讨论下 113815925 简单粗暴解决问题不想啰嗦一大堆 1 检测青龙环境并修复 ql check 2 检测依赖文件并修复 docker exec it qinglong bin bash ql 3 更新并重启青龙 ql
  • 【需要magisk面具】旧手机搭建青龙面版,本地跑青龙【等我有时间整合下机器人以及内网穿透】

    本教程所需113815925群内下载 前期准备 首先在旧手机上安装BusyBox magisk juicessh三个软件 xff0c 网上都能搜索到 BusyBox是一个集成了一百多个最常用 linux 命令和工具的软件 xff0c 用于给
  • 【免root】旧安卓手机本地运行青龙面板[termux高级终端]

    前期准备 下载zerotermux和青龙恢复包并且安装zwerotermux 软件需要后台运行所以我们要打开设置 xff0c 找到电池 xff0c 点击后台耗电管理找到zerotermux然后允许软件后台高耗电 xff08 每部手机设置不同
  • 青龙面版跑QQ阅读

    手机写的教程将就看 本博客QQ群 113815925 可以的话填我的邀请码 121519165 谢谢 首先我们得去配置17行设置下拉取后缀sh 然后就是拉库 ql raw https ghproxy com https raw github
  • 利用青龙面版实现cpolar穿透内网

    之前的钉钉穿透 xff0c 被你们薅跑了 cpolar内网穿透拉库 ql raw https ghproxy com https raw githubusercontent com jiankujidu cpolar main nwct c
  • 随身WIFI debian安装docker

    安装docker环境 1 切换root sudo i 2 更新源 xff1a sudo apt get update 3 安装工具 xff1a sudo apt get install curl wget apt transport htt
  • 随身WIFI刷入debian

    本文使用的型号为UFI001 必须刷入boot xff0c 有adb才能玩 xff0c 也可以直接刷入 其他型号请参考大佬的文章 https www kancloud cn handsomehacker openstick 2636505
  • 傻妞恢复包带短信登录(迟来的恢复包)

    傻妞恢复包 magisk模块就不启动青龙 xff0c 添加下容器就可以 目录全部在 data data com termux files home local share tmoe linux containers proot ubuntu
  • A1153

    题意 xff1a 输入准考证号 xff0c 考试分数 然后输入查询命令 xff0c 对每个命令按照要求模拟输出 思路分析 xff1a 命令为1 xff1a 表示查询考 级的所有记录 xff0c 按照成绩从大到小排名 xff0c 成绩相同则按
  • 电脑显示WiFi已连接,但无法访问internet怎么解决?

    我在玩游戏的时候电脑突然卡崩了 xff0c 我无奈的重启了一下 xff0c 结果电脑重启后连不上网了 xff0c 我开始以为还在重新连接 xff0c 在等待 xff0c 过了好久才发现其实早就连上wifi了 xff0c 但显示无法连接int
  • Python-Django-模型

    一 ORM 模型介绍 1 ORM 模型 对象关系映射 xff08 英语 xff1a Object Relational Mapping xff0c 简称ORM xff0c 或ORM xff0c 或OR mapping xff09 xff0c
  • LeetCodeWeeklyContest-159

    最近看了篇文章 xff0c 文章里说 希望你身边能有个比你聪明五倍 xff0c 但却比你还努力十倍的人 倍数虽然有些夸张 xff0c 但是这个思想还是能get到的 5230 缀点成线 在一个 XY 坐标系中有一些点 xff0c 我们用数组
  • 获取安卓设备唯一标识方法总结

    安卓设备的唯一标识的方法并不唯一 xff0c 也没有哪种方法能够适用于所有的Android设备 xff0c 下面列出几种常见的方式 xff0c 可以根据需要选择 1 IMEI 码 IMEI xff08 国际移动设备识别码 xff09 唯一编