iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备的序列号,这个也是目前为止唯一可以确认唯一的标识符。但是,因为该唯一标识符与手机一一对应,苹果觉得可能会泄露用户隐私,所以在iOS 5.o之后该方法就被废弃掉了。
iOS 6.0系统新增了两个用于替换uniqueIdentifier的接口,分别是:Vendor标识符(IDFV-identifierForVendor)和广告标识符(IDFA-identifierForIdentifier)。至于该两个不能作为唯一标识符,请查看后面介绍;
iOS 7中又一次无情的封杀mac地址,使用之前的方法获取的mac地址全部否变成了02:00:00:00:00:00。解决方案:如果你需要识别设备的唯一性,请使用UIDevice的identifierForVendor属性(因广告的而需要设别设备的应用,请考虑使用ASIdentifierManager的advertisingIdentifier属性作为替代),然后使用KeyChain来保存获取到的唯一标识符,即时APP删除之后在安装,也可以从KeyChain中读取。
实例方法:
//获取UDID
NSString* uniqueIdentifier = [[UIDevice currentDevice] uniqueIdentifier];
它使苹果iOS设备的唯一识别码,它是由40个字符的字母和数组组成(越狱的设备通过某些工具可以改变设备的UDID)。移动网络可利用UDID来识别移动设备,但是,从iOS 5.0(2011年8月份)开始,苹果宣布将不再支持使用uniqueIdentifer方法获取设备的UDID,iOS 5以下是可以使用的。在2013你啊你3月21日苹果已经通知开发者:从2013年5月1日起,访问UIDIDs的程序将不再被审核通过,替代的佛纳甘是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标识符”。所以UDID是绝对不能用了。
实例方法:
8825482C-3BCC-440B-8D7A-A6A43C713CB9
- (NSString*) uuid { CFUUIDRef puuid = CFUUIDCreate( nil ); CFStringRef uuidString = CFUUIDCreateString( nil, puuid ); NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString)); CFRelease(puuid); CFRelease(uuidString); return result; }
它是让分布式系统中的所有元素,都能有唯一的辨识咨询,而不需要透过中央控制端赖做辨识咨询的指定。这样,每个人都可以建立不予其他人冲突的UDID。在此情况下,就不需要考虑数据库建立时的名称重复问题。苹果公司建议使用UUID为应用生成唯一标识字符串。开发者可以在应用第一次启动调用一次,然后将该串存储起来,以便以后替代UDID来使用。但是,如果用户删除该应用再次安装时,又会生成新的字符串,所以不能保证唯一识别该设备。
MAC地址,用来表示互联网上每一个标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符”(Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。MAC地址在网络上用来区分设备的唯一性,接入网络的设备都有一个MAC地址,他们肯定是不同的,是唯一的。一部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一个WIFI的,因此只需要获取WIFI的MAC地址就好了,也就是en0地址。
形象的说,MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。这样就可以非常好的标志设备唯一性,类似与苹果设备的UDID号,通常的用途有:
如何使用MAC地址生成设备的唯一标识,主要分三种:
iOS 之前,因为Mac地址是唯一的,一般app开发者会采取第3种方式来直接安装对应app的设备。但是MAC地址跟UDID一样,存在隐私问题,现在苹果新发布的iOS7上,如果请求MAC地址都会返回一个固定值,那么MAC Address+bundle_id这个值大家的设备都变成一致。所以在iOS 7以后系统中会废弃。
实例代码:
NSString *openUDID = [OpenUDID value];
OPEN UDID,没有用到MAC地址,同时能保证同一台设备上的不同应用私用同一个OpenIDOD,只要用户设备上有一个使用了OpenUDID的应用存在时,其他后续安装的应用如果获取OpenUDID,都会获得第一个应用生成的那个。但是如果把使用了OpenUDID方案的应用全部都删除,再重新获取OpenUDID,此时的OpenUDID就跟以前的不一样。
①、优点:
a、没有用到MAC地址。MAC地址跟UDID一样,存在隐私问题,不能保证以后不会禁用MAC地址;
b、不同设备能够获取各自唯一的识别码,保证了唯一性,可以用于以往UDID的相关用途;
c、从代码分析OpenUDID的获取,识别码获取方便并且保存谨慎。当设备上第一个使用OpenUDID方案的应用程序第一次调试时,会生成一个唯一的识别码,追加8位随机数保持了40位UDID,并且李永乐NSUserDefaults类将识别码进行了保存。但是当应用删除,NSUserDefaults同样会被清空,为了避免重新生成唯一识别码,该方案还用到了UIPasteboard类(设备剪切板),将识别码同时保存到了UIPesteboard。
d、当设备上安装第二个使用了OpenUDID方案的应用程序,将会从UIPeateboard中获取唯一识别码,这里取到的就是之前第一个应用保存到UIPasteboard中的。(前提:设备上有一个使用了OpenUDID的应用存在);
②、缺点:
a、当将设备上所有使用OpenUDID方案的应用程序删除,且设备关机重启,xcode彻底清除并重启,重装应用程序去获取OpenUDID,此时OpenUDID变化,与之前的不一样了,从测试结果可看出;
b、缺点1分析,所有OpenUDID应用卸载后,由UIPasteboard保存的数据即被清除,重装故会重新获取新的OpenUDID;
c、当因为用户干预或者恶意程序,致使IOPasteboard数据清除,从而导致OpenUDID被删除,重装也会获取新的OpenUDID。
实例代码:
3A29445-794D-4D24-A0B4-ABDDF79D44EE
获取广告标示符:NSLog(@”%@”,[[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]);
广告标示符,是iOS 6中另外一个新的方法,提供了一个方法advertisingIdentifier,通过调用该方法会返回一个NSUUID实例,最后可以获得一个UUID,由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序→通用→还原→还原位置与隐私),这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序→通用→关于本机→广告→还原广告标示符)),那么广告标示符也会重新生成。关于广告标识符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”然后再回到程序中,此时获取广告标识符并不会立即获得还原后的标识符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标识符。
实例代码:
<__NSConcreteUUID 0x7fab28f16850> 1C5DB393-C32A-4000-99F2-710E36AB4A82
NSLog(@"%@",[[UIDevice currentDevice] identifierForVendor]);
Vendor标示符,也是iOS6中新增的,跟advertisingIdentifier一样,该方法返回的是一个NSUUID对象,可以获得一个UUID。如果满足条件“相同一个程序里面-相同”的vendor-相同的设备“,那么获取到的这个属性值就不会变。如果是”相同的程序-相同的设备-不同的vendor,或者是相同的程序-不同的设备-无论是否相同的vendpor“这样的情况,那么着个值是不会相同的。
推送token+bundle_id的方法:
apple push token保证设备唯一,但必须有网络情况下才能工作,该方法不依赖于设备本身,但依赖于apple push,而苹果push有时候会抽风的。
UUID一般只生成一次,保存在iOS系统里面,如果应用删除了,重装应用之后它的UUID还是一样的,除非系统重置。但是不能保证在以后的系统升级后还能使用(如果系统保存了该信息就能用)。
开发者们知道KeyChain,他是保存证书的,以及我们平时浏览网页记录的账目密码。iOS中的KeyChain相比OS X比较简单,整个系统只有一个KeyChain,每个程序都可以往KeyChain中记录数据,而且只能读取到自己程序记录在KeyChain中的数据。iOS中Security.framework框架提供了四个主要的方法来操作KeyChain:
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result)
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result)
OSStatus SecItemUpdate(CFDictionaryRef query,
CFDictionaryRef attributesToUpdate)
OSStatus SecItemDelete(CFDictionaryRef query)
注:苹果提供了一个方法允许同一个发商的多个APP访问各APP之间的途径,即在调SecItemAdd添加数据的时候指定AccessGroup,即访问组。一个APP可以属于过个分组,添加KeyChain数据访问组需要做以下两件事情:
+ (NSString *)getUUID{
//此处的accessGroup中的格式为“AppIdentifier.com.***”,其中APPIdentifier就是你的开发者账号对应的ID。
//此处应该和plist文件中的相对应
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"UUID" accessGroup:@"YOUR_BUNDLE_SEED.com.yourcompany.userinfo"];
NSString *strUUID = [keychainItem objectForKey:(id)CFBridgingRelease(kSecValueData)];
//首次执行该方法时,uuid为空
if ([strUUID isEqualToString:@""]){
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
strUUID = (NSString *)CFBridgingRelease(CFUUIDCreateString (kCFAllocatorDefault,uuidRef));
[keychainItem setObject:strUUID forKey:(id)CFBridgingRelease(kSecValueData)];
}
return strUUID;
}
测试代码:
NSString * uuid= [UUID getUUID];
NSLog(@"uuid=%@",uuid);
测试结果:
uuid=19AAB430-9CB8-4325-ACC5-D7D386B68960