设备唯一标识
估计很多开发都有被要求过获取一下设备的唯一标识, 获取设备的唯一标识经常使用在我们做统计或者是在保证一台设备登录亦或者是做 IM 的时候可能会考虑去使用它, 这一次在自己的需求当中就有一个账号绑定设备的需求, 这个需求不讨论它的实用性怎样, 需求还是需要我们自己去完成
按照自己的理解针对这个设备的唯一标识, 我还是建议少拿! 当然说的是针对 iOS 的设备下面就来总结一下这个唯一标识的发展过程
一: UDID
UDID 是什么?
你手机连接电脑的时候会弹出 iTunes, 通过它你就可以直观的看到一台设备的 UDID, 亦或者大家应该使用过蒲公英这个平台, 要是你传到这个平台的 ipa 包要能安装在一台设备上的话就需要你在你自己的开发者证书当中添加到这台设备的 UDID, 这个过程在你直接使用 Xcode 连接设备的时候, Xcode 也正确添加了开发者证书的前提下也是可以直接在你的开发者当中看到设备的 UDID 的, 这个 UDID 是苹果给每一台设备配发的唯一标识, 要是能直接使用它的话就可以直接解决上面我们的问题, 可问题的关键是:
在 iOS 5 之后苹果是禁止获取该 UDID 了, iOS 5 有点遥远了
比如下面是通过 iTunes 获取到的公司的测试机的设备信息:
(有同事问我说为什么我 iTunes 的电话号码下面是序列号, 不是 UDID 啊, 你这是个假的 iTunes 吧!! 哈哈.... 这怎么可能! 你点击一下你的系列号试试! 我把刀架在同事的脖子上问他是真的还是假的?)
二: IDFA
IDFA 又是什么玩意?
IDFA 俗称广告 ID, 估计在开发者里面提交用过应用的朋友都知道, 在最后提交的时候苹果会问你有没有使用广告 ID, 不知道现在该有没有处于懵逼状态不懂苹果为什么要问这个的同行, 看了我们这个就会清楚了为什么会这么问呢? 这个广告 ID 就是 IDFA
这个 IDFA 既然是苹果的玩意, 那是不是我们就可以安心的用了, 答案肯定是不行的, 苹果在用户隐私这一方面还是挺重视的, 你肯定是不能用的! 在手机设置中你是可以关闭这个按钮的, 如下所示:
通过下面的一样代码你就能拿到这个 IDFA:
- #import <AdSupport/AdSupport.h>
- NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
- NSLog(@"拿到的广告 ID:%@",idfa);
三: MAC Address
MAC 地址用来表示互联网上每一个站点的标识符, 采用十六进制数表示, 共六个字节 (48 位) 其中, 前三个字节是由 IEEE 的注册管理机构 RA 负责给不同厂家分配的代码 (高位 24 位), 也称为编制上唯一的标识符 (Organizationally Unique Identifier), 后三个字节(低位 24 位) 由各厂家自行指派给生产的适配器接口, 称为扩展标识符(唯一性)
MAC 地址在网络上用来区分设备的唯一性, 接入网络的设备都有一个 MAC 地址, 他们肯定都是不同的, 是唯一的一部 iPhone 上可能有多个 MAC 地址, 包括 WIFI 的 SIM 的等, 但是 iTouch 和 iPad 上就有一个 WIFI 的, 因此只需获取 WIFI 的 MAC 地址就好了, 也就是 en0 的地址
MAC 地址就如同我们身份证上的身份证号码, 具有全球唯一性这样就可以非常好的标识设备唯一性, 听着上面的解释是不是感觉很完美?
but......
在 iOS 7.0 之后你再去请求 MAC 地址, 返回的永远都是同一个值! 被禁了......
四: IDFV 也就是 UUID
UUID 这个你获取起来是比较容易的, 但你要是想使用这个作为手机的唯一标识也是不行的, 为什么?
我们用事实说明这个问题, 下面的这些结论都是经过自己亲自测试的, 在现有的版本中是没有问题的!!!
获取 UUID, 通过下面的方法:
NSString * strUUID = [UIDevice currentDevice].identifierForVendor.UUIDString
下一步: 你把手机的应用删除了再测试一下, 我们的结论是: 要是只是单纯的这样获取 UUID, 删除了应用在重新安装是会发生变化的!
五: UUID + KeyChain
说了上面的这么多, 这个就是这篇文章的重点内容了, 你获取到 UUID 之后把 UUID 存在系统钥匙串中, 你看到这个方案肯定也有下面这些疑问:
1 删除了应用这个标识会变吗?
2 升级了系统这个标识会变吗?
3 重置了系统之后呢? 这个标识会变吗?
4 既然是使用到了系统钥匙串的东西, 那要是我把手机越狱了, 会有问题吗?
下面是我们这个方案的总的代码, 先把代码给大家, 完了我们再通过测试给上面的问题给出答案! 给 NSString 添加一个 UUID 的类别:
- //
- // NSString+UUID.h
- // Encapsulation
- //
- // Created by Zhangxu on 2018/1/26.
- // 获取 UUID 并存储到 keyChain
- #import <Foundation/Foundation.h>
- @interface NSString (UUID)
- + (NSString *)getUUID;
- @end
- @interface KeyChainStore : NSObject
- // 将 UUID 保存到钥匙串
- + (void)save:(NSString *)service data:(id)data;
- // 读取保存到钥匙串的 UUID
- + (id)load:(NSString *)service;
- // 删除保存到钥匙串的 UUID
- + (void)deleteKeyData:(NSString *)service;
- @end
上面是. h 文件, 下面就是 NSString+UUID.m 的文件:
- //
- // NSString+UUID.m
- // Encapsulation
- // Created by Zhangxu on 2018/1/26.
- // 获取 UUID 并存储到 keyChain
- #import "NSString+UUID.h"
- @class KeyChainStore;
- static NSString * KEY_USERNAME_PASSWORD = @"com.Zhushi.ShuangLongChessAndCard";
- @implementation NSString (UUID)
- +(NSString *)getUUID
- {
- NSString * strUUID = (NSString *)[KeyChainStore load:KEY_USERNAME_PASSWORD];
- // 首次执行该方法时, uuid 为空
- if ([strUUID isEqualToString:@""] || !strUUID)
- {
- // 获取 UUID
- strUUID = [UIDevice currentDevice].identifierForVendor.UUIDString;
- // 将该 uuid 保存到 keychain
- [KeyChainStore save:KEY_USERNAME_PASSWORD data:strUUID];
- //iPhone 8
- //11.2 版本最初安装应用 UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
- //11.2 版本删除重装应用 UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
- // 升级系统 11.2.5 之后 UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
- //iPhone 6
- //10.3.3 最初安装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
- //10.3.3 删除重装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
- // 升级 11 系统重装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
- // 还原系统之后的应用 UUID 1236FB53-CDCE-431E-999B-5C857C679B8A
- }
- return strUUID;
- }
- @end
- #pragma mark -- KeyChainStore
- @implementation KeyChainStore
- + (NSMutableDictionary *)getKeychainQuery:(NSString *)service
- {
- return [NSMutableDictionary dictionaryWithObjectsAndKeys:
- (id)kSecClassGenericPassword,(id)kSecClass,
- service, (id)kSecAttrService,
- service, (id)kSecAttrAccount,
- (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
- nil];
- }
- // 将 UUID 保存到钥匙串
- + (void)save:(NSString *)service data:(id)data
- {
- //Get search dictionary
- NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
- //Delete old item before add new item
- SecItemDelete((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 dictionary
- SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
- }
- // 读取保存到钥匙串的 UUID
- + (id)load:(NSString *)service
- {
- id ret = nil;
- NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
- [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);
- return ret;
- }
- // 删除保存到钥匙串的 UUID
- + (void)deleteKeyData:(NSString *)service
- {
- NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
- SecItemDelete((CFDictionaryRef)keychainQuery);
- }
- @end
最后的结论:
通过上面的代码你可以看到整个代码不是多么的复杂, 我们关心的还是上面提出的几个疑问, 我们一一测试:
1 删除了应用之后这个标识会改变吗?
结论: 只要不是越狱的设备, 删除应用之后是不会改变这个标识的!(越狱设备后面说!)
2 升级了系统这个标识会变吗?
下面是我把手机升级之后拿到的一组数据, 测试机, 就不给标识上码了... 哈哈
iPhone 8
11.2 版本最初安装应用 UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
11.2 版本删除重装应用 UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
升级系统 11.2.5 之后 UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
iPhone 6
10.3.3 最初安装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
10.3.3 删除重装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
升级 11 系统重装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
通过上面的这组数据, 我们可以得到的结论是: 在现有版本情况下, 升级系统是不会改变这个标识的!
3 用于还原了设备会改变这个标识吗? 我们再通过下面这组数据说明, 拿我们的 iPhone6 当小白鼠, 要是不知道怎样还原手机设备的看下面的: 设置 -> 通用 -> 还原
看我们在小白鼠上拿到的数据:
iPhone 6
10.3.3 最初安装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
10.3.3 删除重装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
升级 11 系统重装应用 UUID 711CAC84-0540-4A44-80B4-26F87D2DD8B7
还原系统之后的应用 UUID 1236FB53-CDCE-431E-999B-5C857C679B8A
结论: 还原系统之后我们这个标识符真的改变了!!!!
4 那要是设备越狱了呢?
结论: 在越狱设备上经过测试, 是偶尔可以, 偶尔不行!!! 没错, 就是这个结论!
最后:
通过上面的对比数据分析, 结果我们也给大家了, 通过上面的结论, 你就知道了使用 UUID + KeyChain 的利弊, 在目前中你想要做唯一标识 UUID + KeyChain 暂时应该是最科学的!
来源: https://www.cnblogs.com/taoxu/p/8377026.html