获取UUID并保存到钥匙串

前言:

1 .为了统计和检测应用的使用数据,几乎每家公司都有获取唯一标识的业务需求,在iOS5以前获取唯一标识,可以获取到系统提供的方法UDID(Unique Device Identifier),后来被出于用户隐私的考虑被Apple官方禁止掉了。于是,大家开始在iOS6中使用 MAC 地址(Medium/Media Access Control) ,后来又被Apple官方在iOS7中禁止掉了。苹果及其国外的IT公司都会比较注重用户隐私,所以今后一但有比较靠谱的获取唯一标示的方法放出,苹果肯定会封堵。

2.**  ** 在非越狱的手机上获取某个硬件信息生成唯一标识,第一只能找到苹果的漏洞,第二就是调用一些私有接口,显然这两条路都比较艰难,并不可持续发展,所以网上大部分的唯一标识都是从操作系统层面获取的,在重置手机系统的时候都会被清除,在系统升级、卸载重装、备份恢复都可以保留,现在本人尚未发现可以使用严格意义上的唯一标识。接下来我想跟大家探讨的是如何通过“合法”的手段来尽量拿到不会轻易发生变化的“唯一标识”。

3.**  **在2013年3月21日苹果已经通知开发者,从2013年5月1日起,访问UIDID的应用将不再能通过审核,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标示符”。

4.MAC地址不能再用来设别设备

**  **还有一个生成iOS设备唯一标示符的方法是使用iOS设备的Media Access Control(MAC)地址。一个MAC地址是一个唯一的号码,它是物理网络层级方面分配给网络适配器的。这个地址苹果还有其他的名字,比如说是硬件地址(Hardware Address)或是Wifi地址,都是指同样的东西。

有很多工程和框架都使用这个方法来生成唯一的设备ID。比如说ODIN。然而,苹果并不希望有人通过MAC地址来分辨用户,所以如果你在iOS7系统上查询MAC地址,它现在只会返回02:00:00:00:00:00。

5 **  ** 讲真苹果这傲娇的小脾气什么时候能能改改,不过这样 对于用户隐私的保护,确实起到很大作用,而且苹果也没有把路堵死,现在苹果明确的表明你应该使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]来作为你框架和应用的唯一标示符。坦白的来说,应对这些变化也不是那么的难,见以下代码片段:

