问:

Android 设备是否有唯一 ID,如果有,使用 Java 访问它的简单方法是什么?

答1:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

Settings.Secure#ANDROID_ID 将 Android ID 作为 unique for each user 64 位十六进制字符串返回。

import android.provider.Settings.Secure;private String android_id = Secure.getString(getContext().getContentResolver(),Secure.ANDROID_ID);

另请阅读唯一标识符的最佳做法:https://developer.android.com/training/articles/user-data-ids

有时它被认为是空的,它被记录为“可以在出厂重置时更改”。使用风险自负,并且可以在有根手机上轻松更改。

groups.google.com/group/android-developers/browse_thread/thread/…

我认为我们需要小心在第一个答案中在哈希中使用 ANDROID_ID 因为它可能不会在应用程序首次运行时设置,可能会在以后设置,甚至可能在理论上发生变化,因此唯一 ID 可能会改变

请注意,此解决方案存在巨大限制:android-developers.blogspot.com/2011/03/…

ANDROID_ID 不再唯一标识设备(从 4.2 开始):stackoverflow.com/a/13465373/150016

答2:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

更新:在最近的 Android 版本中,许多与 ANDROID_ID 相关的问题都已解决,我相信这种方法不再需要。请看一下Anthony’s answer。

完全披露:我的应用程序最初使用了以下方法,但不再使用这种方法,我们现在使用 emmby’s answer 链接到的 Android Developer Blog 条目中概述的方法(即生成和保存 UUID#randomUUID())。

这个问题有很多答案,其中大多数只能在“某些”时间里起作用,不幸的是,这还不够好。

根据我对设备的测试(所有手机,至少其中一部未激活):

所有测试的设备都返回了 TelephonyManager.getDeviceId() 的值 所有 GSM 设备(所有测试都使用 SIM 卡)返回了 TelephonyManager.getSimSerialNumber() 的值 所有 CDMA 设备都返回了 getSimSerialNumber() 的值(如预期的那样) 所有具有 Google 帐户的设备added 返回了 ANDROID_ID 的值 所有 CDMA 设备都为 ANDROID_ID 和 TelephonyManager.getDeviceId() 返回了相同的值(或相同值的派生)——只要在设置期间添加了 Google 帐户。我还没有机会测试没有 SIM 卡的 GSM 设备、没有添加 Google 帐户的 GSM 设备或任何处于飞行模式的设备。

因此,如果您想要设备本身独有的东西,TM.getDeviceId()应该就足够了。显然,有些用户比其他用户更偏执,因此对这些标识符中的 1 个或多个进行哈希处理可能很有用,这样字符串对于设备实际上仍然是唯一的,但不会明确标识用户的实际设备。例如,使用 String.hashCode(),结合 UUID:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();

可能会导致类似:00000000-54b3-e7c7-0000-000046bffd97

它对我来说足够好。

正如 Richard 在下面提到的,不要忘记您需要读取 TelephonyManager 属性的权限,因此请将其添加到您的清单中:

导入库

import android.content.Context;
import android.telephony.TelephonyManager;
import android.view.View;

基于电话的 ID 不会出现在平板设备上,不是吗?

因此为什么我说大多数不会一直工作:) 我还没有看到任何对所有设备、所有设备类型和所有硬件配置都可靠的问题的答案。这就是为什么这个问题在这里开始。很明显,对此没有万能的解决方案。个别设备制造商可能有设备序列号,但这些序列号并没有公开给我们使用,也不是必须的。因此,我们只剩下可用的东西了。

代码示例效果很好。请记住将 添加到清单文件。如果存储在数据库中,则返回的字符串长度为 36 个字符。

请注意,此解决方案存在巨大限制:android-developers.blogspot.com/2011/03/…

@softarn:我相信你指的是 emmby 已经链接到的 Android 开发者博客,它解释了你想说的话,所以也许你应该简单地支持他的评论。无论哪种方式,正如 emmby 在他的回答中提到的那样,即使博客信息仍然存在问题。该问题要求提供唯一的设备标识符(而不是安装标识符),因此我不同意您的说法。该博客假设您想要的不一定是跟踪设备,而问题只是要求这样做。否则我同意博客。

