想要追踪、统计用户,自然离不开用户唯一标识符,这是每个公司都面临的问题。在历史上唯一标识符很多,如UDID、MAC地址、OpenUDID等,不再一一介绍他们是怎么挂掉的,现在好用的只剩下了idfa、idfv、UUID+keyChain。
在2013年3月21日苹果已经通知开发者,从2013年5月1日起,访问UIDID的应用将不再能通过审核,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标示符”。unique Identifier即将退出,苹果给了我们Vendor和Advertising identifier两个选择,但应该用哪一个?文档并没有给出确切答案,具体使用哪个完全由你根据自己app的目的来决定。下面我将列出iOS中目前支持的,以及被废弃的唯一标示符方法,并对其做出相应的解释,希望可以帮你做出正确的确定。
一、推荐使用的方法
1.1、广告标示符(IDFA-identifierForIdentifier):
可以理解为广告id,apple公司提供的用于追踪用户的广告标识符。
使用了IDFA的在提交app的时候需要注意:appstore中关于IDFA的选项和设置
缺点:如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。
另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。
要求:iOS>=6.0
这是iOS 6中另外一个新的方法,advertisingIdentifier是新框架AdSupport.framework的一部分。ASIdentifierManager单例提供了一个方法advertisingIdentifier,通过调用该方法会返回一个上面提到的NSUUID实例。
//需要导入AdSupport.framework这个库 #import <AdSupport/AdSupport.h> NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
跟CFUUID和NSUUID不一样,广告标示符是由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。
关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。之所以会这样,我猜测是由于ASIdentifierManager是一个单例。
针对广告标示符用户有一个可控的开关“限制广告跟踪”。
// 判断是否开启 限制广告跟踪选项(该选项在设置-隐私-广告-限制广告隐私) Boolean on = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled];
Nick Arnott的文章中已经指出了。将这个开关打开,实际上什么也没有做,不过这是希望限制你访问广告标示符,ios10之前开关限制广告追踪选项的确没什么用,ios10之后,如果手机开启限制广告追踪的话就不能再得到广告标识符,得到的是下面的0。这个开关是一个简单的boolean标志,当将广告标示符发到任意的服务器端时,你最好判断一下这个值,然后再做决定。
NSLog(@"%@\n",[[[ASIdentifierManager sharedManager] advertisingIdentifier]UUIDString]); NSLog(@"%d\n",[[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]);
输出时,当手机的限制广告追踪开启的时候
//开启的时候 2016-01-05 15:22:19.218 sss[1773:60b] 41B2FD07-695A-4A27-8D26-C30ECE6F7EAD 2016-01-05 15:22:19.233 sss[1773:60b] 0
关闭的时候是
//关闭的时候 2016-01-05 15:19:57.502 sss[1763:60b] 7773E145-26FF-4304-A60F-60C948D52B40 2016-01-05 15:19:57.516 sss[1763:60b] 1
开启和关闭切换的话,idfa会变,如果不切换,保持开启状态,每次都是不会变的,当切换了下之后就会变,或者还原的话会变
ios10更新:
ios10之后,当打开限制广告追踪的时候虽然在模拟器上面仍能获得,但是真机调试,如果手机开启限制广告追踪的话就不能再得到广告标识符,得到的是下面的0,所以ios10之后也推荐使用后面说的SimulateIDFA
00000000-0000-0000-0000-000000000000
1.2、idfv (identifierForVendor)
apple提供给Vendor的唯一标识符,Vendor代表了应用开发商,实际使用时,一个Vendor是CFBundleIdentifier的前两部分。例如,com.baidu.tieba 和 com.baidu.image 得到的idfv是相同的,因为它们的CFBundleIdentifier 前两部分是相同的。
优点:当开关限制广告追踪的选项时,idfv不会改变
缺点:把同一个开发商的所有应用卸载后,再次安装取到的idfv会不同,如果只有你这一个软件,卸载之后重新安装idfv会变化。
要求:iOS>=6.0
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
示例
//关闭广告追踪限制 2016-10-15 22:26:24.635363 test[1219:425254] idfa:22EDE0F9-9088-40DB-BFBD-1BC6F1E37C71 2016-10-15 22:26:24.636190 test[1219:425254] idfv:06C58C45-823F-48B0-B906-0ACC9925D070 //开启广告追踪限制 2016-10-15 22:27:36.337051 test[1226:426248] idfa:00000000-0000-0000-0000-000000000000 2016-10-15 22:27:36.337459 test[1226:426248] idfv:06C58C45-823F-48B0-B906-0ACC9925D070 //开启广告追踪限制,重新安装软件 2016-10-15 22:28:08.265168 test[1228:426658] idfa:00000000-0000-0000-0000-000000000000 2016-10-15 22:28:08.265559 test[1228:426658] idfv:5A07C951-A62C-495D-98CE-C7EDE3CEE064
1.3、NSUUID(每次调用都会改变)
NSUUID在iOS 6中才出现,这跟CFUUID几乎完全一样,只不过它是Objective-C接口。+ (id)UUID 是一个类方法,调用该方法可以获得一个UUID。通过下面的代码可以获得一个UUID字符串:
NSString *uuid = [[NSUUID UUID] UUIDString];
跟CFUUID一样,这个值系统也不会存储,每次调用的时候都会获得一个新的唯一标示符。如果要存储的话,你需要自己存储。在我读取NSUUID时,注意到获取到的这个值跟CFUUID完全一样(不过也可能不一样):
示例: 68753A44-4D6F-1226-9C60-0050E4C00067
1.4、SimulateIDFA
SimulateIDFA是解决ios10之后,如果开启广告限制就追踪不到idfa的问题,SimulateIDFA 是根据一堆设备信息(每个app获取的值都是一样的)生成的一个MD5值。用于标志不同设备。生成的MD5值分两部分。
以 626363D0-90D4-06BF-C281-384E4E69D3E2 为例:
前16位626363D0-90D4-06BF是由比较稳定的参数组合获得,这前16位只有在系统升级的情况下才会变。
后16位C281-384E4E69D3E2 由 一些比较容易被改变的参数组合生成,比较常见的值变化情况是系统重新启动。
参与前16位计算的参数有:
系统版本(9.3.2)、硬件信息(N53AP,iPhone6,2,中国移动46002,1048576000)、coreServices文件创建更新时间(2015-08-07 23:53:00 +0000,2016-06-07 23:53:09 +0000),系统容量(12266725376)
这里有一些信息是升级的时候会变的,系统版本、coreServices文件创建更新时间、系统容量
参与后16位计算的参数有:
系统开机时间(1473301191去掉后面的4位数 147330)、国家代码(CN)、本地语言(zh-Hans-CN)、设备名称(XXXX)
这里的参数都是比较容易变化的,系统重启离上次重启有10000秒的话会变,其他参数在设置里面可以修改
优点:解决了IOS10开启广告限制就追踪不到idfa的问题
缺点:SimulateIDFA分两部分,前16位是在系统升级的时候才会变化,后16位用户的某些行为可能会导致值变化(例如:重启手机、修改设备名称、修改手机本地语言),意思就是系统升级,修改设备名称等都会改变
github下载地址:https://github.com/youmi/SimulateIDFA
从github下载源码,把头文件SimulateIDFA.h和SimulateIDFA.m引入工程
#import "SimulateIDFA.h" NSString *simulateIdfa =[SimulateIDFA createSimulateIDFA]; NSLog(@"simulateIdfa:%@",simulateIdfa);
得到的结果
//关闭广告限制 2016-10-15 22:49:39.682863 SimulateIDFADemo[1242:433288] simulateIdfa:4E91FF42-F7D9-C74D-1CF7-84CB337BD11B //开启广告限制 2016-10-15 22:50:19.374259 SimulateIDFADemo[1247:433975] simulateIdfa:4E91FF42-F7D9-C74D-1CF7-84CB337BD11B //重装软件 2016-10-15 22:50:47.091237 SimulateIDFADemo[1249:434374] simulateIdfa:4E91FF42-F7D9-C74D-1CF7-84CB337BD11B //修改手机名称 2016-10-15 22:59:24.077596 SimulateIDFADemo[1267:437081] simulateIdfa:4E91FF42-F7D9-C74D-D12F-A210F3E747E8 //修改手机语言 2016-10-15 23:01:25.405772 SimulateIDFADemo[1316:439169] simulateIdfa:4E91FF42-F7D9-C74D-4E4A-67F36D496162
二、被弃用的方法
2.1、CFUUID(每次都会改变)
从iOS2.0开始,CFUUID就已经出现了。它是CoreFoundatio包的一部分,因此API属于C语言风格。CFUUIDCreate 方法用来创建CFUUIDRef,并且可以获得一个相应的NSString,如下代码:
CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);NSString *cfuuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
获得的这个CFUUID值系统并没有存储。每次调用CFUUIDCreate,系统都会返回一个新的唯一标示符。如果你希望存储这个标示符,那么需要自己将其存储到NSUserDefaults, Keychain, Pasteboard或其它地方。
2.2、UDID(该函数已经被移除)
在之前的版本中是可用的,但是在iOS5以及之后的版本中,以及被弃用了。虽然,这个UDID用得很广泛,但是,不得不说的是,它在慢慢的远离开发者,不能在考虑使用UDID了。至于这个标示符是转为私有方法,或者完全从以后的iOS版本中移除,还有待观察。不过,这个UDID在部署企业级签名程序时,非常方便。获取UDID的方法如下:
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
示例: bb4d786633053a0b9c0da20d54ea7e38e8776da4
2.3、OpenUDID(在ios7以上已经作废)
在iOS 5发布时,uniqueIdentifier被弃用了,这引起了广大开发者需要寻找一个可以替代UDID,并且不受苹果控制的方案。由此OpenUDID成为了当时使用最广泛的开源UDID替代方案。OpenUDID在工程中实现起来非常简单,并且还支持一系列的广告提供商。
NSString *openUDID = [OpenUDID value];
OpenUDID利用了一个非常巧妙的方法在不同程序间存储标示符 — 在粘贴板中用了一个特殊的名称来存储标示符。通过这种方法,别的程序(同样使用了OpenUDID)知道去什么地方获取已经生成的标示符(而不用再生成一个新的)。
之前已经提到过,在将来,苹果将开始强制使用advertisingIdentifier 或identifierForVendor。如果这一天到来的话,即使OpenUDID看起来是非常不错的选择,但是你可能不得不过渡到苹果推出的方法。
示例: 0d943976b24c85900c764dd9f75ce054dc5986ff
2.4、MAC+MD5获取(ios7之后已经作废)
从iOS7开始,获取MAC地址的方法统一返回02:00:00:00:00:00,所以使用MAC+MD5方法已无意义
三、持久化保存状态
因为一直不变的UDID已经被苹果移除,所有标志符是会因为操作改变的,这里总结下用户操作手机是否会修改保存状态,值是否会变,
√表示值不会变,×标识值会变,?表示未测试
启动程序 | 后台返回 | 重置广告标志符 | 重新安装程序 | 重启手机 | 系统还原 | 升级系统 | 重装系统 | |
UDID(已作废) | √ | √ | √ | √ | √ | √ | √ | √ |
mac+md5(已作废) | √ | √ | √ | √ | √ | √ | √ | √ |
CFUUID | × | × | × | × | × | × | × | × |
NSUUID | × | × | × | × | × | × | × | × |
IDFA | √ | √ | × | √ | √ | × | √ | × |
IDFV | √ | √ | √ | × | √ | × | √(?) | × |
OpenUDID(已作废) | √ | √ | √ | √ | √ | × | √ | × |
SecureUDID | √ | √ | √ | × | √ | × | √ | × |
SimulateIDFA | √ | √ | √ | √ | × | × | × | × |
四、总结
SecureUDID是一个第三方库,是一个开源的基于沙箱机制的解决方案,是虚拟出来的,所以不能确保不同设备上的UDID不同,用户可以选择阻止SecureUDID收集UDID信息,如果用户备份A设备系统并将其恢复到B设备,则B设备将得到A设备的UDID,删除程序并清空剪切板可能会导致丢失,非苹果原生的API,所以使用的话还是最好使用idfa和idfv。
idfa在用户重置广告标志符的时候会变化,所以可以把第一次生成的idfa存放到keychain里面,以后就直接读取keychain值就可以了,这样就能避免用户重置广告标志符造成idfa的变化,而keychain的值只有在用户重置系统的时候才会删除,所以很适合用idfa+keychain的方案,keychain的使用方法《IOS的keychain的三种使用方法》
五、参考文章
版权属于:东哥笔记 - DongGe.org
本文链接:https://dongge.org/blog/262.html
自2017年12月26日起,『转载以及大段采集进行后续编辑』须注明本文标题和链接!否则禁止所有转载和采集行为!