详解Android获取设备唯一ID的几种方式
发布时间 - 2026-01-11 01:45:15 点击率:次先来看看几种比较单一的方式:

IMEI
方式:TelephonyManager.getDeviceId():
问题
- 范围:只能支持拥有通话功能的设备,对于平板不可以。
- 持久性:返厂,数据擦除的时候不彻底,保留了原来的标识。
- 权限:需要权限:Android.permission.READ_PHONE_STATE
- bug: 有些厂家的实现有bug,返回一些不可用的数据
Mac地址
ACCESS_WIFI_STATE权限
有些设备没有WiFi,或者蓝牙,就不可以,如果WiFi没有打开,硬件也不会返回Mac地址,不建议使用
ANDROID_ID
2.2(Froyo,8)版本系统会不可信,来自主要生产厂商的主流手机,至少有一个普遍发现的bug,这些有问题的手机相同的ANDROID_ID: 9774d56d682e549c
但是如果返厂的手机,或者被root的手机,可能会变
Serial Number
从Android 2.3 (“Gingerbread”)开始可用,可以通过android.os.Build.SERIAL获取,对于没有通话功能的设备,它会返回一个唯一的device ID,
以下几个是stackoverflow上评论较多的几个,没贴完,还有其他,综合的,用到以上的部分方式:
地址:http://stackoverflow.com/questions/2785485/is-there-a-unique-android-device-id
有兴趣的朋友可以再仔细看看
支持率比较高的(支持票数157):androidID --> 剔除2.2版本(API 8)中有问题的手机,使用UUID替代
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class DeviceUuidFactory {
protected static final String PREFS_FILE = "device_id.xml";
protected static final String PREFS_DEVICE_ID = "device_id";
protected static volatile UUID uuid;
public DeviceUuidFactory(Context context) {
if (uuid == null) {
synchronized (DeviceUuidFactory.class) {
if (uuid == null) {
final SharedPreferences prefs = context
.getSharedPreferences(PREFS_FILE, 0);
final String id = prefs.getString(PREFS_DEVICE_ID, null);
if (id != null) {
// Use the ids previously computed and stored in the
// prefs file
uuid = UUID.fromString(id);
} else {
final String androidId = Secure.getString(
context.getContentResolver(), Secure.ANDROID_ID);
// Use the Android ID unless it's broken, in which case
// fallback on deviceId,
// unless it's not available, then fallback on a random
// number which we store to a prefs file
try {
if (!"9774d56d682e549c".equals(androidId)) {
uuid = UUID.nameUUIDFromBytes(androidId
.getBytes("utf8"));
} else {
final String deviceId = ((TelephonyManager)
context.getSystemService(
Context.TELEPHONY_SERVICE)
.getDeviceId();
uuid = deviceId != null ? UUID
.nameUUIDFromBytes(deviceId
.getBytes("utf8")) : UUID
.randomUUID();
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
// Write the value out to the prefs file
prefs.edit()
.putString(PREFS_DEVICE_ID, uuid.toString())
.commit();
}
}
}
}
}
/**
* Returns a unique UUID for the current android device. As with all UUIDs,
* this unique ID is "very highly likely" to be unique across all Android
* devices. Much more so than ANDROID_ID is.
*
* The UUID is generated by using ANDROID_ID as the base key if appropriate,
* falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
* be incorrect, and finally falling back on a random UUID that's persisted
* to SharedPreferences if getDeviceID() does not return a usable value.
*
* In some rare circumstances, this ID may change. In particular, if the
* device is factory reset a new device ID may be generated. In addition, if
* a user upgrades their phone from certain buggy implementations of Android
* 2.2 to a newer, non-buggy version of Android, the device ID may change.
* Or, if a user uninstalls your app on a device that has neither a proper
* Android ID nor a Device ID, this ID may change on reinstallation.
*
* Note that if the code falls back on using TelephonyManager.getDeviceId(),
* the resulting ID will NOT change after a factory reset. Something to be
* aware of.
*
* Works around a bug in Android 2.2 for many devices when using ANDROID_ID
* directly.
*
* @see http://code.google.com/p/android/issues/detail?id=10603
*
* @return a UUID that may be used to uniquely identify your device for most
* purposes.
*/
public UUID getDeviceUuid() {
return uuid;
}
}
根据版本进行判断的方式:Serial序列号-->UUID (支持数31)
通过Serial 即可,在覆盖率上,你已经成功的获得了98.4%的用户,剩下的1.6%的用户系统是在9 以下的。
通过AndroidID获取,前面已经说过,在8上,有些商家的手机会有一些bug,返回相同的AndroidID,如果Serial和AndroidID都不行
/**
* Return pseudo unique ID
* @return ID
*/
public static String getUniquePsuedoID()
{
// If all else fails, if the user does have lower than API 9 (lower
// than Gingerbread), has reset their phone or 'Secure.ANDROID_ID'
// returns 'null', then simply the ID returned will be solely based
// off their Android device information. This is where the collisions
// can happen.
// Thanks http://www.pocketmagic.net/?p=1662!
// Try not to use DISPLAY, HOST or ID - these items could change.
// If there are collisions, there will be overlapping data
String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);
// Thanks to @Roman SL!
// http://stackoverflow.com/a/4789483/950427
// Only devices with API >= 9 have android.os.Build.SERIAL
// http://developer.android.com/reference/android/os/Build.html#SERIAL
// If a user upgrades software or roots their phone, there will be a duplicate entry
String serial = null;
try
{
serial = android.os.Build.class.getField("SERIAL").get(null).toString();
// Go ahead and return the serial for api => 9
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}
catch (Exception e)
{
// String needs to be initialized
serial = "serial"; // some value
}
// Thanks @Joe!
// http://stackoverflow.com/a/2853253/950427
// Finally, combine the values we have found by using the UUID class to create a unique identifier
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}
不用READ_PHONE_STATE权限直接获取ROM信息的方式:(支持率较低 16)
String m_szDevIDShort = "35" + //we make this look like a valid IMEI
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 digits
最后贴上自己在项目中用的:
public static String getDeviceId(Context context) {
String deviceId = "";
if (deviceId != null && !"".equals(deviceId)) {
return deviceId;
}
if (deviceId == null || "".equals(deviceId)) {
try {
deviceId = getLocalMac(context).replace(":", "");
} catch (Exception e) {
e.printStackTrace();
}
}
if (deviceId == null || "".equals(deviceId)) {
try {
deviceId = getAndroidId(context);
} catch (Exception e) {
e.printStackTrace();
}
}
if (deviceId == null || "".equals(deviceId)) {
if (deviceId == null || "".equals(deviceId)) {
UUID uuid = UUID.randomUUID();
deviceId = uuid.toString().replace("-", "");
writeDeviceID(deviceId);
}
}
return deviceId;
}
// IMEI码
private static String getIMIEStatus(Context context) {
TelephonyManager tm = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
String deviceId = tm.getDeviceId();
return deviceId;
}
// Mac地址
private static String getLocalMac(Context context) {
WifiManager wifi = (WifiManager) context
.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
return info.getMacAddress();
}
// Android Id
private static String getAndroidId(Context context) {
String androidId = Settings.Secure.getString(
context.getContentResolver(), Settings.Secure.ANDROID_ID);
return androidId;
}
public static void saveDeviceID(String str) {
try {
FileOutputStream fos = new FileOutputStream(file);
Writer out = new OutputStreamWriter(fos, "UTF-8");
out.write(str);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String readDeviceID() {
StringBuffer buffer = new StringBuffer();
try {
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
Reader in = new BufferedReader(isr);
int i;
while ((i = in.read()) > -1) {
buffer.append((char) i);
}
in.close();
return buffer.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
对于获取设备唯一ID并没有绝对的方案,这一点在android的官方博客中也提到了,不过以上几种方案,应该可以满足平时的需求,大家可以选择其中自己认为比较好的,用于自己的项目中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Android获取设备唯一ID
# Android设备唯一ID
# 安卓获取设备唯一标识
# android获取手机唯一标识的方法
# android 获取APP的唯一标识applicationId的实例
# 几个
# 几种
# 自己的
# 是在
# 会有
# 就不
# 不可以
# 中有
# 说过
# 较高
# 可以通过
# 有兴趣
# 比较好
# 较多
# 较低
# 你已经
# 中也
# 可以选择
# 它会
# 贴上
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
java获取注册ip实例
Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】
Laravel软删除怎么实现_Laravel Eloquent SoftDeletes功能使用教程
Laravel怎么创建控制器Controller_Laravel路由绑定与控制器逻辑编写【指南】
浅谈Javascript中的Label语句
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
利用 Google AI 进行 YouTube 视频 SEO 描述优化
音乐网站服务器如何优化API响应速度?
如何用AI帮你把自己的生活经历写成一个有趣的故事?
再谈Python中的字符串与字符编码(推荐)
如何在建站之星绑定自定义域名?
详解vue.js组件化开发实践
如何用腾讯建站主机快速创建免费网站?
青岛网站建设如何选择本地服务器?
EditPlus中的正则表达式实战(5)
网站制作企业,网站的banner和导航栏是指什么?
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?
Android 常见的图片加载框架详细介绍
Laravel如何使用集合(Collections)进行数据处理_Laravel Collection常用方法与技巧
Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑
Laravel如何使用withoutEvents方法临时禁用模型事件
如何在阿里云完成域名注册与建站?
如何快速搭建高效服务器建站系统?
Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)
如何在万网自助建站中设置域名及备案?
进行网站优化必须要坚持的四大原则
详解MySQL数据库的安装与密码配置
公司网站制作价格怎么算,公司办个官网需要多少钱?
iOS正则表达式验证手机号、邮箱、身份证号等
香港服务器网站卡顿?如何解决网络延迟与负载问题?
Laravel PHP版本要求一览_Laravel各版本环境要求对照
如何在VPS电脑上快速搭建网站?
Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲
如何快速重置建站主机并恢复默认配置?
Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明
Python文本处理实践_日志清洗解析【指导】
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
详解Android中Activity的四大启动模式实验简述
php增删改查怎么学_零基础入门php数据库操作必知基础【教程】
Win11任务栏卡死怎么办 Windows11任务栏无反应解决方法【教程】
Internet Explorer官网直接进入 IE浏览器在线体验版网址
HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】
免费视频制作网站,更新又快又好的免费电影网站?
Linux后台任务运行方法_nohup与&使用技巧【技巧】
Windows Hello人脸识别突然无法使用
北京网站制作的公司有哪些,北京白云观官方网站?
如何在IIS中新建站点并配置端口与IP地址?
如何在 Pandas 中基于一列条件计算另一列的分组均值
Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】
Python函数文档自动校验_规范解析【教程】

