安卓唯一序列号

53

我正在开发一个针对 Android 4.0(API 14)及以上版本的应用程序。

我正在寻找一个设备唯一且永久保存(随设备而亡,在出厂重置后不变)的序列号。

我在网上找到了很多关于 Android 设备唯一标识符的结果,但很少有关于 android.os.Build.SERIAL 号的信息。

到目前为止,我排除了使用 ANDROID_ID,因为它可能会在出厂重置后更改。我也排除了使用 IMEI,因为 Android 设备可能是非电话设备。我无法使用 wifi 或蓝牙 MAC ADDRESS,因为设备可能没有这样的硬件和/或如果硬件未启用,则这些 MAC 地址可能无法读取(根据我在网上找到的信息)。

我认为我可以使用 Android 设备序列号。

它很容易通过 android.os.Build.SERIAL 访问(因为它是在 API 级别 9 中添加的,不需要任何额外的权限)。

我的问题是:

  • 考虑到我的应用程序的目标对象是Android 4.0(API 14)及以上版本,请问是否每个 Android 设备的 android.os.Build.SERIAL 号都是唯一的?

  • 目前,android.os.Build.SERIAL 的文档说明如下:硬件序列号(如果有)。仅限字母数字,不区分大小写。这是不是意味着序列号可能不可用?

  • 还有哪些其他备选方案符合上述条件?


1
http://www.pocketmagic.net/2011/02/android-unique-device-id/#.UW-y06JTDzw 和 https://dev59.com/V3E85IYBdhLWcg3wbS1h#5424756 可能会有所帮助。 - D'yer Mak'er
你最终选择了一个解决方案吗?我现在也面临着类似的困境... - IgorGanapolsky
4个回答

56
考虑到我的应用程序针对Android 4.0(API 14)及以上版本,android设备的android.os.Build.SERIAL号码对于每个设备是否唯一?根据Android开发者博客中这篇有用的article,如果可用,则android.os.Build.SERIAL应该是唯一的。从文章中可以看出:

没有电话功能的设备必须在此处报告唯一的设备ID;某些手机也可能这样做。

考虑到我的应用程序针对Android 4.0(API 14)及以上版本,android设备的android.os.Build.SERIAL号码对于每个设备是否唯一?根据Android开发者博客中这篇有用的文章,如果可用,则android.os.Build.SERIAL应该是唯一的。从文章中可以看出:
"没有电话功能的设备必须在此处报告唯一的设备ID;某些手机也可能这样做。"
这是否意味着序列号可能不可用?
正确,它可能不可用。请注意,他们说“没有电话功能的设备需要......”,因此只有没有“电话功能”的设备(如仅限wifi的平板电脑)需要提供SERIAL号码,尽管某些手机仍然会这样做(例如Nexus 4)。
关于这个主题的文档肯定缺乏,但从措辞上看,只有“没有电话功能”的设备需要提交唯一的ID,而提交一个ID的手机可能不是唯一的。

还有什么其他的替代方案符合上述条件吗?

针对您的情况,我认为最好的选择是首先检查deviceId(IMEI或其他标识),如果deviceId不存在,则回退到使用android.os.Build.SERIAL(因为这可能是平板电脑),如下所示:

public static String getDeviceId(Context context) {
    final String deviceId = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
    if (deviceId != null) {
        return deviceId;
    } else {
        return android.os.Build.SERIAL;
    }
}

请记住,要使用deviceId,您需要获得android.permission.READ_PHONE_STATE的权限。
因此,由于您的应用程序的minSDK为14,您可以安全地使用字段android.os.Build.SERIAL。如果我们假设没有电信的设备确实总是在SERIAL中提供唯一的id,那么我认为这将是一个安全的选择,以始终获取唯一的设备id(当然排除任何错误)。

所以,如果我对于不是手机的设备使用 Build.SERIAL ,而对于手机使用 getDeviceId() ,你认为这样做总是有效且能提供唯一性吗?谢谢。 - LuckyMe
@LuckyMe 如果一切按计划进行,我认为是安全的。但是当然会有错误,例如文章中针对 getDeviceId() 的说明:错误:我们已经看到一些生产手机的实现存在错误,返回垃圾数据,例如零或星号。 这也取决于您的最小API将是什么,因为 Build.SERIAL 仅从API 9及以上版本可用。但如果您的情况类似于OP,则我认为您是安全的。但是您应该检查数据库,以查看是否返回了奇怪的设备标识符。 - Tony Chan
1
我之前一直使用Build.SERIAL,认为它是唯一的标识符,但我们刚从中国的一个制造商那里收到了一批平板电脑/智能手机(API 15),发现多个设备上的序列号相同(但不是全部)。这可能只是一个孤立的制造商,但我建议您不要依赖于序列号的唯一性! - Peconia
1
实际上,大多数手机都提供序列号,即使是低端预付费手机也是如此。您可以使用android.os.Build.SERIAL查询序列号。尽管有些手机仍然没有。 - IgorGanapolsky

11

我个人使用 Secure.ANDROID_IDBuild.SERIAL 来识别手机:

androidId = Settings.Secure.getString(this.getContentResolver(), 
                Settings.Secure.ANDROID_ID) + Build.SERIAL;

它们可能拥有相同的ANDROID_ID,也可能没有SERIAL。但两者同时存在的概率很低。


2
似乎这是一个解决方案。我需要每个设备的静态唯一字符串,以发送到我的服务器API来注册用户。而且这个解决方案不需要任何附加权限。很好! - Trancer
3
问题在于,使用Secure.ANDROID_ID获取的值可能会因用户进行出厂设置而发生更改,这意味着即使是同一台设备,您连接的ID也会发生更改。 - Mickäel A.

5

您总结的情况似乎已经很清楚了。

序列号旨在为每个设备提供唯一标识,但(由于这是Android),当然会有产生异常的错误,例如:https://code.google.com/p/android/issues/detail?id=35193

正如您所指出的,文档表明这是一个硬件序列号,但措辞方式表明您不应该依赖它。不要将其误认为设备的实际序列号,即印在背面或包装盒上的序列号。此外,我认为它被使用得比android_id少得多,因此可能存在未报告的问题。

我看到广泛报道说android_id基于序列号,但我相信这并不正确-最近我观察到,在具有新多用户功能的平板电脑上,每个用户帐户都有自己的android_id,但序列号对两者都是相同的。

据我所知,“另一种选择”不存在:您的列表已经完整了。除非您愿意依赖wifi或蓝牙权限,否则序列号是最接近您要求的东西。


3
你说得对,android_id并不是基于序列号生成的。显然它只是基于随机数生成器。看看他们修复了哪里的代码更改这里,当他们最终修复了很多设备都有相同的android_id的 bug 时。 - Tony Chan
使用 Settings.Secure.ANDROID_ID 怎么样?这难道不比序列号更可靠地唯一吗? - IgorGanapolsky

0
通常我会通过对某些唯一字符串(通常是公司名称)+ IMEI(如果没有IMEI,则使用MAC地址[WiFi,蓝牙等])进行SHA1哈希来获取唯一ID。这样可以得到看起来相同但在设备上往往是唯一的ID(如果MAC地址被更改/伪造则不完美)。

5
注意。根据我听到的,一些设备在关闭Wi-Fi时会返回空值MAC地址,导致同一设备有两个ID。请注意此问题。 - Fernando Fabreti
自Marshmallow起,不再报告MAC地址。您不应使用该值。 - IgorGanapolsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接