其实写这篇博客我是拒绝的,这个问题网上大把大把的解决方案
首先明确一个问题,先把概念搞清楚,UUID UDID都是什么鬼,每当有人把UUID和UDID搞混来说,我强迫症都要犯犯了
UDID
U D I D (Unique Device Identifier),唯一标识符,是iOS设备的一个唯一识别码,每台iOS设备都有一个独一无二的编码,UDID其实也是在设备量产的时候,生成随机的UUID写入到iOS设备硬件或者某一块存储器中,所以变成了固定的完全不会改变的一个标识
UUID
U U I D (Universally Unique Identifier) 通用唯一识别码,UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。每次调用生成uuid的方法都会生成唯一的字符串
这是一个软件建构的标准,也是被开源软件基金会 (Open Software Foundation, OSF) 的组织应用在分布式计算环境 (Distributed Computing Environment, DCE) 领域的一部分
通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字,所以你调用几千W次生成UUID的方法,生成这一堆UUID字符串之间重复的几率几乎为0,UUID这个标准使用最普遍的是微软的全局唯一标识符 GUID(Globals Unique Identifiers)
UUID + Keychain
原来苹果是提供获取UDID的API的[UIDevice uniqueIdentifier] ,因为被人滥用,所以变成了私有API,我们都知道私有API是不能上架Appstore的
再后来随着苹果对程序内获取UDID封杀的越来越严格,私有API已经获取不到存取到系统或者硬件中的UDID了,Mac地址等信息
继而出现了使用钥匙串配合UUID,推送Token等方法变相实现
iOS 提供了生成UUID的API,使用方法,每次调用jk_UUID返回的UUID字符串都是不同的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
+ (NSString *)jk_UUID { if([[[UIDevice currentDevice] systemVersion] floatValue] > 6.0) { return [[NSUUID UUID] UUIDString]; } else { CFUUIDRef uuidRef = CFUUIDCreate(NULL); CFStringRef uuid = CFUUIDCreateString(NULL, uuidRef); CFRelease(uuidRef); return (__bridge_transfer NSString *)uuid; } } |
为了实现像把UUID写入到硬件中的效果(当然我们APP是写入不到硬件的), 那么找到类似的存取到自己APP中,或者系统中是不是可能呢
NSUserdefault
数据存储后可以关闭app后依然存在,只有卸载App 或者手动删除, 数据才会消失
由于NSUserdefault和APP安装到卸载的生命周期相同,所以重新卸载安装获取UUID,会是新生成的随机UUID
存到APP中最简单的就是NSUserdefault了
直接调用jk_uuid生成一个UUID "24f4b977-4c4a-4e67-84c6-01a473a33fc7" 存入
1 2 3 |
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject:@"24f4b977-4c4a-4e67-84c6-01a473a33fc7" forKey:@"KEY_DEVICE_UUID"]; [userDefaults synchronize]; |
读取
1 2 |
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; NSString *username = [userDefaults objectForKey:@"KEY_DEVICE_UUID"]; |
Keychain
数据可以删除app后依然存在,属于只能此app读写(开发商多个app可以使用keychain group共享)
钥匙串由操作系统保护并且存储后的数据是比较安全的,常用来存储一些密码,私钥
当系统被重置的时候keychain会被清空
用iOS的 Security.framework 就可以实现钥匙串的访问、读写
这里我借助第三方开源库SSKeychain(https://github.com/soffes/sskeychain)进行示例,如果想用原生方法自行学习,官方也有demo提供下载
存入UUID
1 |
[SSKeychain setPassword:password forService:@"org.skyfox.keychain" account:@"KEY_DEVICE_UUID"]; //org.skyfox.keychain 约定俗成与应用bundleid一致即可 |
读取
1 |
NSString *uuid = [SSKeychain passwordForService:@"org.skyfox.keychain" account:@"KEY_DEVICE_UUID"]; |
在项目中使用demo
1 2 3 4 5 6 7 8 9 10 |
+(NSString*)UUID{ //从keychian中取一下uuid NSString *uuids = [SAMKeychain passwordForService:@"KEY_KEYCHAIN_SERVICE" account:@"org.skyfox.Lottery.UUID"]; //如果keychain中不存在uuid,随机生成一个放进去,下一次上边的uuids就有值了..可以直接用了.. if (uuids.length<=0) { uuids = [NSString jk_UUID]; [SAMKeychain setPassword:uuids forService:@"KEY_KEYCHAIN_SERVICE" account:@"org.skyfox.Lottery.UUID"]; } return uuids; } |
网络请求
1 2 3 4 5 |
[User login:@{@"mobile": self.usernameTextField.text?:@"",@"password":self.passwordTextField.text?:@"",@"uuid":[User UUID]} Success:^(NSURLSessionDataTask *task, User *user, id responseObject) { } Failure:^(NSURLSessionDataTask *task, NSError *error) { }]; |
某一场景的使用流程图
点击查看大图
其他方式(不推荐)
推送Token +bundle id
1、应用中增加推送用来获取token
2、获取应用bundle id
3、根据token+bundle id进行散列运算
apple push token保证设备唯一,但必须有网络情况下才能工作,该方法不依赖于设备本身,但依赖于apple push
Vendor标示符 identifierForVendor
identifierForVendor对供应商来说是唯一的一个值,也就是说,由同一个公司发行的的app在相同的设备上运行的时候都会有这个相同的标识符。然而,如果用户卸载了同一个vendor对应的所有程序,然后在重新安装同一个vendor提供的程序,此时identifierForVendor会被重置,所以基本不考虑这么不靠谱的方式
广告标示符 advertisingIdentifier
advertisingIdentifier是新框架AdSupport.framework 的一部分, 会返回给在这个设备上所有软件供应商相同的 一个值,所以只能在广告的时候使用。这个值会因为很多情况而有所变化,比如说用户初始化设备的时候便会改变。没有广告还使用这个标识或者引人AdSupport.framework后果很严重,拒绝上架!!!!!!!,拒绝上架!!!!!!!,拒绝上架!!!!!!!
获取真实UDID
由于本人是企业应用开发,不用考虑审核上架问题,所以使用了safari下载profile文件获取设备udid的方法
在线生成UUID
转载请注明:天狐博客 » iOS开发之获取设备唯一标识符