答3:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

#最后更新时间:2015 年 6 月 2 日

在阅读了有关创建唯一 ID 的每篇 Stack Overflow 帖子、Google 开发人员博客和 Android 文档之后,我觉得“伪 ID”似乎是最好的选择。

主要问题:硬件与软件

硬件

用户可以更改他们的硬件、Android 平板电脑或手机,因此基于硬件的唯一 ID 不是跟踪用户的好主意

对于跟踪硬件,这是个好主意

软件

用户可以擦除/更改他们的 ROM,如果他们是 root

您可以跨平台(iOS、Android、Windows 和 Web)跟踪用户

在征得他们同意的情况下跟踪个人用户的最佳方法是让他们登录(使用 OAuth 无缝连接)

#Android的整体故障

###- 保证 API >= 9/10(99.5% 的 Android 设备)的唯一性(包括根设备)###- 没有额外的权限

伪代码:

if API >= 9/10: (99.5% of devices)return unique ID containing serial id (rooted devices may be different)elsereturn the unique ID of build information (may overlap data - API < 9)

感谢 @stansult 发布 all of our options(在此 Stack Overflow 问题中)。

##选项列表 - 为什么/为什么不使用它们的原因:

用户电子邮件 - 软件

用户可以更改电子邮件 - 极不可能

API 5+ 或

API 14+ (如何获取安卓设备的主邮箱)

用户电话号码 - 软件

用户可以更改电话号码 - 极不可能

IMEI - 硬件(仅限手机,需要 android.permission.READ_PHONE_STATE)

大多数用户讨厌它在权限中显示“电话呼叫”这一事实。一些用户给出不好的评价是因为他们认为您只是在窃取他们的个人信息,而您真正想要做的只是跟踪设备安装。很明显,您正在收集数据。

Android ID - 硬件(可以为空,可以在出厂重置时更改,可以在有根设备上更改)

因为它可以是’null’,我们可以检查’null’并改变它的值,但这意味着它不再是唯一的。

如果您的用户使用恢复出厂设置的设备,则该值可能已在根设备上更改或更改,因此如果您正在跟踪用户安装,则可能存在重复条目。

WLAN MAC 地址 - 硬件(需要 android.permission.ACCESS_WIFI_STATE)

这可能是次优选择,但您仍在收集和存储直接来自用户的唯一标识符。很明显,您正在收集数据。

蓝牙 MAC 地址 - 硬件(带蓝牙的设备,需要 android.permission.BLUETOOTH)

市场上的大多数应用程序不使用蓝牙,因此如果您的应用程序不使用蓝牙并且您包含蓝牙,用户可能会产生怀疑。

伪唯一 ID - 软件(适用于所有 Android 设备)

很有可能,可能包含冲突 - 请参阅下面发布的我的方法!

这使您可以从用户那里获得一个“几乎唯一”的 ID,而无需获取任何私人信息。您可以根据设备信息创建自己的匿名 ID。

我知道没有任何“完美”的方法可以在不使用权限的情况下获取唯一 ID。但是,有时我们只需要跟踪设备安装。在创建唯一 ID 时,我们可以仅根据 Android API 提供给我们的信息创建一个“伪唯一 ID”,而无需使用额外的权限。这样,我们可以向用户表示尊重,并尝试提供良好的用户体验。

使用伪唯一 ID,您实际上只会遇到这样一个事实,即基于存在类似设备的事实可能存在重复。您可以调整组合方法以使其更加独特;但是,一些开发人员需要跟踪设备安装,这将基于类似设备实现技巧或性能。

##API >= 9:

如果他们的 Android 设备是 API 9 或更高版本,则由于“Build.SERIAL”字段,这保证是唯一的。

记住,从技术上讲,您只错过了大约 0.5% 的用户who have API < 9。所以你可以专注于其余的:这是 99.5% 的用户!

