Android 设备有唯一的 ID 吗?
Android 设备是否有唯一的 ID?如果有,使用 Java 访问它的简单方法是什么?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
Android 设备是否有唯一的 ID?如果有,使用 Java 访问它的简单方法是什么?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(30)
在 Google I/O 上,Reto Meier 发布了关于如何解决此问题的可靠答案,这应该可以满足大多数开发人员跟踪的需求跨安装的用户。安东尼·诺兰在他的答案中展示了方向,但我想我应该写出完整的方法,以便其他人可以轻松地了解如何做到这一点(我花了一段时间才弄清楚细节)。
这种方法将为您提供一个匿名、安全的用户 ID,该 ID 对于用户在不同设备(基于主要 Google 帐户)和安装之间的持久性。基本方法是生成随机用户 ID 并将其存储在应用程序的共享首选项中。然后,您可以使用 Google 的备份代理将链接到云中 Google 帐户的共享首选项存储起来。
让我们看一下完整的方法。首先,我们需要使用 Android 备份服务为 SharedPreferences 创建备份。首先通过
http://developer.android.com/google/backup/signup.html
注册您的应用。Google 将为您提供一个备份服务密钥,您需要将其添加到清单中。您还需要告诉应用程序使用 BackupAgent,如下所示:
然后您需要创建备份代理并告诉它使用共享首选项的帮助代理:
要完成备份,您需要在主 Activity 中创建 BackupManager 的实例:
最后创建一个用户 ID(如果尚不存在),并将其存储在 SharedPreferences 中:
此 User_ID 现在将在各个安装中保持不变,即使用户移动设备也是如此。
有关此方法的详细信息,请参阅 雷托的谈话。
有关如何实现备份代理的完整详细信息,请参阅数据备份。我特别推荐底部有关测试的部分,因为备份不会立即发生,因此要测试您必须强制备份。
At Google I/O Reto Meier released a robust answer to how to approach this which should meet most developers needs to track users across installations. Anthony Nolan shows the direction in his answer, but I thought I'd write out the full approach so that others can easily see how to do it (it took me a while to figure out the details).
This approach will give you an anonymous, secure user ID which will be persistent for the user across different devices (based on the primary Google account) and across installs. The basic approach is to generate a random user ID and to store this in the apps' shared preferences. You then use Google's backup agent to store the shared preferences linked to the Google account in the cloud.
Let's go through the full approach. First, we need to create a backup for our SharedPreferences using the Android Backup Service. Start by registering your app via
http://developer.android.com/google/backup/signup.html
.Google will give you a backup service key which you need to add to the manifest. You also need to tell the application to use the BackupAgent as follows:
Then you need to create the backup agent and tell it to use the helper agent for sharedpreferences:
To complete the backup you need to create an instance of BackupManager in your main Activity:
Finally create a user ID, if it doesn't already exist, and store it in the SharedPreferences:
This User_ID will now be persistent across installations, even if the user moves device.
For more information on this approach see Reto's talk.
And for full details of how to implement the backup agent see Data Backup. I particularly recommend the section at the bottom on testing as the backup does not happen instantaneously and so to test you have to force the backup.
我认为这是为唯一 ID 构建骨架的可靠方法...检查一下。
伪唯一 ID,适用于所有 Android 设备
有些设备没有手机(例如平板电脑),或者由于某种原因,您不想包含 READ_PHONE_STATE 权限。您仍然可以读取 ROM 版本、制造商名称、CPU 类型和其他硬件详细信息等详细信息,如果您想将 ID 用于串行密钥检查或其他一般用途,这些信息将非常适合。以这种方式计算的 ID 不会是唯一的:可以找到具有相同 ID 的两个设备(基于相同的硬件和 ROM 映像),但实际应用程序中的变化可以忽略不计。为此,您可以使用 Build 类:
大多数 Build 成员都是字符串,我们在这里所做的是获取它们的长度并通过数字模进行转换。我们有 13 个这样的数字,并且在前面添加了两个数字 (35),以使其 ID 大小与 IMEI(15 位数字)相同。这里还有其他可能性,只需看看这些字符串即可。
返回类似
355715565309247
的内容。不需要特殊许可,使得这种方法非常方便。(额外信息:上面给出的技术是从 Pocket Magic 上的一篇文章复制的。)
I think this is sure fire way of building a skeleton for a unique ID... check it out.
Pseudo-Unique ID, that works on all Android devices
Some devices don't have a phone (eg. Tablets) or for some reason, you don't want to include the READ_PHONE_STATE permission. You can still read details like ROM Version, Manufacturer name, CPU type, and other hardware details, that will be well suited if you want to use the ID for a serial key check, or other general purposes. The ID computed in this way won't be unique: it is possible to find two devices with the same ID (based on the same hardware and ROM image) but the changes in real-world applications are negligible. For this purpose you can use the Build class:
Most of the Build members are strings, what we're doing here is to take their length and transform it via modulo in a digit. We have 13 such digits and we are adding two more in front (35) to have the same size ID as the IMEI (15 digits). There are other possibilities here are well, just have a look at these strings.
Returns something like
355715565309247
. No special permission is required, making this approach very convenient.(Extra info: The technique given above was copied from an article on Pocket Magic.)
以下代码使用隐藏的 Android API 返回设备序列号。但是,此代码不适用于 Samsung Galaxy Tab,因为此设备上未设置“ro.serialno”。
The following code returns the device serial number using a hidden Android API. But, this code don't works on Samsung Galaxy Tab because "ro.serialno" isn't set on this device.
使用下面的代码,您可以获取 Android 操作系统设备的唯一设备 ID 作为字符串。
Using the code below, you can get the unique device ID of an Android OS device as a string.
我要补充的一件事是——我遇到了其中一种独特的情况。
使用:
事实证明,即使我的 Viewsonic G Tablet 报告的 DeviceID 不为 Null,但每台 G Tablet 都报告相同的编号。
玩“Pocket Empires”会很有趣,它可以让您根据“唯一”DeviceID 即时访问某人的帐户。
我的设备没有手机无线电。
One thing I'll add - I have one of those unique situations.
Using:
Turns out that even though my Viewsonic G Tablet reports a DeviceID that is not Null, every single G Tablet reports the same number.
Makes it interesting playing "Pocket Empires" which gives you instant access to someone's account based on the "unique" DeviceID.
My device does not have a cell radio.
Serial 字段已添加到
Build API 级别 9 中的类(Android 2.3 - Gingerbread)。文档称它代表硬件序列号。因此,如果它存在于设备上,它应该是唯一的。
我不知道 API 级别 >= 9 的所有设备是否真正支持它(=not null)。
A Serial field was added to the
Build
class in API level 9 (Android 2.3 - Gingerbread). Documentation says it represents the hardware serial number. Thus it should be unique, if it exists on the device.I don't know whether it is actually supported (=not null) by all devices with API level >= 9 though.
有关如何获取安装应用程序的每个 Android 设备的唯一标识符的详细说明,请参阅官方 Android 开发人员博客文章 识别应用程序安装。
似乎最好的方法是您在安装时自己生成一个,然后在应用程序重新启动时读取它。
我个人认为这是可以接受的,但并不理想。 Android 提供的任何标识符都不适用于所有情况,因为大多数标识符取决于手机的无线电状态(Wi-Fi 开/关、蜂窝网络开/关、蓝牙开/关)。其他的,例如
Settings.Secure.ANDROID_ID
必须由制造商实现,并且不保证是唯一的。以下是将数据写入安装文件的示例,该文件将与应用程序在本地保存的任何其他数据一起存储。
For detailed instructions on how to get a unique identifier for each Android device your application is installed from, see the official Android Developers Blog posting Identifying App Installations.
It seems the best way is for you to generate one yourself upon installation and subsequently read it when the application is re-launched.
I personally find this acceptable but not ideal. No one identifier provided by Android works in all instances as most are dependent on the phone's radio states (Wi-Fi on/off, cellular on/off, Bluetooth on/off). The others, like
Settings.Secure.ANDROID_ID
must be implemented by the manufacturer and are not guaranteed to be unique.The following is an example of writing data to an installation file that would be stored along with any other data the application saves locally.
在类文件中添加以下代码:
在AndroidManifest.xml中添加:
Add Below code in class file:
Add in AndroidManifest.xml:
有很多不同的方法可以解决这些
ANDROID_ID
问题(有时可能为null
或者特定型号的设备总是返回相同的 ID),各有利弊我自己更喜欢使用现有的 OpenUDID 实现(请参阅https://github.com/ylechelle/OpenUDID)适用于 Android(请参阅 https://github.com/vieux/OpenUDID)。它很容易集成并利用
ANDROID_ID
以及针对上述问题的后备方案。There are a lot of different approaches to work around those
ANDROID_ID
issues (may benull
sometimes or devices of a specific model always return the same ID) with pros and cons:I myself prefer using an existing OpenUDID implementation (see https://github.com/ylechelle/OpenUDID) for Android (see https://github.com/vieux/OpenUDID). It is easy to integrate and makes use of the
ANDROID_ID
with fallbacks for those issues mentioned above.我的两分钱 - 注意,这是针对设备(错误)唯一 ID - 不是 Android 开发者博客。
值得注意的是,@emmby 提供的解决方案会回退到每个应用程序 ID,因为 SharedPreferences 未跨进程同步(请参阅此处和此处)。所以我完全避免了这种情况。
相反,我将获取(设备)ID 的各种策略封装在枚举中 - 更改枚举常量的顺序会影响获取 ID 的各种方式的优先级。返回第一个非 null ID 或引发异常(按照不赋予 null 含义的良好 Java 实践)。例如,我首先有 TELEPHONY - 但一个好的默认选择是 ANDROID_ID
测试版:
My two cents - NB this is for a device (err) unique ID - not the installation one as discussed in the Android developers's blog.
Of note that the solution provided by @emmby falls back in a per application ID as the SharedPreferences are not synchronized across processes (see here and here). So I avoided this altogether.
Instead, I encapsulated the various strategies for getting a (device) ID in an enum - changing the order of the enum constants affects the priority of the various ways of getting the ID. The first non-null ID is returned or an exception is thrown (as per good Java practices of not giving null a meaning). So for instance I have the TELEPHONY one first - but a good default choice would be the ANDROID_ID
beta:
这里有 30 多个答案,有些是相同的,有些是独特的。这个答案是基于其中的一些答案。其中之一是@Lenn Dolling 的回答。
它组合 3 个 ID 并创建一个 32 位十六进制字符串。它对我来说非常有效。
3 个 ID 是:
伪ID - 根据物理设备规格生成
ANDROID_ID -
Settings.Secure.ANDROID_ID
蓝牙地址 - 蓝牙适配器地址
它将返回如下内容:551F27C060712A72730B0A0F734064B1
注意:您始终可以向
longId
字符串添加更多ID。例如,序列号。 wifi 适配器地址。 IMEI。通过这种方式,您可以使其在每个设备上变得更加独特。There are 30+ answers here and some are same and some are unique. This answer is based on few of those answers. One of them being @Lenn Dolling's answer.
It combines 3 IDs and creates a 32-digit hex string. It has worked very well for me.
3 IDs are:
Pseudo-ID - It is generated based on physical device specifications
ANDROID_ID -
Settings.Secure.ANDROID_ID
Bluetooth Address - Bluetooth adapter address
It will return something like this: 551F27C060712A72730B0A0F734064B1
Note: You can always add more IDs to the
longId
string. For example, Serial #. wifi adapter address. IMEI. This way you are making it more unique per device.IMEI 怎么样。这对于 Android 或其他移动设备来说是独一无二的。
How about the IMEI. That is unique for Android or other mobile devices.
Android 操作系统设备的唯一设备 ID 作为字符串,使用
TelephonyManager
和ANDROID_ID
获取:但我强烈推荐 Google 建议的方法,请参阅< a href="http://android-developers.blogspot.mx/2011/03/identifying-app-installations.html" rel="noreferrer">识别应用程序安装。
The unique device ID of an Android OS device as String, using
TelephonyManager
andANDROID_ID
, is obtained by:But I strongly recommend a method suggested by Google, see Identifying App Installations.
以下是我生成唯一 id 的方法:
Here is how I am generating the unique id:
另一种方法是在应用程序中使用
/sys/class/android_usb/android0/iSerial
而无需任何权限。要在 Java 中执行此操作,只需使用 FileInputStream 打开 iSerial 文件并读出字符。请确保将其包装在异常处理程序中,因为并非所有设备都有此文件。
至少已知以下设备具有此文件:
您还可以查看我的博客文章 将 Android 硬件序列号泄露给非特权应用,我在其中讨论了什么其他文件可供参考。
Another way is to use
/sys/class/android_usb/android0/iSerial
in an app without any permissions whatsoever.To do this in Java one would just use a FileInputStream to open the iSerial file and read out the characters. Just be sure you wrap it in an exception handler, because not all devices have this file.
At least the following devices are known to have this file world-readable:
You can also see my blog post Leaking Android hardware serial number to unprivileged apps where I discuss what other files are available for information.
对于特定 Android 设备的硬件识别,您可以检查 MAC 地址。
你可以这样做:
在 AndroidManifest.xml
现在在你的代码中:
在每个 Android 设备中,它们至少是“wlan0”接口是 WI-FI 芯片。
即使 WI-FI 未打开,此代码也能工作。
聚苯乙烯
您可以从包含 MACS 的列表中获得许多其他接口,但这可能会在手机之间发生变化。
For hardware recognition of a specific Android device you could check the MAC Addresses.
you can do it that way:
in AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
now in your code:
In every Android device their is at least a "wlan0" Interface witch is the WI-FI chip.
This code works even when WI-FI is not turned on.
P.S.
Their are a bunch of other Interfaces you will get from the list containing MACS But this can change between phones.
当设备不具备电话功能时,我使用以下代码获取
IMEI
或使用 Secure.ANDROID_ID
作为替代方案:I use the following code to get the
IMEI
or use Secure.ANDROID_ID
as an alternative, when the device doesn't have phone capabilities:TelephonyManger.getDeviceId() 返回唯一的设备 ID,例如 GSM 的 IMEI 和 CDMA 手机的 MEID 或 ESN。
但我建议使用:
Settings.Secure.ANDROID_ID,它将 Android ID 作为唯一的 64 位十六进制字符串返回。
有时 TelephonyManger.getDeviceId() 将返回 null,因此为了确保唯一的 id,您将使用此方法:
TelephonyManger.getDeviceId() Returns the unique device ID, for example, the IMEI for GSM and the MEID or ESN for CDMA phones.
But i recommend to use:
Settings.Secure.ANDROID_ID that returns the Android ID as an unique 64-bit hex string.
Sometimes TelephonyManger.getDeviceId() will return null, so to assure an unique id you will use this method:
Google 实例 ID
在 I/O 2015 上发布;在 Android 上需要播放服务 7.5。
https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation
Google 似乎打算使用此 ID 来识别 Android、Chrome 和 iOS 上的安装。
它标识的是安装而不是设备,但话又说回来,ANDROID_ID(这是公认的答案)现在也不再标识设备。使用 ARC 运行时,每次安装都会生成新的 ANDROID_ID (详细信息此处),就像这个新实例 ID 一样。另外,我认为识别安装(而不是设备)是我们大多数人实际上正在寻找的。
实例 ID 的优点
在我看来,Google 打算将其用于此目的(识别您的安装),它是跨平台的,并且可用于许多其他目的(请参阅上面的链接)。
如果您使用 GCM,那么您最终将需要使用此实例 ID,因为您需要它才能获取 GCM 令牌(取代旧的 GCM 注册 ID)。
缺点/问题
在当前实现 (GPS 7.5) 中,当您的应用请求实例 ID 时,会从服务器检索实例 ID。这意味着上面的调用是一个阻塞调用 - 在我不科学的测试中,如果设备在线,则需要 1-3 秒,如果离线则需要 0.5 - 1.0 秒(大概这是它在放弃并生成一个之前等待的时间)随机 ID)。这是在北美使用 Android 5.1.1 和 GPS 7.5 的 Nexus 5 进行测试的。
如果您将 ID 用于他们预期的目的 - 例如。应用程序身份验证、应用程序识别、GCM - 我认为这 1-3 秒可能会很麻烦(当然取决于您的应用程序)。
Google Instance ID
Released at I/O 2015; on Android requires play services 7.5.
https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation
It seems that Google intends for this ID to be used to identify installations across Android, Chrome, and iOS.
It identifies an installation rather then a device, but then again, ANDROID_ID (which is the accepted answer) now no longer identifies devices either. With the ARC runtime a new ANDROID_ID is generated for every installation (details here), just like this new instance ID. Also, I think that identifying installations (not devices) is what most of us are actually looking for.
The advantages of instance ID
It appears to me that Google intends for it to be used for this purpose (identifying your installations), it is cross-platform, and can be used for a number of other purposes (see the links above).
If you use GCM, then you will eventually need to use this instance ID because you need it in order to get the GCM token (which replaces the old GCM registration ID).
The disadvantages/issues
In the current implementation (GPS 7.5) the instance ID is retrieved from a server when your app requests it. This means that the call above is a blocking call - in my unscientific testing it takes 1-3 seconds if the device is online, and 0.5 - 1.0 seconds if off-line (presumably this is how long it waits before giving up and generating a random ID). This was tested in North America on Nexus 5 with Android 5.1.1 and GPS 7.5.
If you use the ID for the purposes they intend - eg. app authentication, app identification, GCM - I think this 1-3 seconds could be a nuisance (depending on your app, of course).
借助以下函数获取设备设备 UUID、带有品牌名称的型号及其版本号。
在 Android 10 中完美运行,无需允许读取手机状态权限。
代码片段:
调用上述函数并检查上述代码的输出。请在 android studio 中查看您的日志猫。它如下所示:
Get Device UUID, model number with brand name and its version number with the help of below function.
Work in Android 10 perfectly and no need to allow read phone state permission.
Code Snippets:
Call Above function and to check output of above code. please see your log cat in android studio. It look likes below:
Google 现在拥有广告 ID。
这也可以使用,但要注意:
ID
因此,尽管这个 id 可能会改变,但似乎很快就会 我们可能别无选择,具体取决于此 ID 的用途。
更多信息@develper.android
在此处复制粘贴代码
HTH
Google now has an Advertising ID.
This can also be used, but note that :
and
So though this id may change, it seems that soon we may not have a choice, depends on the purpose of this id.
More info @ develper.android
Copy-paste code here
HTH
Settings.Secure#ANDROID_ID
以每个用户唯一的 Android ID 返回< /a> 64 位十六进制字符串。另请阅读唯一标识符的最佳实践:https:// developer.android.com/training/articles/user-data-ids
Settings.Secure#ANDROID_ID
returns the Android ID as an unique for each user 64-bit hex string.Also read Best practices for unique identifiers: https://developer.android.com/training/articles/user-data-ids
更新:从最新版本的 Android 开始,
ANDROID_ID
的许多问题已得到解决,我相信不再需要这种方法。请查看安东尼的回答。完全披露:我的应用程序最初使用以下方法,但不再使用此方法,我们现在使用 Android 开发者博客 条目,emmby 的回答 链接到(即,生成并保存
UUID#randomUUID()
)。
这个问题有很多答案,其中大多数只能在“某些”时间起作用,不幸的是,这还不够好。
根据我对设备的测试(所有手机,至少其中一部未激活):
TelephonyManager.getDeviceId()
的值TelephonyManager.getSimSerialNumber()
的值getSimSerialNumber()
返回 null(如预期)ANDROID_ID 的值
ANDROID_ID
和TelephonyManager.getDeviceId()
返回相同的值(或相同值的派生值) - 只要 在设置过程中已添加 Google 帐户。因此,如果您想要设备本身独有的东西,
TM.getDeviceId()
应该就足够了。显然,某些用户比其他用户更加偏执,因此对这些标识符中的 1 个或多个进行哈希处理可能会很有用,这样该字符串实际上对于设备来说仍然是唯一的,但不会明确标识用户的实际设备。例如,使用String.hashCode()
与 UUID: 结合使用可能会产生如下结果:
00000000-54b3-e7c7-0000-000046bffd97
它对我来说足够好了。
正如 Richard 在下面提到的,不要忘记您需要读取
TelephonyManager
属性的权限,因此将其添加到您的清单中:导入库
UPDATE: As of recent versions of Android, many of the issues with
ANDROID_ID
have been resolved, and I believe this approach is no longer necessary. Please take a look at Anthony's answer.Full disclosure: my app used the below approach originally but no longer uses this approach, and we now use the approach outlined in the Android Developer Blog entry that emmby's answer links to (namely, generating and saving a
UUID#randomUUID()
).There are many answers to this question, most of which will only work "some" of the time, and unfortunately, that's not good enough.
Based on my tests of devices (all phones, at least one of which is not activated):
TelephonyManager.getDeviceId()
TelephonyManager.getSimSerialNumber()
getSimSerialNumber()
(as expected)ANDROID_ID
ANDROID_ID
andTelephonyManager.getDeviceId()
-- as long as a Google account has been added during setup.So if you want something unique to the device itself,
TM.getDeviceId()
should be sufficient. Obviously, some users are more paranoid than others, so it might be useful to hash 1 or more of these identifiers, so that the string is still virtually unique to the device, but does not explicitly identify the user's actual device. For example, usingString.hashCode()
, combined with a UUID:might result in something like:
00000000-54b3-e7c7-0000-000046bffd97
It works well enough for me.
As Richard mentions below, don't forget that you need permission to read the
TelephonyManager
properties, so add this to your manifest:import libraries
#最后更新时间:2015 年 6 月 2 日
在阅读了所有关于创建唯一 ID 的 Stack Overflow 帖子、Google 开发者博客和 Android 文档后,我觉得“伪 ID”是最好的选择。
主要问题:硬件与软件
硬件
软件
#Android 的总体细分
###- 保证 API 的唯一性(包括已 root 的设备)>= 9/10(99.5% 的 Android)设备)
###- 没有额外的权限
伪代码:
感谢@stansult 发布我们的所有选项(在这个 Stack Overflow 问题中)。
##选项列表 - 为什么/为什么不使用它们的原因:
用户电子邮件 - 软件
用户可以更改电子邮件 - 极不可能
API 5+
或API 14+
(如何获取 Android 设备的主电子邮件地址)用户电话号码 - 软件
用户可以更改电话号码 - 极不可能
IMEI - 硬件(仅限手机,需要
android.permission.READ_PHONE_STATE
)大多数用户讨厌它说“电话”在许可中。一些用户给出差评是因为他们认为您只是在窃取他们的个人信息,而您真正想做的只是跟踪设备安装。很明显您正在收集数据。
Android ID - 硬件(可以为空,可以在恢复出厂设置时更改) ,可以在 root 设备上更改)
由于它可以为“null”,因此我们可以检查“null”并更改它的价值,但这意味着它不再是唯一的。
如果您的用户拥有恢复出厂设置的设备,则该值可能已在已取得 root 权限的设备上更改或更改,因此如果您正在跟踪用户安装,则可能会出现重复条目。
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% 的用户谁拥有 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 设备信息。这就是可能发生碰撞的地方。
更改:
请查看以下方法:
#New(适用于带有广告和 Google Play 服务的应用程序):
< strong>从 Google Play 开发者控制台:
实现:
权限:
代码:
源代码/文档:
http://developer.android.com/google/play-services/id.html
http://developer.android.com/reference /com/google/android/gms/ads/identifier/AdvertisingIdClient.html
##重要:
##警告,用户可以重置:
http://en.kioskea .net/faq/34732-android-reset-your-advertising-id
我尝试引用我从中获取信息的每个链接。如果有遗漏需要补充的请评论!
Google 播放器服务实例 ID
https://developers.google.com/instance-id/
#Last Updated: 6/2/15
After reading every Stack Overflow post about creating a unique ID, the Google developer blog, and Android documentation, I feel as if the 'Pseudo ID' is the best possible option.
Main Issue: Hardware vs Software
Hardware
Software
#Overall breakdown with Android
###- Guarantee uniqueness (include rooted devices) for API >= 9/10 (99.5% of Android devices)
###- No extra permissions
Psuedo code:
Thanks to @stansult for posting all of our options (in this Stack Overflow question).
##List of options - reasons why/ why not to use them:
User Email - Software
User could change email - HIGHLY unlikely
API 5+
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
orAPI 14+
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
(How to get the Android device's primary e-mail address)User Phone Number - Software
Users could change phone numbers - HIGHLY unlikely
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
IMEI - Hardware (only phones, needs
android.permission.READ_PHONE_STATE
)Most users hate the fact that it says "Phone Calls" in the permission. Some users give bad ratings because they believe you are simply stealing their personal information when all you really want to do is track device installs. It is obvious that you are collecting data.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Android ID - Hardware (can be null, can change upon factory reset, can be altered on a rooted device)
Since it can be 'null', we can check for 'null' and change its value, but this means it will no longer be unique.
If you have a user with a factory reset device, the value may have changed or altered on the rooted device so there may be duplicates entries if you are tracking user installs.
WLAN MAC Address - Hardware (needs
android.permission.ACCESS_WIFI_STATE
)This could be the second-best option, but you are still collecting and storing a unique identifier that comes directly from a user. This is obvious that you are collecting data.
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE "/>
Bluetooth MAC Address - Hardware (devices with Bluetooth, needs
android.permission.BLUETOOTH
)Most applications on the market do not use Bluetooth, and so if your application doesn't use Bluetooth and you are including this, the user could become suspicious.
<uses-permission android:name="android.permission.BLUETOOTH "/>
Pseudo-Unique ID - Software (for all Android devices)
Very possible, may contain collisions - See my method posted below!
This allows you to have an 'almost unique' ID from the user without taking anything that is private. You can create your own anonymous ID from device information.
I know there isn't any 'perfect' way of getting a unique ID without using permissions; however, sometimes we only really need to track the device installation. When it comes to creating a unique ID, we can create a 'pseudo unique id' based solely on information that the Android API gives us without using extra permissions. This way, we can show the user respect and try to offer a good user experience as well.
With a pseudo-unique id, you really only run into the fact that there may be duplicates based on the fact that there are similar devices. You can tweak the combined method to make it more unique; however, some developers need to track device installs and this will do the trick or performance based on similar devices.
##API >= 9:
If their Android device is API 9 or over, this is guaranteed to be unique because of the 'Build.SERIAL' field.
REMEMBER, you are technically only missing out on around 0.5% of users who have API < 9. So you can focus on the rest: This is 99.5% of the users!
##API < 9:
If the user's Android device is lower than API 9; hopefully, they have not done a factory reset and their 'Secure.ANDROID_ID' will be preserved or not 'null'. (see http://developer.android.com/about/dashboards/index.html)
##If all else fails:
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 on their Android device information. This is where the collisions can happen.
Changes:
Please take a look at the method below:
#New (for apps with ads AND Google Play Services):
From the Google Play Developer's console:
Implementation:
Permission:
Code:
Source/Docs:
http://developer.android.com/google/play-services/id.html
http://developer.android.com/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.html
##Important:
##Warning, users can reset:
http://en.kioskea.net/faq/34732-android-reset-your-advertising-id
I have tried to reference every link that I took information from. If you are missing and need to be included, please comment!
Google Player Services InstanceID
https://developers.google.com/instance-id/
正如 Dave Webb 提到的,Android 开发者博客有一篇文章 涵盖了这一点。他们首选的解决方案是跟踪应用程序安装而不是设备,这对于大多数用例都适用。这篇博客文章将向您展示实现该功能所需的代码,我建议您查看一下。
但是,如果您需要设备标识符而不是应用程序安装标识符,该博客文章将继续讨论解决方案。我与 Google 的某人进行了交谈,以便在您需要时对一些项目进行一些额外的说明。以下是我在上述博客文章中未提及的有关设备标识符的发现:
根据 Google 的建议,我实现了一个类,该类将为每个设备生成唯一的 UUID,在适当的情况下使用 ANDROID_ID 作为种子,必要时依靠 TelephonyManager.getDeviceId() ,如果失败,则诉诸随机生成的唯一 UUID该信息在应用程序重新启动后仍然存在(但不影响应用程序重新安装)。
请注意,对于必须回退设备 ID 的设备,唯一 ID将在恢复出厂设置后仍然保留。这是需要注意的事情。如果您需要确保恢复出厂设置会重置您的唯一 ID,您可能需要考虑直接回退到随机 UUID,而不是设备 ID。
同样,此代码用于设备 ID,而不是应用程序安装 ID。在大多数情况下,您可能需要的是应用程序安装 ID。但如果您确实需要设备 ID,那么以下代码可能适合您。
As Dave Webb mentions, the Android Developer Blog has an article that covers this. Their preferred solution is to track app installs rather than devices, and that will work well for most use cases. The blog post will show you the necessary code to make that work, and I recommend you check it out.
However, the blog post goes on to discuss solutions if you need a device identifier rather than an app installation identifier. I spoke with someone at Google to get some additional clarification on a few items in the event that you need to do so. Here's what I discovered about device identifiers that's NOT mentioned in the aforementioned blog post:
Based on Google's recommendations, I implemented a class that will generate a unique UUID for each device, using ANDROID_ID as the seed where appropriate, falling back on TelephonyManager.getDeviceId() as necessary, and if that fails, resorting to a randomly generated unique UUID that is persisted across app restarts (but not app re-installations).
Note that for devices that have to fallback on the device ID, the unique ID WILL persist across factory resets. This is something to be aware of. If you need to ensure that a factory reset will reset your unique ID, you may want to consider falling back directly to the random UUID instead of the device ID.
Again, this code is for a device ID, not an app installation ID. For most situations, an app installation ID is probably what you're looking for. But if you do need a device ID, then the following code will probably work for you.
以下是 Reto Meier 在今年的 Google I/O 演示中使用的代码,用于获取唯一 ID用户:
如果您将此与备份策略结合起来以将首选项发送到云(Reto 的 talk,您应该有一个与用户关联的 id,并在设备被擦除甚至更换后保留下来。我打算使用这个在未来的分析中(换句话说,我还没有做到这一点:)。
Here is the code that Reto Meier used in the Google I/O presentation this year to get a unique id for the user:
If you couple this with a backup strategy to send preferences to the cloud (also described in Reto's talk, you should have an id that ties to a user and sticks around after the device has been wiped, or even replaced. I plan to use this in analytics going forward (in other words, I have not done that bit yet :).
这是一个简单的问题,没有简单的答案。
此外,这里所有现有的答案要么已经过时,要么不可靠。
因此,如果您正在寻找 2020 年之后的解决方案。
以下是需要记住的一些事项:
所有基于硬件的标识符(IMEI、MAC、序列号等)对于非 Google 设备(Pixel 和 Nexus 除外)来说都是不可靠的,统计数据全球大多数 Android 活跃设备。因此,官方 Android 标识符最佳实践明确指出:
这使得此处的大多数答案无效。另外,由于不同的 Android 安全更新,其中一些需要更新且更严格的运行时权限,而用户可以简单地拒绝这些权限。
例如,
CVE-2018-9489
会影响上述所有基于 WIFI 的技术。这使得这些标识符不仅不可靠,而且在许多情况下也无法访问。
简而言之:不要使用这些技术。
这里的许多其他答案都建议使用
AdvertisingIdClient
,它也是不兼容的,因为它的设计仅用于广告分析。 官方参考中也有说明这不仅对于设备识别而言不可靠,而且您还必须遵循 有关广告跟踪的用户隐私政策,该政策明确规定用户可以随时重置或阻止该政策。
所以也不要使用它。
因为您无法拥有所需的静态全局唯一且可靠的设备标识符。 Android官方参考建议:
它对于设备上的应用程序安装来说是独一无二的,因此当用户卸载该应用程序时,它就会被清除,因此它不是 100% 可靠,但它是退而求其次的。
注意 从今天开始,
FirebaseInstanceId
已弃用,您应该使用FirebaseInstallations
代替。要使用
FirebaseInstallations
,请添加最新的 firebase-messaging 依赖项 进入你的 gradle并使用下面的代码来获取 firebase ID:
如果你需要将设备标识存储在远程服务器上,那么不要按原样存储(纯文本),而是 加盐哈希。
如今,这不仅是最佳实践,实际上您还必须根据 GDPR - 标识符 和类似规定。
It's a simple question, with no simple answer.
Moreover, all of the existing answers here are either out of date or unreliable.
So if you're searching for a solution after 2020.
Here are a few things to keep in mind:
All the hardware-based identifiers (IMEI, MAC, Serial Number, etc.) are unreliable for non-google devices (except Pixels and Nexuses), which are statistically most of the android active devices worldwide. Therefore official Android identifiers best practices clearly states:
Which makes most of the answers here invalid. Also due to different android security updates, some of them require newer and stricter runtime permissions, which can be simply denied by the user.
For example
CVE-2018-9489
affects all the WIFI based techniques mentioned above.That makes those identifiers not only unreliable but also inaccessible in many cases.
So in simpler words: don't use those techniques.
Many other answers here are suggesting to use the
AdvertisingIdClient
, which is also incompatible, as it's by design only for ads profiling. It's also stated in the official referenceIt's not only unreliable for device identification, but you also must follow the user privacy regarding ad tracking policy, which states clearly that users can reset or block it at any moment.
So don't use it either.
Since you cannot have the desired static globally unique and reliable device identifier. Android's official reference suggests:
It's unique for the application installation on the device, so when the user uninstalls the app - it's wiped out, so it's not 100% reliable, but it's the next best thing.
Note As of today the
FirebaseInstanceId
is deprecated, you should useFirebaseInstallations
instead.To use
FirebaseInstallations
add the latest firebase-messaging dependency into your gradleAnd use the code below to get the firebase ID:
If you need to store the device identification on your remote server, then don't store it as is (plain text), but a hash with salt.
Today it's not only a best practice, you actually must do it by law according to GDPR - identifiers and similar regulations.
您还可以考虑 Wi-Fi 适配器的 MAC 地址。像这样检索:
需要清单中的权限
android.permission.ACCESS_WIFI_STATE
。据报道,即使未连接 Wi-Fi 也可用。如果上面答案中的乔在他的许多设备上尝试一下,那就太好了。
在某些设备上,当 Wi-Fi 关闭时该功能不可用。
注意:从 Android 6.x 开始,它返回一致的假 MAC 地址:
02:00:00:00:00:00
Also you might consider the Wi-Fi adapter's MAC address. Retrieved like this:
Requires permission
android.permission.ACCESS_WIFI_STATE
in the manifest.Reported to be available even when Wi-Fi is not connected. If Joe from the answer above gives this one a try on his many devices, that'd be nice.
On some devices, it's not available when Wi-Fi is turned off.
NOTE: From Android 6.x, it returns consistent fake mac address:
02:00:00:00:00:00
这里有相当有用的信息。
它涵盖五种不同的 ID 类型:
android.permission.READ_PHONE_STATE
)android. permission.ACCESS_WIFI_STATE
)android.permission.BLUETOOTH
)There’s rather useful info here.
It covers five different ID types:
android.permission.READ_PHONE_STATE
)android.permission.ACCESS_WIFI_STATE
)android.permission.BLUETOOTH
)官方 Android 开发者博客现在有一篇关于这个主题的完整文章,识别应用程序安装。
The official Android Developers Blog now has a full article just about this very subject, Identifying App Installations.