对于对Sofien的解决方案感兴趣的Java用户,我已经:
- 将Sofien的代码转换为Java并进行了进一步的简化;
- 在Android 10(API 29)、Android 11(API 30)和之前的版本上进行了广泛的测试。
1. 代码和讨论
@Nullable
String getUniqueID() {
UUID wideVineUuid = new UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L);
try {
MediaDrm wvDrm = new MediaDrm(wideVineUuid);
byte[] wideVineId = wvDrm.getPropertyByteArray(MediaDrm.PROPERTY_DEVICE_UNIQUE_ID);
return Arrays.toString(wideVineId);
} catch (Exception e) {
return null;
}
}
就Sofien的代码而言,我做了两个主要的改变。
- 我没有使用
MessageDigest
,这使得代码更简单。此外,MessageDigest.update()
方法将SHA-256
哈希函数应用于其参数,这会极低概率地导致UUID丢失唯一性。不对UUID进行哈希的唯一缺点是您没有固定长度的UUID,在我的应用程序中我不关心这一点。 - 我使用
Arrays.toString
代替Kotlin函数toHexString
(Java中没有单行等价物)。这个选择是安全的,因为(A)它不抛出Exception
并且(B)它保留wideVineId
和String
表示之间的一对一对应关系。如果您喜欢坚持十六进制转换,则Apache Commons Codec库提供了一行解决方案。
当然,这些更改将导致不同的UUID,其他选择也是可能的。注意,使用Arrays.toString
生成的UUID采用以下格式。
[92, -72, 76, -100, 26, -86, 121, -57, 81, -83, -81, -26, -26, 3, -49, 97, -24, -86, 17, -106, 25, 102, 55, 37, 47, -5, 33, -78, 34, 121, -58, 109]
如果您不想在UUID中包含特殊字符,可以使用 String.replaceAll()
函数将其移除。
2. 测试
我已经测试了UUID的持久性
测试设备/操作系统组合如下:
- Google Pixel 4A / API 30
- Samsung Galaxy S10 / API 29
- Samsung Galaxy S9 / API 29
- Huawei Nexus 6P / API 27(也测试了出厂设置)
- LG V20 / API 27(也测试了出厂设置)
- Asus ZenFone 2 / API 23
- Samsung Galaxy J5 / API 23
- LG Nexus 5 / API 23
- LG K4 / API 22
- Samsung Galaxy J3 / API 22
- Samsung Galaxy S4 / API 21
在所有的测试中,targetSdkVersion
都是30。欢迎进行更多测试(尤其是在API 29和30上的测试)。