如何查找Android设备的序列号?
我需要为 Android 应用程序使用唯一的 ID,并且我认为设备的序列号是一个不错的选择。如何在我的应用程序中检索 Android 设备的序列号?
I need to use a unique ID for an Android app and I thought the serial number for the device would be a good candidate. How do I retrieve the serial number of an Android device in my app ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
getSystemService 是 Activity 类中的一个方法。 getDeviceID() 将返回设备的 MDN 或 MEID,具体取决于手机使用的无线电(GSM 或 CDMA)。
每个设备必须在此处返回一个唯一的值(假设它是电话)。这应该适用于任何带有 SIM 插槽或 CDMA 无线电的 Android 设备。您只能独自使用 Android 供电的微波炉;-)
getSystemService is a method from the Activity class. getDeviceID() will return the MDN or MEID of the device depending on which radio the phone uses (GSM or CDMA).
Each device MUST return a unique value here (assuming it's a phone). This should work for any Android device with a sim slot or CDMA radio. You're on your own with that Android powered microwave ;-)
正如 Dave Webb 提到的,Android 开发者博客有一篇文章 涵盖了这一点。
我与谷歌的某人进行了交谈,以获得对一些项目的额外澄清。以下是我发现上述博客文章中未提及的内容:
根据 Google 的建议,我实现了一个类,该类将为每个设备生成唯一的 UUID,在适当的情况下使用 ANDROID_ID 作为种子,必要时依靠 TelephonyManager.getDeviceId() ,如果失败,则诉诸随机生成的唯一 UUID该信息在应用程序重新启动后仍然存在(但不是应用程序重新安装)。
As Dave Webb mentions, the Android Developer Blog has an article that covers this.
I spoke with someone at Google to get some additional clarification on a few items. Here's what I discovered 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).
此代码使用隐藏的 Android API 返回设备序列号。
This code returns device serial number using a hidden Android API.
不过,不能保证 Android ID 是唯一标识符。
Although, it is not guaranteed that the Android ID will be an unique identifier.
Android 开发者博客上有一篇讨论此问题的优秀文章。
它建议不要使用
TelephonyManager.getDeviceId()
因为它不适用于平板电脑等非手机的 Android 设备,所以它需要READ_PHONE_STATE
权限,并且它不能在所有手机上可靠地工作。相反,您可以使用以下其中一项:
这篇文章讨论了每种方法的优缺点,值得一读,以便您可以找出最适合您使用的方法。
There is an excellent post on the Android Developer's Blog discussing this.
It recommends against using
TelephonyManager.getDeviceId()
as it doesn't work on Android devices which aren't phones such as tablets, it requires theREAD_PHONE_STATE
permission and it doesn't work reliably on all phones.Instead you could use one of the following:
The post discusses the pros and cons of each and it's worth reading so you can work out which would be the best for your use.
对于设备唯一且在其生命周期内恒定的简单数字(除非恢复出厂设置或黑客攻击),请使用 Settings.Secure.ANDROID_ID。
要使用设备序列号(“系统设置/关于/状态”中显示的序列号)(如果可用)并回退到 Android ID:
For a simple number that is unique to the device and constant for its lifetime (barring a factory reset or hacking), use Settings.Secure.ANDROID_ID.
To use the device serial number (the one shown in "System Settings / About / Status") if available and fall back to Android ID:
IMEI 很好,但仅适用于带有电话的 Android 设备。您还应该考虑支持平板电脑或其他没有手机的 Android 设备。
您有一些替代方案,例如:构建类成员、BT MAC、WLAN MAC,甚至更好 - 所有这些的组合。
我在我的博客上的一篇文章中解释了这些细节,请参阅:
http://www.pocketmagic.net/?p=1662
The IMEI is good but only works on Android devices with phone. You should consider support for Tablets or other Android devices as well, that do not have a phone.
You have some alternatives like: Build class members, BT MAC, WLAN MAC, or even better - a combination of all these.
I have explained these details in an article on my blog, see:
http://www.pocketmagic.net/?p=1662
由于这里没有答案提到一个完美的、防故障的 ID,它通过系统更新持久存在,并且存在于所有设备中(主要是因为 Google 没有单独的解决方案),我决定发布一个方法,通过组合两个可用的标识符,并在运行时检查在它们之间进行选择,该方法是下一个最好的方法。
在编写代码之前,有 3 个事实:
TelephonyManager.getDeviceId()
(akaIMEI)对于非 GSM、3G、LTE 等设备无法正常工作或根本无法工作,但始终会当存在相关硬件时返回唯一 ID,即使未插入 SIM 卡或不存在 SIM 卡插槽(某些 OEM 已这样做)。自 Gingerbread (Android 2.3)
android.os.Build.SERIAL
必须存在于任何不提供 IMEI 的设备上,即没有上述内容硬件存在,根据 Android 政策。由于事实 (2.),这两个唯一标识符中至少有一个将始终存在,并且 SERIAL 可以与 IMEI 同时存在.
注意:事实 (1.) 和 (2.) 基于Google 声明
解决方案
有了上述事实,人们总是可以通过检查是否有 IMEI 绑定的硬件来获得唯一标识符,并在没有时回退到 SERIAL,因为人们不能检查现有的 SERIAL 是否有效。以下静态类提供了 2 种用于检查此类存在并使用 IMEI 或 SERIAL 的方法:
我建议使用
getCleartextID_HARDCHECK
。如果反射在您的环境中不存在,请改用getCleartextID_SIMCHECK
方法,但要考虑到它应该适应您特定的 SIM 存在需求。PS:请注意,OEM 已设法根据 Google 政策排除 SERIAL(多个设备具有相同的 SERIAL),并且 Google 表示,至少有一个已知案例一个大的OEM(没有透露,我也不知道它是哪个品牌,我猜是三星)。
免责声明:这回答了获取唯一设备 ID 的原始问题,但 OP 指出他需要应用程序的唯一 ID,从而引入了歧义。即使对于这种情况 Android_ID 会更好,但在通过 2 个不同的 ROM 安装(甚至可以是相同的 ROM)对应用程序进行 Titanium 备份之后,它也将无法工作。我的解决方案保持独立于闪存或恢复出厂设置的持久性,并且仅当通过黑客/硬件模组发生 IMEI 或 SERIAL 篡改时才会失败。
Since no answer here mentions a perfect, fail-proof ID that is both PERSISTENT through system updates and exists in ALL devices (mainly due to the fact that there isn't an individual solution from Google), I decided to post a method that is the next best thing by combining two of the available identifiers, and a check to chose between them at run-time.
Before code, 3 facts:
TelephonyManager.getDeviceId()
(a.k.a.IMEI) will not work well or at all for non-GSM, 3G, LTE, etc. devices, but will always return a unique ID when related hardware is present, even when no SIM is inserted or even when no SIM slot exists (some OEM's have done this).Since Gingerbread (Android 2.3)
android.os.Build.SERIAL
must exist on any device that doesn't provide IMEI, i.e., doesn't have the aforementioned hardware present, as per Android policy.Due to fact (2.), at least one of these two unique identifiers will ALWAYS be present, and SERIAL can be present at the same time that IMEI is.
Note: Fact (1.) and (2.) are based on Google statements
SOLUTION
With the facts above, one can always have a unique identifier by checking if there is IMEI-bound hardware, and fall back to SERIAL when it isn't, as one cannot check if the existing SERIAL is valid. The following static class presents 2 methods for checking such presence and using either IMEI or SERIAL:
I would advice on using
getCleartextID_HARDCHECK
. If the reflection doesn't stick in your environment, use thegetCleartextID_SIMCHECK
method instead, but take in consideration it should be adapted to your specific SIM-presence needs.P.S.: Do please note that OEM's have managed to bug out SERIAL against Google policy (multiple devices with same SERIAL), and Google as stated there is at least one known case in a big OEM (not disclosed and I don't know which brand it is either, I'm guessing Samsung).
Disclaimer: This answers the original question of getting a unique device ID, but the OP introduced ambiguity by stating he needs a unique ID for an APP. Even if for such scenarios Android_ID would be better, it WILL NOT WORK after, say, a Titanium Backup of an app through 2 different ROM installs (can even be the same ROM). My solution maintains persistence that is independent of a flash or factory reset, and will only fail when IMEI or SERIAL tampering occurs through hacks/hardware mods.
上述所有方法都存在问题。在 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 现在将在各个安装中保持不变,即使用户切换设备也是如此。
有关此方法的更多信息,请参阅此处 Reto 的演讲 http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html
有关如何实现备份代理的完整详细信息,请参阅此处的开发人员网站:http: //developer.android.com/guide/topics/data/backup.html
我特别推荐底部有关测试的部分,因为备份不会立即发生,因此要测试您必须强制备份。
There are problems with all the above approaches. 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.
This approach will give you an anonymous, secure user ID which will be persistent for the user across different devices (including tablets, based on primary Google account) and across installs on the same device. 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.
Lets 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 this link: 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 switches devices.
For more information on this approach see Reto's talk here http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html
And for full details of how to implement the backup agent see the developer site here: http://developer.android.com/guide/topics/data/backup.html
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.
另一种方法是在没有任何权限的应用程序中使用 /sys/class/android_usb/android0/iSerial 。
要在 java 中执行此操作,只需使用 FileInputStream 打开 iSerial 文件并读出字符。请确保将其包装在异常处理程序中,因为并非所有设备都有此文件。
至少已知以下设备具有此文件:
您还可以在此处查看我的博客文章: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial -number.html 我在其中讨论了哪些其他文件可供参考。
Another way is to use /sys/class/android_usb/android0/iSerial in an App with no 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 here: http://insitusec.blogspot.com/2013/01/leaking-android-hardware-serial-number.html where I discuss what other files are available for info.
正如@haserman所说:
但有必要在清单文件中包含权限:
As @haserman says:
But it's necessary including the permission in the manifest file:
Android 操作系统设备的唯一设备 ID(字符串形式)。
但我强烈推荐 Google 建议的这种方法::
识别应用程序安装< /a>
Unique device ID of Android OS Device as String.
but I strngly recommend this method suggested by Google::
Identifying App Installations
Build.SERIAL
是最简单的方法,尽管并不完全可靠,因为它可以为空或者有时返回不同的值(证明 1,证明 2)比您在设备设置中看到的要好。根据设备制造商和 Android 版本,有多种方法可以获取该数字,因此我决定编译在一个 要点。这是它的简化版本:
Build.SERIAL
is the simplest way to go, although not entirely reliable as it can be empty or sometimes return a different value (proof 1, proof 2) than what you can see in your device's settings.There are several ways to get that number depending on the device's manufacturer and Android version, so I decided to compile every possible solution I could found in a single gist. Here's a simplified version of it :
我知道这个问题很旧,但可以用一行代码来完成
String deviceID = Build.SERIAL;
I know this question is old but it can be done in one line of code
String deviceID = Build.SERIAL;
适用于 API 29 和 30,已在 Samsung Galaxy s7 s9 Xcover 上测试
Works on API 29 and 30, tested on Samsung galaxy s7 s9 Xcover
我发现上面 @emmby 发布的示例类是一个很好的起点。但正如其他海报所提到的,它有一些缺陷。主要的一个问题是它不必要地将 UUID 保存到 XML 文件中,然后总是从该文件中检索它。这使得该类容易被黑客攻击:任何拥有 root 权限的手机都可以编辑 XML 文件,为自己提供一个新的 UUID。
我更新了代码,以便仅在绝对必要时(即使用随机生成的 UUID 时)保留为 XML,并根据 @Brill Pappin 的答案重构逻辑:
I found the example class posted by @emmby above to be a great starting point. But it has a couple of flaws, as mentioned by other posters. The major one is that it persists the UUID to an XML file unnecessarily and thereafter always retrieves it from this file. This lays the class open to an easy hack: anyone with a rooted phone can edit the XML file to give themselves a new UUID.
I've updated the code so that it only persists to XML if absolutely necessary (i.e. when using a randomly generated UUID) and re-factored the logic as per @Brill Pappin's answer:
是的。它是设备硬件序列号,并且是唯一的。因此,在 api 级别 2.3 及更高版本上,您可以使用 android.os.Build.ANDROID_ID 来获取它。对于低于 2.3 的 API 级别,请使用 TelephonyManager.getDeviceID()。
你可以阅读这个 http://android-developers.blogspot.in /2011/03/identifying-app-installations.html
Yes. It is a device hardware serial number and it is unique. So on api level 2.3 and above you can use android.os.Build.ANDROID_ID to get it. For below 2.3 API level use TelephonyManager.getDeviceID().
you can read this http://android-developers.blogspot.in/2011/03/identifying-app-installations.html