获取唯一标识符

一、iOS不同版本获取唯一标识符的方法比较

1、iOS 5:UDID(Unique Device Identifier)

iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备的序列号,这个也是目前为止唯一可以确认唯一的标识符。但是,因为该唯一标识符与手机一一对应,苹果觉得可能会泄露用户隐私,所以在iOS 5.o之后该方法就被废弃掉了。

2、iOS 6:MAC(Medium/Media Access Control)地址

iOS 6.0系统新增了两个用于替换uniqueIdentifier的接口,分别是:Vendor标识符(IDFV-identifierForVendor)和广告标识符(IDFA-identifierForIdentifier)。至于该两个不能作为唯一标识符,请查看后面介绍;

3、iOS 7:KeyChain(钥匙串)

iOS 7中又一次无情的封杀mac地址,使用之前的方法获取的mac地址全部否变成了02:00:00:00:00:00。解决方案:如果你需要识别设备的唯一性,请使用UIDevice的identifierForVendor属性(因广告的而需要设别设备的应用,请考虑使用ASIdentifierManager的advertisingIdentifier属性作为替代),然后使用KeyChain来保存获取到的唯一标识符,即时APP删除之后在安装,也可以从KeyChain中读取。

二、不同阶段中出现的不同标识符

1、UDID(Unique Device Identifier)

实例方法:

//获取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是绝对不能用了。

2、UUID(Universally Unique Identifier)

实例方法:

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来使用。但是,如果用户删除该应用再次安装时,又会生成新的字符串,所以不能保证唯一识别该设备。

3、MAC(Medium/Media Access Control) Address

MAC地址,用来表示互联网上每一个标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符”(Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。MAC地址在网络上用来区分设备的唯一性,接入网络的设备都有一个MAC地址,他们肯定是不同的,是唯一的。一部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一个WIFI的,因此只需要获取WIFI的MAC地址就好了,也就是en0地址。

形象的说,MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。这样就可以非常好的标志设备唯一性,类似与苹果设备的UDID号,通常的用途有:

  • ①、用于一些统计与分析目的,利用用户的操作习惯和数据更好的规划产品;
  • ②、作为用户ID来唯一识别用户,可以用游客身份使用app又能再服务器端保存相应的信息,省去用户名、密码等注册过程。

如何使用MAC地址生成设备的唯一标识,主要分三种:

  • ①、直接使用”MAC Address”;
  • ②、使用“MD5(MAC Address)”;
  • ③、使用“MD5(Mac Address+bundie_id)”获得“机器+应用”的唯一标识(bound_id是应用的唯一标识);

iOS 之前,因为Mac地址是唯一的,一般app开发者会采取第3种方式来直接安装对应app的设备。但是MAC地址跟UDID一样,存在隐私问题,现在苹果新发布的iOS7上,如果请求MAC地址都会返回一个固定值,那么MAC Address+bundle_id这个值大家的设备都变成一致。所以在iOS 7以后系统中会废弃。

4、OPEN UDID

  1. 下载第三方OpenUDID库;
  2. 加入头文件: #include “OpenUDID.h”

实例代码:

 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。

5、广告标示符(IDFA-identifierForIdentifier)

实例代码:

3A29445-794D-4D24-A0B4-ABDDF79D44EE
  1. 添加框架:AdSupport.framework
  2. 添加头文件: #import < AdSupport/ASIdentifierManager.h >
  3. 获取广告标示符:NSLog(@”%@”,[[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]);

    广告标示符,是iOS 6中另外一个新的方法,提供了一个方法advertisingIdentifier,通过调用该方法会返回一个NSUUID实例,最后可以获得一个UUID,由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序→通用→还原→还原位置与隐私),这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序→通用→关于本机→广告→还原广告标示符)),那么广告标示符也会重新生成。关于广告标识符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”然后再回到程序中,此时获取广告标识符并不会立即获得还原后的标识符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标识符。
    

6、Vendor标示符(IDFV-identifierForVendor)

实例代码:

<__NSConcreteUUID 0x7fab28f16850> 1C5DB393-C32A-4000-99F2-710E36AB4A82
NSLog(@"%@",[[UIDevice currentDevice] identifierForVendor]);
 Vendor标示符,也是iOS6中新增的,跟advertisingIdentifier一样,该方法返回的是一个NSUUID对象,可以获得一个UUID。如果满足条件“相同一个程序里面-相同”的vendor-相同的设备“,那么获取到的这个属性值就不会变。如果是”相同的程序-相同的设备-不同的vendor,或者是相同的程序-不同的设备-无论是否相同的vendpor“这样的情况,那么着个值是不会相同的。

7、推送token+bundle_id

推送token+bundle_id的方法:

  1. 应用中增加推送用来获取token;
  2. 获取应用bundle_id;
  3. 根据token+bundle_id进行散列运算;

apple push token保证设备唯一,但必须有网络情况下才能工作,该方法不依赖于设备本身,但依赖于apple push,而苹果push有时候会抽风的。

三、解决方案

UUID一般只生成一次,保存在iOS系统里面,如果应用删除了,重装应用之后它的UUID还是一样的,除非系统重置。但是不能保证在以后的系统升级后还能使用(如果系统保存了该信息就能用)。
开发者们知道KeyChain,他是保存证书的,以及我们平时浏览网页记录的账目密码。iOS中的KeyChain相比OS X比较简单,整个系统只有一个KeyChain,每个程序都可以往KeyChain中记录数据,而且只能读取到自己程序记录在KeyChain中的数据。iOS中Security.framework框架提供了四个主要的方法来操作KeyChain:

1、查询:

OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result)

2、添加:

OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result)

3、更新KeyChain中的Item:

OSStatus SecItemUpdate(CFDictionaryRef query,
    CFDictionaryRef attributesToUpdate)

4、删除KeyChain中的Item:

OSStatus SecItemDelete(CFDictionaryRef query)

注:苹果提供了一个方法允许同一个发商的多个APP访问各APP之间的途径,即在调SecItemAdd添加数据的时候指定AccessGroup,即访问组。一个APP可以属于过个分组,添加KeyChain数据访问组需要做以下两件事情:

  • a、在APP target的Build Setting里面设置Code Signing Entitlements,指向包含AccessGroup的分组信息的plist文件。该文件必须和工程文件在同一个目录下。例如:在Target-Build Setting-Code Signing栏下的Code Signing Entitlements右侧添加KeychainAccessGroups.plist,如下图:
    这里写图片描述
  • b、在工程目录下新建一个KeychainAccessGroups.plist文件,该文件的结构中最顶层的节点必须是一个名为“keychain-accedd-groups”的Array,并且该Array中每一项都是一个描述分组的NSString。对于String的格式也有相应要求,格式为“AppIdentifier.com.*”,其中APPIdentifier就是你的开发者账号对应的ID。
  • c、下载官方的KeychainItemWrapper类
    http://developer.apple.com/library/ios/#samplecode/GenericKeychain/Listings/Classes_KeychainItemWrapper_h.html#//apple_ref/doc/uid/DTS40007797-Classes_KeychainItemWrapper_h-DontLinkElementID_9
  • d、添加库文件Security.framework
  • e、代码示例:
+ (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

你可能感兴趣的:(ios,uuid,唯一标识符)