IMEI 、UDID、IDFA 、IDFV 、UUID
参考:
总结
目前最佳获取设备的唯一标识方案:UUID+keychain
IMEI
苹果已经不允许APP获取IMEI,在:设置-通用-关于本机中可以查看到IMEI。
UDID
IDFA和IDFV
- IDFA:广告标识符
- IDFV:APP 提供商 标识符
IDFA和IDFV都可以通过系统API获取到一个NSUUID对象,二者都是6.0开始使用。
IDFA
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
广告标识符,对于一个设备来说,是唯一的。一般情况下,不同的APP提供商获取到该值是唯一的。可能使之改变的情况如下:
- 1、用户手动重置(设置-通用-还原-还原位置与隐私)
- 2、用户重置系统
- 3、设置 - 隐私 - 广告 - 限制广告跟踪
官方文档
An alphanumeric string unique to each device, used only for serving advertisements.
Unlike the identifierForVendor property of the UIDevice, the same value is returned to all vendors. This identifier may change—for example, if the user erases the device—so you should not cache it.每个设备唯一的字母数字字符串,仅用于提供广告。
与UIDevice的identifierForVendor属性不同,相同的值返回给所有供应商。这个标识符可能会改变——例如,如果用户擦除设备——所以您不应该缓存它。
In iOS 10.0 and later, the value of advertisingIdentifier is all zeroes when the user has limited ad tracking.
If the value is nil, wait and get the value again later. This happens, for example, after the device has been restarted but before the user has unlocked the device.
在iOS 10.0及以后版本中,当用户限制广告跟踪时,advertisingIdentifier的值都是0。如果值为nil,则等待并稍后再次获取该值。例如,这发生在设备重启之后,但在用户解锁设备之前。
从官方文档可得出:
- 同个供应商,同一个设备,值相同。
- 用户限制广告跟踪,iOS10以上,返回的值都为0,如:00000000-0000-0000-0000-000000000000
- 用户重新关闭限制广告跟踪,值会改变。
对于IDFA的使用,在提审的时候,也要注意相关选项的勾选:
imageIDFV
NSUUID *idfv = [UIDevice currentDevice].identifierForVendor;
NSLog(@"%@",idfv);
The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.
对于来自运行在相同设备上的相同供应商的应用程序,此属性的值是相同的。对于来自不同厂商的同一设备上的应用程序,以及对于来自不同厂商的不同设备上的应用程序,将返回不同的值。
If the value is nil, wait and get the value again later. This happens, for example, after the device has been restarted but before the user has unlocked the device.
如果值为nil,则等待并稍后再次获取该值。例如,这发生在设备重启之后,但在用户解锁设备之前。
The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. The value can also change when installing test builds using Xcode or when installing an app on a device using ad-hoc distribution. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes.
当用户从设备上删除该供应商的所有应用程序并随后重新安装其中一个或多个应用程序时,该值将发生变化。在使用Xcode安装测试构建时,或者在使用特别发行版在设备上安装应用程序时,该值也可以更改。因此,如果您的应用程序在任何地方存储此属性的值,那么您应该优雅地处理标识符更改的情况。
从官方文档可以获得如下的要点:
- 来自同一个提供商的APP运行在同一个设备上,不同APP获取该值相同。
- 来自不同的提供商的不同APP,不管是不是同一个设备上,该值都不同。
- 同一个设备上,删除了该提供商的所有APP,再次安装该提供商的其中一个或者多个APP,值会改变。
- 如果获取到该值为nil,等待并稍后再获取该值。这种情况发生在用户重启设备并解锁之前。
- 如果用户使用xcode或者ad-hoc企业证书分发的安装的情况,值也可能改变,因此,应该优雅的缓存该值。(如何缓存?keychain)
供应商区分
为什么主要是由于提供商的来区分呢?因为这个值就是根据提供商的不用来生成的(包名 bundle identifier)。
如何区分是否是同一个提供商?其实就是看包名。
包名的格式一般都是这样的:
com.example.app1
com.example.app2
com.example.app.app1
com.example.app.app2
从系统版本上来看,取决于不同部分
- iOS6上:取前两部分:com.example
- iOS7以上:除了最后那部分的其他部分:com.example、com.example.app
用表格来表示如下:
Bundle ID | iOS 6.x | iOS 7.x |
---|---|---|
com.example.app1 | com.example | com.example |
com.example.app2 | com.example | com.example |
com.example.app.app1 | com.example | com.example.app |
com.example.app.app2 | com.example | com.example.app |
因此,com.example.app1和com.example.app2也就属于同一个提供商了。
既然获取该值可能会为nil,切会改变。因为我们可以生产一个,并且用keychain保存起来。这样对于用一个APP提供商,同一个设备,无论用户删除APP与否,都可以获取到同一个值,相当于设备的唯一标识(IMEI)了。
以上的值,IMEI,UDID无法获取
IDFA根据值会因为用户的设置而获取不到,用户重置手机会改变。
IDFV用户充值手机会改变。且IDFA,IDFV都跟bundle identifier(包名)有关,不能对每个包都获得不同值,因此不合适。
生成UUID
//生成UUID
- (NSString *)uuidString{
CFUUIDRef uuid_ref = CFUUIDCreate(NULL);
CFStringRef uuid_string_ref= CFUUIDCreateString(NULL, uuid_ref);
NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuid_string_ref];
CFRelease(uuid_ref);
CFRelease(uuid_string_ref);
return [uuid lowercaseString];
}
通过测试,用这种方式每次生成的值都不一样。只能保存到keychain,每次获取,先去keychain获取,如果有则取出,没有则插入一个新的。即使用户删除该APP,UUID还是会保存在keychain,保证了UUID的唯一性。
至于如何使用keychain。。。等我研究后再写。现在用的是一个关于keychain框架,可以很方便的操作keychain。
也可以使用SSKeychain
以及别人使用来保存UUID的方式: