iOS唯一设备ID

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

iOS唯⼀设备ID
设备ID,简单来说就是⼀串符号(或者数字),⽤来唯⼀标识⼀台硬件设备。

对于APP⾃⾝产品⽽⾔,使⽤设备唯⼀ID可以追踪到⽤户从下载、激活、注册、使⽤、流失、回归的全流程数据,对产品运营⼯作⾮常有帮助。

对于精准⼴告和个性化推荐⽽⾔,可以使⽤设备ID进⾏数据收集、然后进⾏千⼈千⾯的精准营销。

IMEI
IMEI是国际移动设备识别码,⼀串15位的号码,每部通过正规渠道销售的GSM⼿机均有唯⼀的IMEI码。

IMEI码由GSMA协会统⼀规划,并授权各地区组织进⾏分配,⼀般由运营商存储在SIM卡中。

因此,与Android⼿机⼀样,iOS也有IMEI码,可在(设置 -> 通⽤ -> 关于⼿机 )中查看。

但在iOS5中已经完全的禁⽤了它。

UDID
UDID(Unique Device Identifier Description)是苹果IOS设备的唯⼀识别码,由40个字符的字母和数字组成。

在很多需要限制⼀台设备⼀个账号的应⽤中经常会⽤到。

在iOS5中可以获取到设备的UDID,但在iOS7中已经完全的禁⽤了它。

iOS7之前编译的app如果在iOS7上运⾏,它不会返回设备的UDID,⽽是会返回⼀串字符串,以FFFFFFFF开头,跟着identifierForVendor的⼗六进制值。

NSString *UDID = [[UIDevice currentDevice] uniqueIdentifier];
查看设备UDID
⽅法1:
(1)将⼿机通过数据线查到电脑,并在⼿机上信任此电脑后,就可以在iTune中查看⼿机的UDID
(2)如下可以看到当前⼿机的UDID(注:如显⽰为序列号、ECID、型号识别符等,请点击切换到UDID)
注:新的Mac系统(如:macOS Catalina 版本:10.15.5)已经去掉了iTune了,可从这⾥查看⼿机的UDID
⽅法2:将⼿机通过数据线查到电脑,并在⼿机上信任此电脑后,在Xcode菜单“Window” -- “Devices and Simulators”的Devices⾯板中查看⼿机的UDID
当然,⽬前想要获取UDID也并不是全⽆办法,不过过程⾮常复杂有兴趣的朋友可以参考这篇博客:
OpenUDID
由于UDID在iOS7中完全的禁⽤,成为了当时使⽤最⼴泛的开源UDID替代⽅案
OpenUDID利⽤了⼀个⾮常巧妙的⽅法在不同程序间存储标⽰符 — 在粘贴板中⽤了⼀个特殊的名称来存储标⽰符。

通过这种⽅法,别的程序(同样使⽤了OpenUDID)知道去什么地⽅获取已经⽣成的标⽰符(⽽不⽤再⽣成⼀个新的)。

⽽且根据贡献者的代码和⽅法,和⼀些开发者的经验,如果把使⽤了OpenUDID⽅案的应⽤全部都删除,再重新获取OpenUDID,此时的OpenUDID就跟以前的不⼀样。

可见,这种⽅法还是不保险。

值得⼀提是:OpenUDID库早已经弃⽤了, 在其官⽅的博客中也指明了, 停⽌维护OpenUDID的原因是为了更好的向苹果的举措靠拢。

UUID
UUID(Universally Unique IDentifier):通⽤唯⼀识别码。

它是苹果提供的⼀个获取⼤随机数的⽅法。

形如:68753A44-4D6F-1226-
9C60-0050E4C00067
据说UUID随机数算法得到的数重复概率为170亿分之⼀。

这样,每个⼈都可以建⽴不与其它⼈冲突的 UUID。

CFUUID
从iOS2.0开始,CFUUID就已经出现了。

它是CoreFoundatio包的⼀部分,因此API属于C语⾔风格。

CFUUIDCreate ⽅法⽤来创建CFUUIDRef,并且可以获得⼀个相应的NSString。

每次调⽤CFUUIDCreate,系统都会返回⼀个新的CFUUID,但是它会保持唯⼀性。

CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
NSString *cfuuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
NSUUID
在iOS 6中才出现,与CFUUID完全⼀样,只不过它是Objective-C接⼝。

同样,NSUUID 每次获取的值都会发⽣变化,但是它会保持唯⼀性。

NSString *uuid = [[NSUUID UUID] UUIDString];
IDFV
IDFV(Identifier For Vendor)是iOS 6.0系统新增⽤于替换UDID的接⼝。

是给Vendor标识⽤户⽤的,每个设备在所属同⼀个Vender的应⽤⾥,都有相同的值。

形如:95955F33-BFBD-48BA-A630-866D2DAE482D
其中的Vender是指应⽤提供商。

iOS6.x是通过BundleID前两部分来匹配,iOS7.x是通过除了最后⼀个部分来匹配。

如果相同就是同⼀个Vender,共享同⼀个idfv的值。

具体详见:
Bundle ID iOS 6.x iOS 7.x
com.example.app1com.example.app1com.example.app1
com.example.app2com.example.app2com.example.app2
com.example.app.app1com.example.app.app1com.example.app.app1
com.example.app.app2com.example.app.app2com.example.app.app2
example example example
和idfa不同的是,idfv的值是⼀定能取到的,所以⾮常适合于作为内部⽤户⾏为分析的主id,来标识⽤户,替代OpenUDID。

如果⽤户将属于此Vender的所有App卸载,则idfv的值会被重置,即再重装此Vender的App,idfv的值和之前不同。

NSString *strIDFV = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
IDFA
IDFA是iOS 6.0系统新增⼴告标⽰符,适⽤于对外:例如⼴告推⼴,换量等跨应⽤的⽤户追踪等。

在同⼀个设备上的所有App都会取到相同的值,是苹果专门给各⼴告提供商⽤来追踪⽤户⽽设的。

形如:9C287922-EE26-4501-94B5-DDE6F83E1475
但如果⽤户完全重置系统(设置 -> 通⽤ -> 还原 -> 还原位置与隐私) ,这个⼴告标⽰符会重新⽣成。

在iOS 10.0之前,⽤户开启了“限制⼴告跟踪”(设置 -> 隐私- > ⼴告 -> 限制⼴告跟踪)之后,商家⼀样可以获取idfa,只不过与之前的不⼀样了。

在iOS 10.0及以后,开启了该功能,获取到的idfa为⼀个固定值00000000-0000-0000-0000-000000000000;同样每次开启再关闭,相应的idfa也会重新⽣成。

具体详见:
NSString* IdfaString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
SimulateIDFA
由于IDFA在iOS 10.0及以后版本中,可能⽆法获取,因此有⼈开发了IDFA的替代⽅案SimulateIDFA。

是⼀个github开源库,它会根据⼀堆设备信息(每个app获取的值都是⼀样的)⽣成的⼀个MD5值。

⽤于标志不同设备。

与IDFA格式⼀样,形如:626363D0-90D4-06BF-C281-384E4E69D3E2
前16位626363D0-90D4-06BF是由⽐较稳定的参数组合获得(如下),这前16位只有在系统升级的情况下才会变。

系统版本(9.3.2)// 系统升级会变
硬件信息(N53AP,iPhone6,2,中国移动46002,1048576000)
coreServices⽂件创建更新时间(2015-08-0723:53:00 +0000,2016-06-0723:53:09 +0000) // 系统升级会变
系统容量(12266725376) // 系统升级会变
后16位C281-384E4E69D3E2由⼀些⽐较容易被改变的参数组合⽣成,⽐较常见的值变化情况是系统重新启动。

系统开机时间(1473301191去掉后⾯的4位数147330) // 系统重启会变
国家代码(CN)
本地语⾔(zh-Hans-CN)
设备名称(XXXX)
在需要获取 SimulateIDFA的地⽅调⽤代码
NSString *simulateIDFA = [SimulateIDFA createSimulateIDFA];
OpenIDFA
由于IDFA在iOS 10.0及以后版本中,可能⽆法获取,同样,有⼈开发了IDFA的替代⽅案OpenIDFA。