##API < 9:

如果用户的Android设备低于API 9;希望他们没有进行出厂重置,并且他们的“Secure.ANDROID_ID”将被保留或不为“null”。 (见http://developer.android.com/about/dashboards/index.html)

##如果一切都失败了:

如果一切都失败了,如果用户确实低于 API 9(低于 Gingerbread),重置了他们的设备,或者“Secure.ANDROID_ID”返回“null”,那么返回的 ID 将完全基于他们的 Android 设备信息.这是可能发生碰撞的地方。

变化:

删除了“Android.SECURE_ID”,因为出厂重置可能会导致值更改

编辑代码以更改 API

改变了伪

请看下面的方法:

/*** 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 device 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 dataString 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!// https://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 device, there will be a duplicate entryString serial = null;try {serial = android.os.Build.class.getField("SERIAL").get(null).toString();// Go ahead and return the serial for api => 9return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();} catch (Exception exception) {// String needs to be initializedserial = "serial"; // some value}// Thanks @Joe!// https://stackoverflow.com/a/2853253/950427// Finally, combine the values we have found by using the UUID class to create a unique identifierreturn new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}

#New(适用于带有广告和 Google Play 服务的应用):

从 Google Play 开发者控制台:

自 2014 年 8 月 1 日起,Google Play 开发者计划政策要求上传和更新全新的应用程序以使用广告 ID 代替任何其他持久性标识符用于任何广告目的。学到更多

执行:

允许:

代码:

import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import java.io.IOException;
...// Do not call this function from the main thread. Otherwise,
// an IllegalStateException will be thrown.
public void getIdThread() {Info adInfo = null;try {adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);} catch (IOException exception) {// Unrecoverable error connecting to Google Play services (e.g.,// the old version of the service doesn't support getting AdvertisingId).} catch (GooglePlayServicesAvailabilityException exception) {// Encountered a recoverable error connecting to Google Play services. } catch (GooglePlayServicesNotAvailableException exception) {// Google Play services is not available entirely.}final String id = adInfo.getId();final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
}

来源/文档:

http://developer.android.com/google/play-services/id.html http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html

##重要的:

当 Google Play 服务可用时,广告 ID 旨在完全取代现有的其他标识符用于广告目的(例如在 Settings.Secure 中使用 ANDROID_ID)。 Google Play 服务不可用的情况由 getAdvertisingIdInfo() 引发的 GooglePlayServicesNotAvailableException 指示。

##警告,用户可以重置:

http://en.kioskea.net/faq/34732-android-reset-your-advertising-id

我试图引用我从中获取信息的每个链接。如果您缺少并且需要包括在内,请发表评论!

Google 播放器服务实例 ID

https://developers.google.com/instance-id/

我在我的应用程序中使用了您的方法来发送评论。我有坏消息。不幸的是,PsuedoID 并不是完全独一无二的。我的服务器记录了 5 个 ID 超过 100 个,几乎 30 个 ID 记录了超过 30 个。重复次数最多的 ID 是“ffffffff-fc8f-6093-ffff-ffffd8”(159 条记录)和“ffffffff-fe99-b334-ffff-ffffef”(154 次)。也基于时间和评论,很明显有不同的人。到现在为止的总记录是10,000。请让我知道为什么会这样。坦克。

我在 1.5 多年前写了这个。我不知道为什么它对你来说不是独一无二的。你可以试试广告ID。如果没有,您可以提出自己的解决方案。

sorta ..如果您解决这个问题并就此提出您的想法,我将非常感激

@user1587329 谢谢。我正在努力为每个人提供最新信息。当涉及到硬件与软件和跨平台时,这个问题很棘手。

为什么这么难用一个简单的没有冲突的唯一ID呢?只需使用 Pseudo-Unique ID - Software + date (hhmmss) 它没有冲突。组合时间越长,应用的难度越高。

答4:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

正如 Dave Webb 所提到的,Android Developer Blog has an article 涵盖了这一点。他们首选的解决方案是跟踪应用安装而不是设备,这适用于大多数用例。博客文章将向您展示实现该功能所需的代码,我建议您查看一下。

但是,如果您需要设备标识符而不是应用程序安装标识符,博客文章会继续讨论解决方案。如果您需要这样做,我与 Google 的某个人进行了交谈,以获得对一些项目的额外说明。以下是我在上述博客文章中未提及的有关设备标识符的发现:

ANDROID_ID 是首选设备标识符。 ANDROID_ID 在 Android <=2.1 或 >=2.3 的版本上非常可靠。只有2.2有帖子中提到的问题。

几家制造商的几款设备受到 2.2 中的 ANDROID_ID 错误的影响。

据我所知,所有受影响的设备都具有相同的 ANDROID_ID,即 9774d56d682e549c。这也是模拟器报告的相同设备ID,顺便说一句。

Google 认为 OEM 已经为他们的许多或大部分设备修复了这个问题,但我能够验证,至少在 2011 年 4 月开始时,仍然很容易找到 ANDROID_ID 损坏的设备。

根据 Google 的建议,我实现了一个类,该类将为每个设备生成唯一的 UUID,在适当的情况下使用 ANDROID_ID 作为种子,必要时使用 TelephonyManager.getDeviceId(),如果失败,则使用随机生成的唯一 UUID这在应用程序重新启动(但不是应用程序重新安装)中持续存在。

请注意,对于必须回退设备 ID 的设备,唯一 ID 将在出厂重置后保留。这是需要注意的。如果您需要确保恢复出厂设置会重置您的唯一 ID,您可能需要考虑直接回退到随机 UUID 而不是设备 ID。

同样,此代码用于设备 ID,而不是应用程序安装 ID。在大多数情况下,应用程序安装 ID 可能就是您要查找的内容。但是,如果您确实需要设备 ID,那么以下代码可能适合您。

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 volatile static 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 fileuuid = 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 filetry {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 fileprefs.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;}
}

您不应该对各种 ID 进行哈希处理以使它们的大小都相同吗?此外,您应该对设备 ID 进行散列处理,以免意外暴露私人信息。

好点,史蒂夫。我更新了代码以始终返回 UUID。这确保 a) 生成的 ID 始终具有相同的大小,并且 b) android 和设备 ID 在返回之前经过哈希处理,以避免意外暴露个人信息。我还更新了描述,指出设备 ID 将在出厂重置后保持不变,这可能不适合某些用户。

我相信你是不正确的;首选的解决方案是跟踪安装,而不是设备标识符。您的代码比博客文章中的代码更长、更复杂,对我来说,它增加了任何价值并不明显。

好点,我更新了评论,强烈建议用户使用应用程序安装 ID 而不是设备 ID。但是,我认为这个解决方案对于确实需要设备而不是安装 ID 的人来说仍然很有价值。

ANDROID_ID 可以在出厂重置时更改,因此它也无法识别设备

答5:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

以下是 Reto Meier 在今年的 Google I/O 演示中使用的代码,用于获取用户的唯一 ID:

private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";public synchronized static String id(Context context) {if (uniqueID == null) {SharedPreferences sharedPrefs = context.getSharedPreferences(PREF_UNIQUE_ID, Context.MODE_PRIVATE);uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);if (uniqueID == null) {uniqueID = UUID.randomUUID().toString();Editor editor = sharedPrefs.edit();editor.putString(PREF_UNIQUE_ID, uniqueID);editor.commit();}}return uniqueID;
}

如果您将此与备份策略相结合以将首选项发送到云(也在 Reto 的 talk 中描述,您应该有一个与用户相关联的 ID,并在设备被擦除甚至更换后仍然存在。我计划在未来的分析中使用它(换句话说,我还没有这样做:)。

如果您不需要在卸载和重新安装后保留唯一 ID(例如促销活动/游戏,您有 3 次获胜的机会,期间),这是一个很好的选择。

Meier 演示依赖于使用 Android 备份管理器,而这又取决于用户选择打开该功能。这对于应用程序用户偏好(Meier 的使用)来说很好,因为如果用户没有选择该选项,她就不会备份这些选项。但是,最初的问题是关于为设备生成唯一 ID,并且此 ID 是每个应用程序生成的,甚至不是每次安装生成的,更不用说每个设备了,并且由于它依赖于用户选择备份选项,因此它的用途超出了用户偏好(例如,对于有时间限制的试验)是有限的。

这不适用于卸载或清除数据。

非常糟糕的解决方案

我认为这是一个很好的解决方案,设备和服务器上有一个唯一的 ID,以防你卸载。您可以确保将其与客户电子邮件一起保存,以便保留;-p

答6:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

这是一个简单的问题,没有简单的答案。

此外,这里所有现有的答案要么已过时,要么不可靠。

因此,如果您正在寻找 2020 年后的解决方案。

这里有几件事要记住:

所有基于硬件的标识符(IMEI、MAC、序列号等)对于非 Google 设备(Pixel 和 Nexus 除外)都是不可靠的,这些设备在统计上是 most of the android active devices worldwide。因此官方Android identifiers best practices明确指出:

避免使用硬件标识符,例如 IMEI、MAC 地址等…

这使得这里的大多数答案都无效。同样由于不同的android安全更新,其中一些需要更新和更严格的运行时权限,用户可以简单地拒绝。

例如 CVE-2018-9489 会影响上述所有基于 WIFI 的技术。

这使得这些标识符不仅不可靠,而且在许多情况下也无法访问。

所以用更简单的话来说:不要使用那些技术。

这里的许多其他答案都建议使用 AdvertisingIdClient,这也是不兼容的,因为它的设计仅用于广告分析。 official reference 中也有说明

仅将广告 ID 用于用户分析或广告用例

它不仅对设备识别不可靠,而且您还必须遵守 user privacy regarding ad tracking 政策,该政策明确规定用户可以随时重置或阻止它。

所以也不要使用它。

由于您无法拥有所需的静态全局唯一且可靠的设备标识符。 Android的官方参考建议:

尽可能为所有其他用例使用 Firebase 安装 ID (FID) 或私人存储的 GUID,但支付欺诈预防和电话除外。

它对于设备上的应用程序安装来说是独一无二的,所以当用户卸载应用程序时 - 它会被清除,所以它不是 100% 可靠的,但它是次优的。

注意 从今天起,FirebaseInstanceId 已被弃用,您应该改用 FirebaseInstallations。

要使用 FirebaseInstallations,请将 latest firebase-messaging dependency 添加到您的 gradle

implementation 'com.google.firebase:firebase-messaging:23.0.0'

并使用以下代码获取 Firebase ID:

FirebaseInstallations.getInstance().getId().addOnCompleteListener(task -> {if (task.isSuccessful()) {String firebaseIdentifier = task.getResult();// Do what you need with firebaseIdentifier}
});

如果您需要将设备标识存储在远程服务器上,则不要按原样(纯文本)存储它,而是 hash with salt。

今天,这不仅是一种最佳做法,而且您实际上必须根据 GDPR - identifiers 和类似法规依法执行。

就目前而言,这是最好的答案,第一句话就是最好的总结:“这是一个简单的问题,没有简单的答案——只是喜欢它。

@M.UsmanKhan,答案是在那之后写的:“今天,这不仅是最佳实践,而且您实际上必须根据 GDPR - 标识符和类似法规依法执行。”

@DavidSchneider 网络内容本质上是动态的,GDPR 只是其中一个例子,请注意我写过“GDPR 和类似法规”,因为有许多本地和全球法规会影响您的产品/系统/领域.在任何情况下,您正在寻找的 GDPR 部分是:标识、在线标识符和数据保护原则

如果重新安装应用程序,firebase 唯一 ID 将更改

@MichaelPaccione 不多,但特别是在卸载应用程序时。请注意,我已经在答案中写了它。

答7:

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

您也可以考虑 Wi-Fi 适配器的 MAC 地址。像这样检索:

WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
return wm.getConnectionInfo().getMacAddress();

需要清单中的权限 android.permission.ACCESS_WIFI_STATE。

据报道,即使在未连接 Wi-Fi 时也可用。如果上面答案中的乔在他的许多设备上试一试,那就太好了。

在某些设备上,关闭 Wi-Fi 时它不可用。

注意: 从 Android 6.x 开始,它返回一致的假 mac 地址:02:00:00:00:00:00

这需要 android.permission.ACCESS_WIFI_STATE

我想你会发现它在 WiFi 关闭时不可用,在几乎所有的 Android 设备上。关闭 WiFi 会在内核级别删除设备。

@Sanandrea - 让我们面对现实吧,在有根设备上,一切都可以被欺骗。

在 Android M 上访问 WiFi MAC 地址已被阻止:stackoverflow.com/questions/31329733/…

从 Android 6.x 开始,它返回一致的假 mac 地址:02:00:00:00:00:00

答8:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

有相当有用的信息 here。

它涵盖了五种不同的 ID 类型:

IMEI(仅适用于使用手机的 Android 设备;需要 android.permission.READ_PHONE_STATE) Pseudo-Unique ID(适用于所有 Android 设备) Android ID(可以为空,可以在恢复出厂设置时更改,可以在 root 手机上更改) WLAN MAC 地址字符串(需要 android.permission.ACCESS_WIFI_STATE) BT MAC 地址字符串(带蓝牙的设备,需要 android.permission.BLUETOOTH)

遗漏了重要的一点(此处和文章中):除非打开它们,否则您无法获得 WLAN 或 BT MAC!否则我认为 WLAN MAC 将是完美的标识符。你不能保证用户会打开他们的 Wi-Fi,而且我真的不认为自己打开它是“合适的”。

@Tom 你错了。即使它们已关闭,您仍然可以读取 WLAN 或 BT MAC。但是,不能保证设备具有可用的 WLAN 或 BT 模块。

最值得注意的是,本地 WiFi 和蓝牙 MAC 地址不再可用。从现在开始,aWifiInfo 对象的 getMacAddress() 方法和 BluetoothAdapter.getDefaultAdapter().getAddress() 方法都将返回 02:00:00:00:00:00

@sarikakate 仅在 6.0 Marshmallow 及更高版本中才是真的......它在 6.0 Marshmallow 以下仍然按预期工作。

答9:

huntsbot.com – 高效赚钱,自由工作

官方 Android 开发者博客现在有一篇关于这个主题的完整文章,Identifying App Installations。

该论点的关键在于,如果您试图从硬件中获取唯一 ID,那么您可能会犯错误。

而且,如果您允许通过恢复出厂设置来重置设备锁,那么您的试用软件模型就像死机一样好。

并且博文已经链接到该网站:developer.android.com/training/articles/user-data-ids

答10:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

在 Google I/O,Reto Meier 发布了关于如何解决此问题的可靠答案,该答案应满足大多数开发人员在跨安装跟踪用户的需求。安东尼诺兰在他的回答中表明了方向,但我想我会写出完整的方法,以便其他人可以轻松地看到如何去做(我花了一段时间才弄清楚细节)。

这种方法将为您提供一个匿名的、安全的用户 ID,该用户 ID 将在不同设备(基于主要 Google 帐户)和安装中对用户保持不变。基本方法是生成随机用户 ID 并将其存储在应用程序的共享首选项中。然后,您使用 Google 的备份代理将链接到云中的 Google 帐户的共享首选项存储起来。

让我们来看看完整的方法。首先,我们需要使用 Android 备份服务为我们的 SharedPreferences 创建一个备份。首先通过 http://developer.android.com/google/backup/signup.html 注册您的应用程序。

Google 将为您提供一个备份服务密钥,您需要将其添加到清单中。您还需要告诉应用程序使用 BackupAgent,如下所示:

...

然后您需要创建备份代理并告诉它使用辅助代理来共享首选项:

public class MyBackupAgent extends BackupAgentHelper {// The name of the SharedPreferences filestatic final String PREFS = "user_preferences";// A key to uniquely identify the set of backup datastatic final String PREFS_BACKUP_KEY = "prefs";// Allocate a helper and add it to the backup agent@Overridepublic void onCreate() {SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);addHelper(PREFS_BACKUP_KEY, helper);}
}

要完成备份,您需要在主 Activity 中创建 BackupManager 的实例:

BackupManager backupManager = new BackupManager(context);

最后创建一个用户 ID,如果它不存在,并将其存储在 SharedPreferences 中:

  public static String getUserID(Context context) {private static String uniqueID = null;private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";if (uniqueID == null) {SharedPreferences sharedPrefs = context.getSharedPreferences(MyBackupAgent.PREFS, Context.MODE_PRIVATE);uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);if (uniqueID == null) {uniqueID = UUID.randomUUID().toString();Editor editor = sharedPrefs.edit();editor.putString(PREF_UNIQUE_ID, uniqueID);editor.commit();//backup the changesBackupManager mBackupManager = new BackupManager(context);mBackupManager.dataChanged();}}return uniqueID;
}

即使用户移动设备,此 User_ID 现在将在安装中保持不变。

有关此方法的更多信息,请参阅 Reto’s talk。

有关如何实施备份代理的完整详细信息,请参阅Data Backup。我特别推荐底部的测试部分,因为备份不会立即发生,因此要进行测试,您必须强制备份。

当用户拥有多个设备时,这不会导致多个设备具有相同的 id 吗?例如平板电脑和手机。

答11:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

我认为这肯定是为唯一 ID 构建骨架的有效方式…检查一下。

伪唯一 ID,适用于所有 Android 设备 某些设备没有手机(例如平板电脑),或者出于某种原因,您不想包含 READ_PHONE_STATE 权限。您仍然可以阅读 ROM 版本、制造商名称、CPU 类型和其他硬件详细信息等详细信息,如果您想将 ID 用于序列密钥检查或其他一般用途,这将非常适合。以这种方式计算的 ID 不会是唯一的:可以找到具有相同 ID 的两个设备(基于相同的硬件和 ROM 映像),但实际应用程序中的变化可以忽略不计。为此,您可以使用 Build 类:

String m_szDevIDShort = "35" + //we make this look like a valid IMEIBuild.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

大多数 Build 成员都是字符串,我们在这里所做的是获取它们的长度并通过模数转换它。我们有 13 个这样的数字,我们在前面添加两个(35)以具有与 IMEI 相同大小的 ID(15 位)。这里还有其他的可能性很好,看看这些字符串。返回类似 355715565309247 的内容。不需要特别许可,使这种方法非常方便。

(额外信息:上面给出的技术是从 Pocket Magic 上的一篇文章中复制的。)

有趣的解决方案。听起来这是一种情况,你真的应该只是散列所有连接的数据,而不是试图提出你自己的“散列”函数。即使每个值都有不同的大量数据,在很多情况下也会发生冲突。我的建议:使用哈希函数,然后将二进制结果转换为十进制并根据需要截断。要做到这一点,尽管您确实应该使用 UUID 或完整的哈希字符串。

您应该感谢您的来源...这已直接从以下文章中删除:pocketmagic.net/?p=1662

这个 ID 容易发生冲突,就像你不知道是什么一样。它实际上可以保证在来自同一运营商的相同设备上是相同的。

如果设备升级,这也可能会改变。

非常非常糟糕的解决方案。在两个 Nexus 5 上测试...返回相同的数字。

原文链接:https://www.huntsbot.com/qa/oD1e/is-there-a-unique-android-device-id?lang=zh_CN&from=csdn

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

是否有唯一的 Android 设备 ID?相关推荐

  1. 是否有唯一的Android设备ID?

    Android设备是否具有唯一的ID,如果是,则使用Java访问它的简单方法是什么? #1楼 有许多不同的方法可以解决这些ANDROID_ID问题(有时可能为null或特定模型的设备总是返回相同的ID ...

  2. android设备id完美解决方法,如何在Android中获取唯一的设备硬件ID?

    您可以在下面的链接中查看此博客 [http://android-developers.blogspot.in/2011/03/identifying-app-installations.html] A ...

  3. java 如何获取设备号_java – 如何获取android设备ID?

    如何获取Android设备ID?我不知道什么是"背景". import android.content.Context; import android.provider.Setti ...

  4. jsb调用java_cocos2d-js | JSB 调用Java函数 | Android设备ID

    引擎版本:cocos2d-x-3.13 语言:cocos2d-js 几乎所有的游戏项目都有获取玩家设备ID的需求,这里记录一下使用cocos2d-js时的Android设备获取方式. 用JS获取And ...

  5. Android 设备Id 唯一不重复,Redmi

    1.(唯一)不重复类: package com.xxx.xxx.util;import android.annotation.SuppressLint; import android.content. ...

  6. android 获取设备id 崩溃,获取Android设备ID时出错

    我正在尝试在我的Android应用中检索我的adroid设备的设备ID.但是,在我的程序中添加以下行后,错误存在并且程序无法启动: String ts = Context.TELEPHONY_SERV ...

  7. android设备id完美解决方法,安卓获取渠道名渠道id Android获取设备唯一标识的终极解决方法,防止安卓7.0时崩溃问题...

    一,先说获取渠道名(这里以友盟为例) /* * 4.5.1新加渠道名字段,用来传给后台去统计各个渠道下载量 * */ public static String getSource() { //获取渠道 ...

  8. Android设备的ID

    Android的开发者在一些特定情况下都需要知道手机中的唯一设备ID.例如,跟踪应用程序的安装,生成用于复制保护的DRM时需要使用设备的唯一ID.在本文档结尾处提供了作为参考的示例代码片段. 范围 本 ...

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

    前言 udid: UDID是Unique Device Identifier的缩写,中文意思是设备唯一标识. uuid: UUID是Universally Unique Identifier的缩写,中 ...

最新文章

  1. ETSafeMail安全电子邮件技术白皮书
  2. 全注解怎么使用分页插件_分页插件使用的方式
  3. (76)FPGA随机函数($dist_uniform)
  4. 比人高效10倍,3分钟就能评估帕金森!这是腾讯新推出的AI医生
  5. HALCON 21.11:深度学习笔记---模型(8)
  6. python写错了如何撤销-Python集成开发工具Pycharm的使用方法:复制,撤销上一步.......
  7. Linux下的Vivado安装——以Ubuntu为例
  8. 《C专家编程》笔记——第一章
  9. BUUCTF-pwn(11)
  10. 你的头发还好吗?大数据分析脱发城市哪里强
  11. 超星网络学生登录入口 附使用教程
  12. Docker镜像分层原理-联合文件系统(UnionFS)
  13. 一年代码功能点的创新性怎么写_技术部分创新点-新产品
  14. hdu 2087 剪花布条 kmp小水
  15. 电脑如何设置日程提醒闹钟
  16. [python]一个特别好的学习python网站
  17. DML、DDL、DCL是什么?
  18. 【Unity3D插件】UniRx(基于Unity的响应式编程框架)插件教程
  19. 物理木板过河问题java_抖音捡木板过河
  20. antd Table 列hover高亮

热门文章

  1. Chrome前端插件
  2. 飞腾CPU体系结构(八)
  3. HEVC学习(二十八) —— 量化之二
  4. 各大自媒体平台的收益情况汇总
  5. BGP Confederation(BGP联邦)
  6. GOOGLE怎么用?
  7. POI设置Excel下拉列表(数据有效性验证)
  8. steam好友服务器当前处于离线状态,steam怎么修改在线状态-steam设置离线、想交易、隐身等状态的方法 - 河东软件园...
  9. $NOIP 2018 PJ游记[ZJ]$
  10. linux系统中如何查ip,在Linux系统中查看ip的命令是什么