iOS设备唯一标识的前世今生
设备唯一标识
估计很多开发都有被要求过获取一下设备的唯一标识,获取设备的唯一标识经常使用在我们做统计或者是在保证一台设备登录亦或者是做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位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。
四: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 暂时应该是最科学的!
iOS设备唯一标识的前世今生的更多相关文章
- [转]iOS设备唯一标识探讨
转自:http://www.jianshu.com/p/b83b0240bd0e iOS设备唯一标识探讨 为了统计和检测应用的使用数据,几乎每家公司都有获取唯一标识的业务需求,在iOS5以前获取唯一标 ...
- 获取iOS设备唯一标识
[获取iOS设备唯一标识] 1.已禁用-[UIDevice uniqueIdentifier] 苹果总是把用户的隐私看的很重要.-[UIDevice uniqueIdentifier]在iOS5实际在 ...
- ios设备唯一标识获取策略
In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02 ...
- iOS设备唯一标识(可以用版)
由于UDID和OpenUDID被禁用,系统自带的的识别唯一标识有两种 广告标示符(IDFA-identifierForIdentifier) 这是iOS 6中另外一个新的方法,advertisingI ...
- 获得iOS设备唯一标识
使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]来作为你框架和应用的唯一标示符.坦白的来说 ...
- iOS获取设备唯一标识的8种方法
8种iOS获取设备唯一标识的方法,希望对大家有用. UDID UDID(Unique Device Identifier),iOS 设备的唯一识别码,是一个40位十六进制序列(越狱的设备通过某些工具可 ...
- ios开发——实用技术篇OC篇&获取设备唯一标识
获取设备唯一标识 WWDC 2013已经闭幕,IOS7 Beta随即发布,界面之难看无以言表...,简直就是山寨Android. 更让IOS程序猿悲催的是,设备唯一标识的MAC Address在IOS ...
- iOS获取设备唯一标识的各种方法?IDFA、IDFV、UDID分别是什么含义?
一.UDID (Unique Device Identifier) UDID的全称是Unique Device Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和 ...
- 获取设备唯一标识 uuid(采用第三方库SSKeychain)
SSKeyChain 下载链接: http://pan.baidu.com/s/1booV3VD 密码: ivdi /** * 获取设备唯一标识 uuid */ +(NSString*) uuid ...
随机推荐
- JavaScript获取页面宽度高度
网页可见区域宽:document.body.clientWidth网页可见区域高:document.body.clientHeight网页可见区域宽:document.body.offsetWidth ...
- 让两个数x,y一直保持互质的模版
int gcd(int x,int y) { )return x; else return gcd(y,x%y); }
- 【NOI2014】魔法森林
为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为 1…n1…n,边标号为1…m1…m.初始时小E同学在 11 号节点,隐 ...
- MFC中自定义消息
在头文件stdafx.h中增加一个自定义消息宏 #define WM_USER_THREADEND WM_USER + 1 在于增加新消息的窗口或对话框类的头文件中增加一个回调函数声明 afx_msg ...
- SQL Server 使用问题解答(持续更新中)
问题一:sql server 2014不允许保存更改,您所做的更改要求删除并重新创建以下表 解答:工具-选项-不勾选组织保存要求重新创建表的更改,如下图确定.
- 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](六)
前言 大家好,我是Rector 又是星期五,很兴奋,很高兴,很high...啦啦啦... Rector在图享网又和大家见面啦!!!上一篇<一步一步创建ASP.NET MVC5程序[Reposit ...
- 坑爹的file_exists
介绍 我发现了一个问题,今天与大家分享.我把整个过程描述一下. 问题 公司有个框架是基于smarty写的,我负责php的升级,维护人员把新环境布上来之后,测试人员找我提出经常报错(错 ...
- 解Linux SSH命令大全,新手必看SSH命令
下面介绍一些基本的常用的Linux SSH命令,都是一些很简单的Linux SSH命令,新手掌握了这几个,一般管理一般的vps或者linux主机就可以了! 我们的教程介绍了putty的使用方法 ...
- python判断两个list包含关系
a = [1,2] b = [1,2,3] c = [0, 1] set(b) > set(a) set(b) > set(c)
- Centos7-卸载自带的jdk 安装jdk8
卸载JDK Centos7一般都会带有自己的openjdk,我们一般都回用oracle的jdk,所以要卸载 步骤一:查询系统是否以安装jdk #rpm -qa|grep java 或 #rpm ...