是⼀个github开源库,与SimulateIDFA⼀样,同样是IDFA的⼀种替代⽅案。

OpenIDFA是对下⾯的参数组合进⾏MD5
系统开机时间(1473241127减去后四位值为147324)
系统容量(29230571520)
系统版本(9.3.4)
机型(N78AP,iPod5,1)
国家代码(CN)
本地语⾔(zh-Hans-CN)
⼀些预装的App // 由于⽤的是canOpenURL这个接⼝,iOS9就已经废了
时区(Asia/Shanghai)
当天时间(160804, 16年8⽉4⽇) // 这个值是其每天值都会变化的原因
与SimulateIDFA相⽐,OpenIDFA 有⼀些限制,⽣成的IDFA会每天变化,在⼀些极端条件下重复率⽐较⾼。

MAC地址
MAC地址在⽹络上⽤来区分设备的唯⼀性,接⼊⽹络的设备都有⼀个MAC地址,他们肯定都是不同的,是唯⼀的。

⼀部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有⼀个WIFI的,因此只需获取WIFI的MAC地址就好了,也就是en0的地址。

MAC地址就如同我们⾝份证上的⾝份证号码,具有全球唯⼀性。

- (NSString *)macAddress
{
int mib[6];
size_t len;
char *buf;
unsigned char *ptr;
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
if ((mib[5] = if_nametoindex("en0")) == 0) {
}
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
printf("Error: sysctl, take 1/n");
return NULL;
}
if ((buf = malloc(len)) == NULL) {
printf("Could not allocate memory. error!/n");
return NULL;
}
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
printf("Error: sysctl, take 2");
return NULL;
}
ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl);
NSString *outstring = [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
NSLog(@"outString:%@", outstring);
free(buf);
return [outstring uppercaseString];
}
但在iOS 7.0之后,如果请求Mac地址都会返回⼀个固定值:02:00:00:00:00:00
herody⽹友实现的UQID
详见其在github上开源项⽬:
使⽤KeyChain来提升持久性
上⾯的设备ID⽅案,可保证唯⼀性,但在持久性上存在或多或少的问题。

为了最⼤限度地维持设备ID的持久性,可以借助KeyChain来保存第⼀次⽣成出来的设备ID,然后下次直接从KeyChain读取该ID
iOS系统中有⼀个KeyChain(类似于windows的注册表),每个程序都可以往KeyChain中记录数据,⽽且只能读取到⾃⼰程序记录在KeyChain中的数据。

详细特点如下:
1. KeyChain与在App的sandbox不⼀样,即使删除了App,资料依然保存在KeyChain中,如果重新安装了App,还可以从KeyChain中获取数据
2. KeyChain的数据可以⽤group的⽅式,让程序可以在App间共享。

共享的条件如下:
①相同的bundle id组:⽐如这⾥有两个应⽤程序: A应⽤程序使⽤的provision对应的bundle id是com.jaybin.keychain1,B应⽤程序使⽤的provision对应的 bundle id是com.jaybin.keychain2 。

那么这两个应⽤程序就可以共享keychain数据。

②应⽤程序需要打开Keychain Sharing
3. keychain的数据以加密的⽅式存储在设备中
因此就算我们程序删除掉,系统经过升级以后再安装回来,依旧可以获取到与之前⼀致的设备ID(系统还原、刷机除外)
+ (NSString *)UUID {
KeychainItemWrapper *keyChainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MYAppID" accessGroup:@"com.test.app"];
NSString *UUID = [keyChainWrapper objectForKey:(__bridge id)kSecValueData];
if (UUID == nil || UUID.length == 0) {
UUID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
[keyChainWrapper setObject:UUID forKey:(__bridge id)kSecValueData];
}
return UUID;
注:KeychainItemWrapper⼯具类详见:参考。

相关文档
最新文档