NSString*identifierForVendor=[[UIDevice currentDevice].identifierForVendor UUIDString];NSString*identifierForAdvertising=[[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];

但是这样用法有个缺点,就是程序每次被删除以后,获取到的都是新的uuid,并不能实现每个手机的唯一性.

所以下面要讲的就是这个问题的解决办法.

**  **对于这个问题有一个可行的办法,就是把获取到的uuid保存在钥匙串里面,这样即使程序删除重装,获取到的uuid一直是同一个,实现了手机的唯一标识的作用.

保存钥匙串 我们需要用到keychain,除此之外,Code Signing Entitlements的创建方法也不够严谨。下面教大家一种方法,简单快速.

1.新建一个工程,看一下自己的Bundle Id.这个Bundle Id 要和你用真机测试时的证书上面的Bundle Id相匹配。

注意这个Bundle identifier

2.Target - Capabilities - Keychain Sharing - ON

注意圆圈里面的保持一致

这步主要目的是打开Keychain Sharing,将它由灰色状态的OFF改为蓝色状态的ON。

会自动生成这个

左侧的目录会自动生成Entitlements文件,不需要自己创建了。

也就是说,Bundle Identifier、Keychain Sharing的Keychain Groups、Entitlements文件的Keychain Access Groups的第一个元素,它们要保持上图所示的一致性。

设置好了以后可以运行下程序,没问题可以进行下一步。

.传说中的uuid类和keychain类来啦

既然苹果的keychain方法会崩溃而且有些复杂,我们只保存一个uuid的话可以用下面的简单方法:

KeyChainStore.h#import@interfaceKeyChainStore:NSObject+(void)save:(NSString*)service data:(id)data;+(id)load:(NSString*)service;+(void)deleteKeyData:(NSString*)service;@end

KeyChainStore.m////  KeyChainStore.m//  getUUID////  Created by ckl@pmm on 16/9/18.//  Copyright © 2016年 CKLPronetway. All rights reserved.//#import"KeyChainStore.h"@implementationKeyChainStore+(NSMutableDictionary*)getKeychainQuery:(NSString*)service{return[NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword,(id)kSecClass,service,(id)kSecAttrService,service,(id)kSecAttrAccount,(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,nil];}+(void)save:(NSString*)service data:(id)data{//Get search dictionaryNSMutableDictionary*keychainQuery=[selfgetKeychainQuery:service];//Delete old item before add new itemSecItemDelete((CFDictionaryRef)keychainQuery);//Add new object to search dictionary(Attention:the data format)[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data]forKey:(id)kSecValueData];//Add item to keychain with the search dictionarySecItemAdd((CFDictionaryRef)keychainQuery,NULL);}+(id)load:(NSString*)service{id ret=nil;NSMutableDictionary*keychainQuery=[selfgetKeychainQuery:service];//Configure the search setting//Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue[keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];[keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];CFDataRef keyData=NULL;if(SecItemCopyMatching((CFDictionaryRef)keychainQuery,(CFTypeRef*)&keyData)==noErr){@try{ret=[NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData*)keyData];}@catch(NSException*e){NSLog(@"Unarchive of %@ failed: %@",service,e);}@finally{}}if(keyData)CFRelease(keyData);returnret;}+(void)deleteKeyData:(NSString*)service{NSMutableDictionary*keychainQuery=[selfgetKeychainQuery:service];SecItemDelete((CFDictionaryRef)keychainQuery);}@end

getUUID.h#import@interfacegetUUID:NSObject+(NSString*)getUUID;@end

getUUID.m////  getUUID.m//  getUUID////  Created by ckl@pmm on 16/9/18.//  Copyright © 2016年 CKLPronetway. All rights reserved.//#import"getUUID.h"#import"KeyChainStore.h"#defineKEY_USERNAME_PASSWORD @"com.company.app.usernamepassword"#defineKEY_USERNAME @"com.company.app.username"#defineKEY_PASSWORD @"com.company.app.password"@implementationgetUUID+(NSString*)getUUID{NSString*strUUID=(NSString*)[KeyChainStore load:@"com.company.app.usernamepassword"];//首次执行该方法时,uuid为空if([strUUID isEqualToString:@""]||!strUUID){//生成一个uuid的方法CFUUIDRef uuidRef=CFUUIDCreate(kCFAllocatorDefault);strUUID=(NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault,uuidRef));//将该uuid保存到keychain[KeyChainStore save:KEY_USERNAME_PASSWORD data:strUUID];}returnstrUUID;}@end

在Viewcontroller里面执行如下代码

#import"ViewController.h"#import"getUUID.h"@interfaceViewController()@end@implementationViewController-(void)viewDidLoad{[superviewDidLoad];NSLog(@" uuid  is  ---> %@",[getUUID getUUID]);// Do any additional setup after loading the view, typically from a nib.}

打印出来类似于以下的长串字符:

获取到的uuid.png

把程序卸载掉然后重新运行一次,获取到的还是上次保存的uuid.

不知道手机越狱以后,会不会改变,因为楼主手机版本是最新的9.3.5,身边还没相关越狱设备,希望大家可以自行测试一下.并告知楼主.联系方式 : QQ :576484150

参考地址:

:http://blog.sina.com.cn/s/blog_5971cdd00102vqgy.html

:http://blog.csdn.net/chy555chy/article/details/51628079

:https://www.jianshu.com/p/29572b756d26

写了一个demo,已经放在gitHub上了,有兴趣的同学可以下载下来瞅瞅.

demo 地址 :https://github.com/chengkunlun/getUUID

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容