54个答案
导入android.provider。 设置。 安全; private String android_id=安全.getString(getContext().getContentResolver(), 安全。 安卓ID_ID);
-
523 -
33 -
23 我认为我们需要注意在第一个答案中的散列中使用ANDROID_ID,因为它可能在应用程序首次运行时未设置,也可能稍后设置,甚至可能在理论上更改,因此唯一ID可能会更改 – 用户604363 评论 2011年2月5日17:06 -
51 -
42
所有测试的设备都返回了的值 电话管理器.getDeviceId() 所有GSM设备(均使用SIM卡测试)都返回了 电话管理器.getSimSerialNumber() 的所有CDMA设备均返回null 获取SimSerialNumber() (如预期) 添加了Google帐户的所有设备都返回了的值 安卓ID_ID 所有CDMA设备都返回了相同的值(或相同值的派生) 安卓ID_ID 和 电话管理器.getDeviceId() -- 只要 安装过程中添加了一个谷歌帐户。 我还没有机会测试没有SIM卡的GSM设备、没有添加Google帐户的GSM设备,或者任何处于飞行模式的设备。
final TelephonyManager tm=(电话管理器)getBaseContext().getSystemService(Context.TELEPHONY_SERVICE); 最终字符串tmDevice,tmSerial,androidId; tmDevice=“”+tm.getDeviceId(); tmSerial=“”+tm.getSimSerialNumber(); androidId=“”+android.provider。 设置。 Secure.getString(getContentResolver(),android.provider。 设置。 安全。 安卓ID_ID); UUID设备UUID=新的UUID(androidId.hashCode(),(长)tmDevice.hashCode()<<32)|tmSerial.hashCode[)]; String设备Id=设备Uuid.toString();
<uses-permission android:name=“android.permission.READ_PHONE_STATE”/>
导入android.content。 语境; 导入android.telephony。 电话经理; 导入android.view。 视图;
-
162 -
25 因此,为什么我说大多数都不会一直工作:)我还没有找到对所有设备、所有设备类型和所有硬件配置都可靠的答案。 这就是为什么这个问题要从这里开始。 很明显,对于这个问题,没有最终的解决方案。 个别设备制造商可能有设备序列号,但这些序列号不供我们使用,也不是必须的。 因此,我们只剩下可用的了。 – 乔 评论 2010年6月29日19:40 -
33 代码示例工作得很好。 记住添加 <uses-permission android:name=“android.permission.READ_PHONE_STATE”/> 到清单文件。 如果存储在数据库中,则返回的字符串长度为36个字符。 – 理查德 评论 2011年2月27日22:28 -
12 -
22 @softarn:我相信你指的是emmby已经链接到的Android开发者博客,它解释了你是什么 尝试 可以这么说,也许你应该投票支持他的评论。 不管怎样,正如emmby在回答中提到的那样,即使博客信息也存在问题。 这个问题要求一个独特的 设备 标识符(不是安装标识符),所以我不同意您的说法。 博客假设你想要什么 不一定是 跟踪设备,而问题只是要求这样。 我同意博客的其他观点。 – 乔 评论 2011年7月22日0:45
主要问题:硬件与软件
硬件
用户可以更改他们的硬件、Android平板电脑或手机,因此基于硬件的唯一ID对于 跟踪用户 对于 跟踪硬件 ,这是个好主意
软件
如果用户是root用户,则可以擦除/更改其ROM 您可以跨平台(iOS、Android、Windows和Web)跟踪用户 最好的愿望 追踪个人用户 和他们的 同意 就是让他们登录(使用OAuth无缝登录)
如果API>=9/10:(99.5%的设备) 返回包含串行ID的唯一ID(根设备可能不同) 其他的 返回生成信息的唯一ID(可能与数据重叠-API<9)
用户电子邮件-软件 用户可以更改电子邮件-极不可能 API 5标准+ <使用权限android:name=“android.permission.GET_ACCOUNTS”/> 或 API 14标准+ <uses-permission android:name=“android.permission.READ_PROFILE”/> <uses-permission android:name=“android.permission.READ_CONTACTS”/> ( 如何获取Android设备的主要电子邮件地址 ) 用户电话号码-软件 用户可以更改电话号码-极不可能 <uses-permission android:name=“android.permission.READ_PHONE_STATE”/> IMEI-硬件 (仅手机,需要 android权限。 阅读_语音_状态 ) 大多数用户都讨厌权限中显示“Phone Calls”。 一些用户给出了糟糕的评级,因为他们认为您只是在窃取他们的个人信息,而您真正想做的只是跟踪设备的安装。 很明显,您正在收集数据。 <uses-permission android:name=“android.permission.READ_PHONE_STATE”/> Android ID-硬件 (可以为空,可以在出厂重置时更改,可以在根设备上更改) 因为它可以是“null”,所以我们可以检查“null“并更改其值,但这意味着它将不再是唯一的。 如果用户具有出厂重置设备,则根设备上的值可能已更改或更改,因此如果您正在跟踪用户安装,则可能会有重复条目。 WLAN MAC地址-硬件 (需要 android权限。 访问_WIFI_STATE ) 这可能是第二个最佳选择,但您仍在收集和存储直接来自用户的唯一标识符。 很明显,您正在收集数据。 <uses-permission android:name=“android.permission.ACCESS_WIFI_STATE”/> 蓝牙MAC地址-硬件 (具有蓝牙功能的设备,需要 android权限。 蓝牙 ) 市场上的大多数应用程序都不使用蓝牙,因此如果您的应用程序不使用蓝牙并且您包含了蓝牙,用户可能会产生怀疑。 <uses-permission android:name=“android.permission.BLUETOOTH”/> 伪Unique ID-软件 (适用于所有Android设备) 很可能,可能包含冲突-请参阅下面发布的我的方法! 这允许您从用户那里获得一个“几乎唯一”的ID,而无需获取任何私密信息。 您可以根据设备信息创建自己的匿名ID。
删除了“Android”。 “SECURE_ID”,因为工厂重置可能导致值更改 编辑代码以更改API 更改了伪
/** *返回伪唯一ID *@返回ID */ 公共静态字符串getUniquePsuedoID(){ //如果所有其他都失败了,如果用户的API 9(更低 //(比姜饼),已重置其设备或“安全”。 安卓ID_ID’ //返回“null”,则返回的ID将完全基于 //关闭他们的Android设备信息。 这就是碰撞的地方 //可能发生。 //谢谢 http://www.pocketmagic.net/?p=1662 ! //尽量不要使用DISPLAY、HOST或ID-这些项目可能会发生变化。 //如果存在冲突,将存在重叠数据 String m_szDevIDShort=“35”+(Build.BARDE.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); //感谢@Roman SL! // https://stackoverflow.com/a/4789483/950427 //只有API>=9的设备才具有android.os。 生成。 串行的 // http://developer.android.com/reference/android/os/Build.html#SERIAL //如果用户升级软件或根目录他们的设备,将有重复条目 字符串序列=空; 尝试{ serial=android.os。 Build.class.getField(“SERIAL”).get(null).toString(); //继续并返回api=>9的序列 return新的UUID(m_szDevIDShort.hashCode(),serial.hashCode()).toString(); }catch(异常异常){ //字符串需要初始化 serial=“serial”;// 一些价值 } //谢谢@Joe! // https://stackoverflow.com/a/2853253/950427 //最后,通过使用UUID类组合我们找到的值来创建唯一标识符 return新的UUID(m_szDevIDShort.hashCode(),serial.hashCode()).toString(); }
从2014年8月1日开始,谷歌游戏开发者计划政策 需要全新的应用程序上传和更新才能在中使用广告ID 代替任何其他用于广告目的的永久标识符。 了解更多信息
<uses-permission android:name=“android.permission.INTERNET”/>
导入com.google.android.gms.ads.identifier。 广告IdClient; 导入com.google.android.gms.ads.identifier。 广告IdClient。 信息; 导入com.google.android.gms.common。 GooglePlayServicesAvailabilityException; 导入com.google.android.gms.common。 GooglePlayServicesNotAvailableException; 导入java.io.IOException; ... //不要从主线程调用此函数。 否则, //将引发IllegalStateException。 公共void getIdThread(){ Info adInfo=空; 尝试{ adInfo=广告IdClient.getAdvertisingIdInfo(mContext); }catch(IOException异常){ //连接到Google Play服务时发生不可恢复的错误(例如。, //旧版本的服务不支持获取AdvertisingId)。 }catch(GooglePlayServicesAvailabilityException异常){ //连接到Google Play服务时遇到可恢复的错误。 }catch(GooglePlayServicesNotAvailableException异常){ //Google Play服务并不完全可用。 } final字符串id=adInfo.getId(); 最后一个布尔值isLAT=adInfo.isLimitAdTrackingEnabled(); }
广告ID将完全替换现有的 出于广告目的使用其他标识符(例如使用ANDROID_ID 在“设置”中。 安全)。 案例 Google Play Services不可用的位置由 引发GooglePlayServicesNotAvailableException 获取广告IdInfo()。
Google Player服务实例ID
-
7 我在我的应用程序中使用了你的方法来发送评论。 我有个坏消息。 不幸的是,PsuedoID并不是完全唯一的。 我的服务器记录了5个ID的100多个ID,将近30个ID的30多个ID。重复次数最多的ID是“ffffffff-fc8f-6093-ffffffd8”(159条记录)和“ffffff-fe99-b334-ffff-ffffef”(154次)。 而且根据时间和评论,很明显存在不同的人。 到目前为止,总记录是10000条。 请告诉我为什么会这样。 油箱。 – 霍贾特·雷哈内 评论 2015年3月17日16:36 -
三 -
ANDROID_ID是首选设备标识符。 ANDROID_ID在ANDROID版本<=2.1或>=2.3上非常可靠。 只有2.2有帖子中提到的问题。 一些制造商的一些设备受到2.2中ANDROID_ID错误的影响。 据我所知,所有受影响的设备 相同的ANDROID_ID ,这是 9774d56d682e549c 。这也是模拟器报告的相同设备id,顺便说一句。 谷歌认为,原始设备制造商已经为他们的许多或大多数设备修复了这个问题,但我能够验证,至少到2011年4月初,仍然很容易找到ANDROID_ID坏了的设备。
导入android.content。 语境; 导入android.content。 共享首选项; 导入android.provider。 设置。 安全; 导入android.telephony。 电话经理; 导入java.io.UnsupportedEncodingException; 导入java.util。 UUID; 公共类DeviceUuidFactory{ 受保护的静态最终字符串PREFS_FILE=“device_id.xml”; 受保护的静态最终字符串PREFS_DEVICE_ID=“DEVICE_ID”; 保护挥发性静态UUID UUID; 公共DeviceUuidFactory(上下文上下文){ if(uuid==空){ 同步(DeviceUuidFactory.class){ if(uuid==空){ final SharedPreferences首选项=上下文 .getSharedPreferences(PREFS_FILE,0); 最终字符串id=prefs.getString(prefs_DEVICE_id,null); if(id!=空){ //使用以前计算并存储在 //prefs文件 uuid=uuid.fromString(id); }其他{ final字符串androidId=Secure.getString( context.getContentResolver(),安全。 安卓ID_ID); //使用Android ID,除非它坏了,在这种情况下 //设备ID回退, //除非不可用,否则随机回退 //我们存储到prefs文件中的数字 尝试{ if(!“9774d56d682e549c”.equals(androidId)){ uuid=uuid.nameUUIDFromBytes(androidId .getBytes(“utf8”); }其他{ 最终字符串设备ID=( (TelephonyManager)上下文 .getSystemService(上下文.TELEPHONY_SERVICE) .getDeviceId(); uuid=设备ID!= 无效的? UUID(统一用户识别码) .nameUUIDFromBytes(设备ID .getBytes(“utf8”):UUID .randomUUID(); } }catch(不支持的编码异常e){ 抛出新的RuntimeException(e); } //将值写入prefs文件 首选编辑() .putString(PREFS_DEVICE_ID,uuid.toString()) .commit(); } } } } } /** *返回当前android设备的唯一UUID。 与所有UUID一样, *这个唯一的ID“极有可能”在所有安卓系统中都是唯一的 *设备。 这比ANDROID_ID要多得多。 * *如果合适,UUID是通过使用ANDROID_ID作为基键生成的, *如果已知ANDROID_ID,则返回TelephonyManager.getDeviceID() *不正确,并最终返回到持久化的随机UUID *如果getDeviceID()未返回可用值,则设置为SharedPreferences。 * *在某些罕见的情况下,此ID可能会更改。 特别是,如果 *设备出厂重置后,可能会生成新的设备ID。 此外,如果 *用户从Android的某些错误实现中升级手机 *2.2到更新的无bug版本的Android,设备ID可能会更改。 *或者,如果用户在既没有合适的 *Android ID或设备ID,此ID可能会在重新安装时更改。 * *注意,如果代码返回到使用TelephonyManager.getDeviceId()时, *在工厂重置之后,所得到的ID将不会改变。 有些事情要做 *知道。 * *在使用Android_ID时,可以解决许多设备的Android 2.2中的错误 *直接。 * *@参见 http://code.google.com/p/android/issues/detail?id=10603 * *@return一个UUID,可用于在大多数情况下唯一识别您的设备 *目的。 */ 公共UUID getDeviceUuid(){ 返回uuid; } }
私有静态字符串uniqueID=null; private static final String PREF_UNIQUE_ID=“PREF_NUIQUE_ID”; 公共同步静态字符串id(上下文上下文){ if(uniqueID==空){ SharedPreferences sharedPrefs=上下文.getSharedPreverses( PREF_UNIQUE_ID,上下文。 模式_专用); uniqueID=sharedPrefs.getString(PREF_UNIQUE_ID,null); if(uniqueID==空){ uniqueID=UUID.randomUUID().toString(); 编辑器编辑器=sharedPrefs.edit(); editor.putString(PREF_UNIQUE_ID,uniqueID); editor.commit(); } } return uniqueID; }
-
4 -
三 Meier演示依赖于使用Android Backup Manager,而这又取决于用户选择打开该功能。这对于应用程序用户的首选项(Meier的使用)来说很好,因为如果用户没有选择该选项,她就不会备份这些功能。 然而,最初的问题是为 装置 该ID是按应用程序生成的,甚至不是按安装生成的,更不用说按设备生成了,而且由于它依赖于用户选择备份选项,因此其超出用户首选项的使用受到了限制(例如,对于有时间限制的试用)。 – 卡尔 评论 2012年12月22日11:15 -
17
避免使用硬件标识符 ,例如IMEI、MAC地址等。。。
仅将广告ID用于用户分析或广告用例
使用Firebase安装ID(FID)或专用存储的GUID 尽可能用于除支付欺诈预防和电话之外的所有其他用例。
实现'com.google.firebase:firebase消息传递:23.0.0'
FirebaseInstallations.getInstance().getId().addOnCompleteListener(任务->{ if(task.isSuccessful()){ 字符串firebaseIdentifier=task.getResult(); //使用firebaseIdentifier执行您需要的操作 } });
-
-
1 @戴维·施耐德(DavidSchneider),网络内容本质上是动态的,GDPR只是其中一个例子,请注意我写过“ GDPR和类似法规 “,因为有许多地方和全球法规影响您的产品/系统/领域。在任何情况下,您需要的GDPR部分包括: 识别 , 在线标识符 和 数据保护原则 – 尼基塔·库尔丁 评论 2020年7月21日10:39 -
-
三 @famfamfam因为跟踪设备对用户的隐私和安全构成威胁。 没有合法的案例需要这样做,所以没有理由让它成为可能。 Hw ID被证明是错误的,谷歌正在慢慢修复它们。 – 代理(_L) 评论 2022年2月14日13:12 -
1 @这是一个单独的问题。 根据stackoverflow的政策,应该单独询问。 无论如何,请记住,管理演示/试用版本可能会对您的产品产生业务影响,所以我认为没有一种解决方案可以匹配所有情况。 – 尼基塔·库尔丁 评论 3月24日7:57
WifiManager wm=(WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE); return wm.getConnectionInfo().getMacAddress();
-
9 -
7 -
13 -
6 -
8
IMEI公司 (仅适用于使用手机的Android设备;需要 android权限。 读取电话状态 ) 伪唯一ID (适用于所有Android设备) Android ID (可以为空,可以在出厂重置时更改,可以在根电话上更改) WLAN MAC地址 字符串(需要 android权限。 访问_WIFI_STATE ) BT MAC地址 字符串(具有蓝牙功能的设备,需要 android权限。 蓝牙 )
<application android:label=“MyApplication” android:backupAgent=“MyBackupAgent”> ... <meta-data android:name=“com.google.android.backup.api_key” android:value=“your_backup_service_key”/> </应用程序>
公共类MyBackupAgent扩展了BackupAgentHelper{ //SharedPreferences文件的名称 static final String PREFS=“user_preferences”; //唯一标识备份数据集的密钥 静态最终字符串PREFS_BACKUP_KEY=“PREFS”; //分配一个助手并将其添加到备份代理 @覆盖 公共void onCreate(){ SharedPreferencesBackupHelper helper=新的SharedPreffeencesBackuphelper(this,PREFS); addHelper(PREFS_BACKUP_KEY,助手); } }
BackupManager BackupManager=新的BackupManager(上下文);
公共静态字符串getUserID(上下文上下文){ 私有静态字符串uniqueID=null; private static final String PREF_UNIQUE_ID=“PREF_NUIQUE_ID”; if(uniqueID==空){ SharedPreferences sharedPrefs=上下文.getSharedPreverses( 我的备份代理。 PREFS,上下文。 模式_专用); uniqueID=sharedPrefs.getString(PREF_UNIQUE_ID,null); if(uniqueID==空){ uniqueID=UUID.randomUUID().toString(); 编辑器编辑器=sharedPrefs.edit(); editor.putString(PREF_UNIQUE_ID,uniqueID); editor.commit(); //备份更改 BackupManager mBackupManager=新的BackupManager(上下文); mBackupManager.dataChanged(); } } return uniqueID; }
-
9 -
字符串m_szDevIDShort=“35”+//我们使其看起来像有效的IMEI 生成。 BOARD.length()%10+内部版本。 品牌长度()%10+ 生成。 CPU_ABI.length()%10+内部版本。 设备长度()%10+ 生成。 DISPLAY.length()%10+内部版本。 主机长度()%10+ 构建。 ID长度()%10+内部版本。 制造商长度()%10+ 生成。 MODEL.length()%10+内部版本。 产品长度()%10+ 生成。 TAGS.length()%10+内部版本。 TYPE.length()%10+ 构建。 用户长度()%10// 13位数
-
10 有趣的解决方案。 听起来,在这种情况下,您真的应该只对连接的所有数据进行散列,而不是尝试使用自己的“散列”函数。 在许多情况下,即使每个值有不同的大量数据,也会发生冲突。 我的建议是:使用散列函数,然后将二进制结果转换为十进制,并根据需要截断它。 要做到这一点,您应该真正使用UUID或完整的散列字符串。 – 波默罗伊 评论 2011年4月12日16:28 -
25 -
11 -
10 -
13
字符串序列=空; 尝试{ 类别<?> c=Class.forName(“android.os.SystemProperties”); 方法get=c.getMethod(“get”,String.class); serial=(String)get.invoke(c,“ro.serialno”); } catch(忽略异常){ }
deviceId=Secure.getString(getApplicationContext().getContentResolver(),安全。 安卓ID_ID);
deviceId=Secure.getString(this.getContext().getContentResolver(),安全。 安卓ID_ID);
公共类安装{ 私有静态字符串sID=null; private static final String INSTALLATION=“安装”; 公共同步静态字符串id(上下文上下文){ if(sID==空){ 文件安装=新文件(context.getFilesDir(),安装); 尝试{ if(!installation.exists()) writeInstallationFile(安装); sID=读取安装文件(安装); } catch(异常e){ 抛出新的RuntimeException(e); } } 返回sID; } 私有静态字符串readInstallationFile(文件安装)引发IOException{ RandomAccessFile f=新的RandomAccess文件(安装,“r”); byte[]字节=新字节[(int)f.length()]; f.readFully(字节); f.关闭(); 返回新字符串(字节); } private static void writeInstallationFile(文件安装)引发IOException{ FileOutputStream out=新的FileOutput Stream(安装); 字符串id=UUID.randomUUID().toString(); out.write(id.getBytes()); out.close(); } }
final TelephonyManager tm=(电话管理器)getBaseContext() .getSystemService(SplashActivity.TELEPHONY_SERVICE); 最终字符串tmDevice,tmSerial,androidId; tmDevice=“”+tm.getDeviceId(); Log.v(“DeviceIMEI”,“”+tmDevice); tmSerial=“”+tm.getSimSerialNumber(); Log.v(“GSM设备序列号[simcard]”,“”+tmSerial); androidId=“”+android.provider。 设置。 安全.getString(getContentResolver(), android.provider。 设置。 安全。 安卓ID_ID); Log.v(“androidId CDMA设备”,“”+androidId); UUID设备UUID=新的UUID(androidId.hashCode(), ((长)tmDevice.hashCode()<<32)|tmSerial.hashCode()); String设备Id=设备Uuid.toString(); Log.v(“deviceIdUUID通用唯一标识符”,“”+deviceId); String deviceModelName=android.os。 生成。 模型; Log.v(“型号名称”,“”+设备型号名称); String deviceUSER=android.os。 生成。 用户; Log.v(“Name USER”,“”+设备用户); String devicePRODUCT=android.os。 生成。 产品; Log.v(“PRODUCT”,“”+设备PRODUCT); String deviceHARDWARE=android.os。 生成。 硬件; Log.v(“硬件”,“”+设备硬件); 字符串deviceBRAND=android.os。 生成。 品牌; Log.v(“BRAND”,“”+设备BRAND); 字符串myVersion=android.os。 生成。 版本。 发布; Log.v(“VERSION.RELEASE”,“”+myVersion); int sdkVersion=android.os。 生成。 版本。 SDK_INT; Log.v(“版本.SDK_INT”,“”+sdkV版本);
<使用权限android:name=“android.permission.READ_PHONE_STATE”/>
实现自定义ID生成算法(基于假定为静态且不会更改的设备属性->谁知道) 滥用其他ID,如 IMEI公司 、序列号、Wi-Fi/Bluetooth-MAC地址(它们不存在于所有设备上,也不需要其他权限)
导入android。 许可证; 导入android.bluetooth。 蓝牙适配器; 导入android.content。 语境; 导入android.content.pm.PackageManager; 导入android.net.wifi。 WifiManager; 导入android.provider。 设置。 安全; 导入android.telephony。 电话经理; 导入android.util。 日志; //TODO:哈希 公共最终类DeviceIdentifier{ 专用设备标识符(){} /**@参见 http://code.google.com/p/android/issues/detail?id=10603 */ private static final String ANDROID_ID_BUG_MSG=“设备遭受” +“Android ID bug-它的ID是模拟器ID:” +ID。 BUGGY_ANDROID_ID; 私有静态volatile字符串uuid;// 需要挥发性物质-见EJ第71项 //需要惰性初始化才能获得上下文 /** *返回此设备的唯一标识符。 第一个(按顺序 *枚举ID中定义的常量)非空标识符为 *返回或引发DeviceIDException。 DeviceIDException也是 *如果ignoreBuggyAndroidID为false且设备具有Android ID,则引发 *错误 * *@param ctx(参数ctx) *Android常量(用于检索系统服务) *@param ignoreBuggyAndroidID *如果为false,则在带有android ID错误的设备上,错误 *不返回android ID,而是返回DeviceIDException *抛出的 *@return a*设备*ID-从不返回null,而是返回 *引发DeviceIDException *@throws DeviceIDException *如果没有枚举方法返回设备ID */ 公共静态字符串getDeviceIdentifier(Context ctx, boolean ignoreBuggyAndroidID)引发DeviceIDException{ 字符串结果=uuid; if(结果==空){ 同步(DeviceIdentifier.class){ 结果=uuid; if(结果==空){ for(id id:IDs.values()){ 尝试{ result=uuid=id.getId(ctx); }catch(设备IDNotUniqueException e){ if(!ignoreBuggyAndroidID) 抛出新的DeviceIDException(e); } if(result!=null)返回结果; } 抛出新的DeviceIDEException(); } } } 返回结果; } 专用静态枚举ID{ 电话_ID{ @覆盖 字符串getId(上下文ctx){ //TODO:添加基于SIM的机制? tm.getSimSerialNumber(); final TelephonyManager tm=(电话管理器)ctx .getSystemService(上下文.TELEPHONY_SERVICE); 如果(tm==空){ w(“电话管理器不可用”); 返回null; } 资产权限(ctx,权限.READ_PHONE_STATE); 返回tm.getDeviceId(); } }, 安卓ID_ID{ @覆盖 字符串getId(Context ctx)引发DeviceIDException{ //无需许可! final字符串andoidId=SecuregetString( ctx.getContentResolver(), android.provider。 设置。 安全。 安卓ID_ID); if(BUGGY_ANDROID_ID.equals(andoidId)){ e(ANDROID_ID_BUG_MSG); 抛出新的DeviceIDNotUniqueException(); } 返回andoidId; } }, WIFI_MAC公司{ @覆盖 字符串getId(上下文ctx){ WifiManager wm=(WifiManager)ctx .getSystemService(上下文.WIFI_SERVICE); 如果(wm==空){ w(“Wifi管理器不可用”); 返回null; } assertPermission(ctx,permission.ACCESS_WIFI_STATE);// 我猜 //getMacAddress()没有java文档!!! 返回wm.getConnectionInfo().getMacAddress(); } }, 蓝牙_MAC{ @覆盖 字符串getId(上下文ctx){ 蓝牙适配器ba=蓝牙适配器.getDefaultAdapter(); if(ba==空){ w(“蓝牙适配器不可用”); 返回null; } assertPermission(ctx,permission.BLUETOOTH); return ba.getAddress(); } } //TODO伪ID // http://www.pocketmagic.net/2011/02/android-unique-device-id/ ; 静态最终字符串BUGGY_ANDROID_ID=“9774d56d682e549c”; private final static String TAG=IDs.class.getSimpleName(); abstract String getId(Context ctx)抛出DeviceIDException; private static void w(字符串消息){ Log.w(标签,消息); } private static void e(字符串消息){ 日志.e(标签,消息); } } 私有静态void assertPermission(Context ctx,String perm){ final int checkPermission=ctx.getPackageManager().checkPermission( perm,ctx.getPackageName()); if(checkPermission!=包管理器.PERMISSION_GRANTED){ throw new SecurityException(“Permission”+perm+“is required”); } } // ========================================================================= //例外情况 // ========================================================================= 公共静态类DeviceIDException扩展异常{ private static final long serialVersionUID=-808369995384519417L; private static final String NO_ANDROID_ID=“无法检索” +“设备ID”; 公共DeviceIDException(Throwable Throwable){ super(NO_ANDROID_ID,可丢弃); } 公共DeviceIDException(String detailMessage){ super(详细消息); } 公共设备IDException(){ 超级(NO_ANDROID_ID); } } 公共静态最终类DeviceIDNotUniqueException扩展 DeviceIDException(设备IDE异常){ 私有静态最终长序列VersionUID=-8940090896069484955L; 公用设备IDNotUniqueException(){ 超级(ANDROID_ID_BUG_MSG); } } }
@禁止警告(“弃用”) @SuppressLint(“硬件ID”) 公共静态字符串generateDeviceIdentifier(上下文上下文){ 字符串伪Id=“35”+ 构建。 电路板长度()%10+ 生成。 品牌长度()%10+ 生成。 CPU_ABI.length()%10+ 生成。 设备长度()%10+ 生成。 显示长度()%10+ 生成。 主机长度()%10+ 生成。 ID长度()%10+ 生成。 制造商长度()%10+ 生成。 型号.长度()%10+ 生成。 产品长度()%10+ 生成。 标签长度()%10+ 生成。 TYPE.length()%10+ 生成。 用户长度()%10; String androidId=设置。 Secure.getString(context.getContentResolver(),设置。 安全。 安卓ID_ID); BluetoothAdapter蓝牙适配器=蓝牙适配器.getDefaultAdapter(); 字符串btId=“”; if(bluetoothAdapter!=空){ btId=蓝牙适配器.getAddress(); } 字符串longId=pseudoId+androidId+btId; 尝试{ MessageDigest MessageDigest=消息摘要.getInstance(“MD5”); messageDigest.update(longId.getBytes(),0,longId.length()); //获取md5字节 byte md5Bytes[]=消息摘要.摘要(); //创建十六进制字符串 字符串标识符=“”; for(字节md5Byte:md5Bytes){ int b=(0xFF&md5字节); //如果是单个数字,请确保前面有0(正确的填充) 如果(b<=0xF){ 标识符+=“0”; } //将数字添加到字符串 标识符+=整数.toHexString(b); } //十六进制字符串到大写 identifier=identifier.toUpperCase(); 返回标识符; }catch(异常e){ Log.e(“标签”,e.toString()); } 返回“”; }
-
三 添加 UUID(统一用户识别码) 到 长Id 并将其存储在文件中,将使其成为最唯一的标识符: 字符串uuid=uuid.randomUUID().toString(); – 穆萨·阿尔弗雷 评论 2017年4月11日7:08 -
三 如果所有这些都失败了,如果用户的API 9(低于Gingerbread),则重置手机或“安全”。 ANDROID_ID’。 如果返回“null”,那么返回的ID将仅基于他们的Android设备信息。 这就是碰撞可能发生的地方。 尽量不要使用DISPLAY、HOST或ID-这些项目可能会发生变化。 如果存在冲突,将存在重叠数据。 来源: gist.github.com/pedja1/fe69e8a80ed505500caa注册中心 – 穆萨·阿尔弗雷 评论 2017年4月11日7:17 -
2 @忍者由于BLE mac地址是唯一的,是的,生成的ID将始终是唯一的。 然而,如果您真的想确定,我建议将UUID添加到 长Id 。将这一行改为: 字符串longId=pseudoId+androidId+btId+UUID.randomUUID().toString(); 这将确保生成的ID是唯一的。 – ᴛ ʜᴇᴘᴀᴛᴇʟ 评论 2019年4月3日12:38
Android OS设备的唯一设备ID为String,使用 电话管理器
和 安卓ID_ID
,通过以下方式获得:
字符串deviceId; 最终电话管理器mTelephony=(电话管理器)getSystemService(Context.TELEPHONY_SERVICE); if(mTelephony.getDeviceId()!= null){ 设备Id=mTelephony.getDeviceId(); } 其他{ deviceId=安全设置字符串( getApplicationContext().getContentResolver(), 安全。 安卓ID_ID); }
公共静态字符串getDeviceId(上下文ctx) { 电话管理器tm=(电话管理器)ctx.getSystemService(Context.TELEPHONY_SERVICE); 字符串tmDevice=tm.getDeviceId(); String androidId=Secure.getString(ctx.getContentResolver(),安全。 安卓ID_ID); 字符串序列=空; if(Build.VERSION.SDK_INT>Build.VERTION_CODES.FROYO)serial=Build。 系列; 如果(tmDevice!=null)返回“01”+tmDevice; 如果(androidId!=null)返回“02”+androidId; 如果(serial!=null)返回“03”+serial; //其他替代方案(即Wi-Fi MAC、蓝牙MAC等) 返回null; }
用户@爬行 :~$adb shell ls-l/sys/class/android_usb/android0/iSerial -rw-r--r--根4096 2013-01-10 21:08 i序列 用户@爬行 :~$adb shell cat/sys/class/android_usb/android0/iSerial 0a3xxxxxxxxxx5
银河系Nexus Nexus S公司 摩托罗拉Xoom 3G 东芝AT300 HTC一V 迷你MK802 三星Galaxy S II
-
-
2
List<NetworkInterface>interfacesList=Collections.List(NetworkInterface.getNetworkInterfaces()); for(NetworkInterface接口:interfacesList){ //这将为您提供MAC ADDRESS接口 接口.getHardwareAddress(); }
字符串标识符=空; TelephonyManager tm=(TelephoneyManager)context.getSystemService(context.TELEPHONY_SERVICE)); 如果(tm!=空) 标识符=tm.getDeviceId(); if(identifier==null||identifier.length()==0) identifier=Secure.getString(activity.getContentResolver(),安全。 安卓ID_ID);
最终TelephonyManager mTelephony=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); 字符串myAndroidDeviceId=mTelephony.getDeviceId();
String myAndroidDeviceId=Secure.getString(getApplicationContext().getContentResolver(),安全。 安卓ID_ID);
公共字符串getUniqueID(){ 字符串myAndroidDeviceId=“”; 电话管理器mTelephony=(电话管理器)getSystemService(Context.TELEPHONY_SERVICE); if(mTelephony.getDeviceId()!= null){ myAndroidDeviceId=m电话.getDeviceId(); }其他{ myAndroidDeviceId=安全.getString(getApplicationContext().getContentResolver(),安全。 安卓ID_ID); } return myAndroidDeviceId; }
InstanceID iid=实例ID.getInstance(上下文);// 谷歌文档是错误的-这需要上下文 字符串id=iid.getId();// 阻塞呼叫
私有void fetchDeviceInfo(){ 字符串uniquePseudoID=“35”+ 生成。 电路板长度()%10+ 生成。 品牌长度()%10+ 生成。 设备长度()%10+ 生成。 显示长度()%10+ 生成。 主机长度()%10+ 生成。 ID长度()%10+ 生成。 制造商长度()%10+ 生成。 型号.长度()%10+ 生成。 产品长度()%10+ 构建。 标签长度()%10+ 生成。 TYPE.length()%10+ 生成。 用户长度()%10; 字符串序列=Build.getRadioVersion(); 字符串uuid=新的uuid(uniquePseudoID.hashCode(),serial.hashCode()).toString(); String brand=构建。 品牌; String modelno=构建。 模型; 字符串版本=内部版本。 版本。 发布; Log.e(标签,“fetchDeviceInfo:\n”+ “\n uuid为:”+uuid+ “\n brand是:”+brand+ “\n model为:”+modelno+ “\n版本为:”+版本); }