首先,就目前掌握的资料来看,该问题没有彻底的解决方案。网络资料很多,主要分为4类。建议采用方案4。
方案一:Android设备标识或设备硬件信息
常用的有:
1)蓝牙/Wifi的Mac地址、IMSI、sim卡序列号;
2)CPU 的名称、核数、频率,Ram大小、Rom大小、屏幕分辨率,CPU的序列号在目前的测试设备中,显示为一串0;
3)device_id、android_id、serialno。
首先,有些在Android低版本(2.1到2.3)不稳定。其次,上面的几类各有缺点:
第1类受用户行为影响较大,比如开关wifi或蓝牙,插拔sim卡;
第2类表征能力差,同一型号手机中,这些特点没有区分度;
第3类是推荐的,但不能抵抗wipe,其中android_id的生成是以serialno为基础的。
方案二:采用UUID跟踪特定安装,不必绑定具体的设备
随机生成UUID,在本地存储。不做赘述。详见:
http://android-developers.blogspot.co.uk/2011/03/identifying-app-installations.html
方案三:Android Backup Service
AndroidBackup Service provides a backup transport for Android's data backup framework,which allows you to copy a user's persistent app data to remote "cloud" storage. 未做深入研究。
详见:
http://developer.android.com/training/cloudsync/backupapi.html
https://developer.android.com/google/play-services/auth.html
方案四:方案1和方案2的结合
这种方法是,以一些特定的信息为基础,生成设备的唯一标识。
首先,算法角度,常用的有UUID、摘要两种。这两种算法都是以特定的数据为基础,生成一个唯一的、固定长度的字符串。这里选择UUID。
其次,计算的基础数据,建议选择divice_id和android_id。原因是,1)这两个标识虽然不能抵抗wipe操作,但受用户的行为影响比较小;2)如果正常获取,都是唯一的;③如果不能正常获取,结果也是固定的,不会频繁变化。
再次,优先级的考虑。从这两个标识的缺点考虑。
1)device_id。
①不能标识非手机设备,例如Pad。
②权限问题,因为用户的反感。
③获取异常,厂商定制系统中存在的bug,致使返回结果为空,或者为一串“0”或“*”。
④对于双卡双待手机,会返回两个device_id。
2)android_id。
①Android2.3以前,系统Bug,导致不同的设备产生相同的结果:9774d56d682e549c。
②有些可能返回null。
③设备差异:对于CDMA设备,与device_id返回相同的值。
综合考虑,device_id不能标识某些pad,以及用户的权限问题,是我们不能接受的,所以优先使用android_id。对于android_id返回为null的情况,再考虑使用device_id。
最后,当android_id和device_id都返回异常的情况,我们可以随机生成一个UUID。
关于android_id的生成机制见参考资料:
http://my.oschina.net/u/996206/blog/215960
主要代码
主要代码如下,详见Demo程序。
private String getUUID(){
UUID uuid;
String androidId = android_id;
try {
if(!"9774d56d682e549c".equals(androidId)) {
//在Android2.3版本之前才会有这个问题。
uuid = UUID.nameUUIDFromBytes(androidId.getBytes("utf8"));
} else {
String deviceId = device_id;
uuid = deviceId != null ?UUID.nameUUIDFromBytes(deviceId.getBytes("utf8")) :UUID.randomUUID();
}
} catch (UnsupportedEncodingExceptione) {
throw new RuntimeException(e);
}
return uuid.toString();
}
测试结果
根据在现有测试机上的测试结果,android_id可以正常获取到,所以生成的UUID都是以此为基础的。
以下是测试结果数据。
手机型号:GT-I9300I
android_id:c3bec6b0ed7cbc20
device_id:359776058450570
andr_uuid:f205bf07-ee2f-3d27-b3ff-c8db52bed45c
dev_uuid:915c5b80-2368-3fa4-85aa-c1316d852be2
UUID:f205bf07-ee2f-3d27-b3ff-c8db52bed45c
手机型号:HONORH30-L01
android_id:4e5d03bca1d55673
device_id:864502020279410
andr_uuid:89101b66-2d8a-3f82-8bc2-cfba09edff7c
dev_uuid:0fc0f0d0-0b82-3476-a674-0e285427c650
UUID:89101b66-2d8a-3f82-8bc2-cfba09edff7c
手机型号:vivoS7i(t)
android_id:b0374e0856f27689
device_id:863880029053270
andr_uuid:1cf7fb3f-f836-3510-9fe2-ee08cd9b1cd2
dev_uuid:34053b22-f29b-3039-a593-23f534a0207c
UUID:1cf7fb3f-f836-3510-9fe2-ee08cd9b1cd2
手机型号:GT-S7572
android_id:c09ff3a16a57e6bc
device_id:358905059907129
andr_uuid:da400450-c131-3399-be5e-facfc0866ceb
dev_uuid:077c827d-96c6-3d4f-b508-283c1cdd6e0f
UUID:da400450-c131-3399-be5e-facfc0866ceb
手机型号:HUAWEIY320-T00
android_id:4d40a1dfa74973c5
device_id:860271022990473
andr_uuid:77fe6e20-5afe-37ec-b916-f11be3b9dbf5
dev_uuid:e6ef768a-9398-33aa-a925-15c7696deef5
UUID:77fe6e20-5afe-37ec-b916-f11be3b9dbf5
手机型号:HTCSensation XE with Beats Audio Z715e
android_id:c5dc41f5caabe5d2
device_id:358313045847881
andr_uuid:e282e4f1-70ed-3d95-af5b-ebdfd2c90a28
dev_uuid:133095a2-0f3e-325b-ada5-b486fb351e0a
UUID:e282e4f1-70ed-3d95-af5b-ebdfd2c90a28
不足之处与改进
就目前的调研结果,对android_id饱受诟病的地方是,wipe之后会变化或者无法得到正常返回。device_id在wipe之后,有说有影响的,有说不变化的。
再考虑到device_id的权限申请问题、不能标识非手机的移动设备等问题,建议只用android_id即可,如果android_id不能正常返回,则随机生成一个。
最后,选择android_id与device_id而非其它的硬件信息的原因已经在方案一中提到。虽然android_id是基于serialno生成,而后者也是一种硬件信息,但这受wipe的影响,并不是不变的。
如果坚持要从硬件角度唯一的标识设备,恐怕还要从wifi与蓝牙mac地址等角度考虑,而这受用户的行为影响较大。比如,注册时同时取得mac与sim卡序列号,根据两者确定一个准则;后续对设备的确定方法,在wifi下采用mac,在2G/3G下根据sim序列号。