想要追踪、统计用户,自然离不开用户唯一标识符,这是每个公司都面临的问题。在历史上唯一标识符很多,如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中目前支持的,以及被废弃的唯一标示符方法,并对其做出相应的解释,希望可以帮你做出正确的确定。</p><h2>一、推荐使用的方法</h2><h3>1.1、广告标示符(IDFA-identifierForIdentifier):</h3><p>
可以理解为广告id,apple公司提供的用于追踪用户的广告标识符。</p><p>
使用了IDFA的在提交app的时候需要注意:<a href="http://www.hudongdong.com/skill/240.html" target="_blank">appstore中关于IDFA的选项和设置</a> </p><p>
缺点:如果用户完全重置系统((设置程序 -&gt; 通用 -&gt; 还原 -&gt; 还原位置与隐私) ,这个广告标示符会重新生成。</p><p>
另外如果用户明确的还原广告(设置程序-&gt; 通用 -&gt; 关于本机 -&gt; 广告 -&gt; 还原广告标示符) ,那么广告标示符也会重新生成。</p><p>
要求:iOS&gt;=6.0</p><p>
这是iOS 6中另外一个新的方法,advertisingIdentifier是新框架AdSupport.framework的一部分。ASIdentifierManager单例提供了一个方法advertisingIdentifier,通过调用该方法会返回一个上面提到的NSUUID实例。</p><pre class="prettyprint linenums">//需要导入AdSupport.framework这个库

import <AdSupport/AdSupport.h>

NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

跟CFUUID和NSUUID不一样,广告标示符是由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。</p><p>
关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。之所以会这样,我猜测是由于ASIdentifierManager是一个单例。</p><p>
针对广告标示符用户有一个可控的开关“限制广告跟踪”。</p><pre class="prettyprint linenums">//&nbsp;判断是否开启&nbsp;&nbsp;限制广告跟踪选项(该选项在设置-隐私-广告-限制广告隐私)

Boolean on = [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled];

Nick Arnott的文章中已经指出了。将这个开关打开,实际上什么也没有做,不过这是希望限制你访问广告标示符,ios10之前开关限制广告追踪选项的确没什么用,ios10之后,如果手机开启限制广告追踪的话就不能再得到广告标识符,得到的是下面的0。这个开关是一个简单的boolean标志,当将广告标示符发到任意的服务器端时,你最好判断一下这个值,然后再做决定。

NSLog(@"%@\n",[[[ASIdentifierManager sharedManager] advertisingIdentifier]UUIDString]);
NSLog(@"%d\n",[[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]);

输出时,当手机的限制广告追踪开启的时候</p><pre class="prettyprint lang-js linenums">//开启的时候

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

关闭的时候是</p><pre class="prettyprint linenums">//关闭的时候

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会变,如果不切换,保持开启状态,每次都是不会变的,当切换了下之后就会变,或者还原的话会变</p><p><span style="color: rgb(255, 0, 0);">ios10更新:</span><br/></p><p>ios10之后,当打开限制广告追踪的时候虽然在模拟器上面仍能获得,但是真机调试,如果手机开启限制广告追踪的话就不能再得到广告标识符,得到的是下面的0,所以ios10之后也推荐使用后面说的SimulateIDFA</p><pre class="prettyprint lang-cpp linenums">00000000-0000-0000-0000-000000000000</pre><h3>1.2、idfv (identifierForVendor)</h3><p>
apple提供给Vendor的唯一标识符,Vendor代表了应用开发商,实际使用时,一个Vendor是CFBundleIdentifier的前两部分。例如,com.baidu.tieba 和 com.baidu.image 得到的idfv是相同的,因为它们的CFBundleIdentifier 前两部分是相同的。</p><p>优点:当开关限制广告追踪的选项时,idfv不会改变</p><p>
缺点:把同一个开发商的所有应用卸载后,再次安装取到的idfv会不同,如果只有你这一个软件,卸载之后重新安装idfv会变化。</p><p>
要求:iOS&gt;=6.0</p><pre class="prettyprint linenums">NSString&nbsp;*idfv&nbsp;=&nbsp;[[[UIDevice&nbsp;currentDevice]&nbsp;identifierForVendor]&nbsp;UUIDString];</pre><p>示例<br/></p><pre class="prettyprint lang-cpp linenums">//关闭广告追踪限制

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字符串:</p><pre class="prettyprint linenums">NSString&nbsp;*uuid&nbsp;=&nbsp;[[NSUUID&nbsp;UUID]&nbsp;UUIDString];</pre><p>
跟CFUUID一样,这个值系统也不会存储,每次调用的时候都会获得一个新的唯一标示符。如果要存储的话,你需要自己存储。在我读取NSUUID时,注意到获取到的这个值跟CFUUID完全一样(不过也可能不一样):</p><p>
示例: 68753A44-4D6F-1226-9C60-0050E4C00067</p><h3>1.4、SimulateIDFA</h3><p>SimulateIDFA是解决ios10之后,如果开启广告限制就追踪不到idfa的问题,SimulateIDFA 是根据一堆设备信息(每个app获取的值都是一样的)生成的一个MD5值。用于标志不同设备。生成的MD5值分两部分。</p><p>以 626363D0-90D4-06BF-C281-384E4E69D3E2 为例:</p><p>前16位626363D0-90D4-06BF是由比较稳定的参数组合获得,这前16位只有在系统升级的情况下才会变。</p><p>后16位C281-384E4E69D3E2 由 一些比较容易被改变的参数组合生成,比较常见的值变化情况是系统重新启动。</p><p>参与前16位计算的参数有:</p><p>系统版本(9.3.2)、硬件信息(N53AP,iPhone6,2,中国移动46002,1048576000)、coreServices文件创建更新时间(2015-08-07 23:53:00 +0000,2016-06-07 23:53:09 +0000),系统容量(12266725376)</p><p>这里有一些信息是升级的时候会变的,系统版本、coreServices文件创建更新时间、系统容量</p><p>参与后16位计算的参数有:</p><p>系统开机时间(1473301191去掉后面的4位数 147330)、国家代码(CN)、本地语言(zh-Hans-CN)、设备名称(XXXX)</p><p>这里的参数都是比较容易变化的,系统重启离上次重启有10000秒的话会变,其他参数在设置里面可以修改</p><p>优点:解决了IOS10开启广告限制就追踪不到idfa的问题</p><p>缺点:SimulateIDFA分两部分,前16位是在系统升级的时候才会变化,后16位用户的某些行为可能会导致值变化(例如:重启手机、修改设备名称、修改手机本地语言),意思就是系统升级,修改设备名称等都会改变</p><p>github下载地址:<a href="https://github.com/youmi/SimulateIDFA" target="_blank">https://github.com/youmi/SimulateIDFA</a></p><p>从github下载源码,把头文件SimulateIDFA.h和SimulateIDFA.m引入工程</p><pre class="prettyprint lang-cpp linenums">#import&nbsp;&quot;SimulateIDFA.h&quot;

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,如下代码:</p><pre class="prettyprint lang-cpp linenums">CFUUIDRef&nbsp;cfuuid&nbsp;=&nbsp;CFUUIDCreate(kCFAllocatorDefault);NSString&nbsp;*cfuuidString&nbsp;=&nbsp;(NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault,&nbsp;cfuuid));</pre><p>
获得的这个CFUUID值系统并没有存储。每次调用CFUUIDCreate,系统都会返回一个新的唯一标示符。如果你希望存储这个标示符,那么需要自己将其存储到NSUserDefaults, Keychain, Pasteboard或其它地方。</p><h3>2.2、UDID(该函数已经被移除)</h3><p>
在之前的版本中是可用的,但是在iOS5以及之后的版本中,以及被弃用了。虽然,这个UDID用得很广泛,但是,不得不说的是,它在慢慢的远离开发者,不能在考虑使用UDID了。至于这个标示符是转为私有方法,或者完全从以后的iOS版本中移除,还有待观察。不过,这个UDID在部署企业级签名程序时,非常方便。获取UDID的方法如下:</p><pre class="prettyprint linenums">NSString&nbsp;*udid&nbsp;=&nbsp;[[UIDevice&nbsp;currentDevice]&nbsp;uniqueIdentifier];</pre><p>
示例: bb4d786633053a0b9c0da20d54ea7e38e8776da4</p><h3>2.3、OpenUDID(在ios7以上已经作废)</h3><p>
在iOS 5发布时,uniqueIdentifier被弃用了,这引起了广大开发者需要寻找一个可以替代UDID,并且不受苹果控制的方案。由此OpenUDID成为了当时使用最广泛的开源UDID替代方案。OpenUDID在工程中实现起来非常简单,并且还支持一系列的广告提供商。</p><pre class="prettyprint linenums">NSString&nbsp;*openUDID&nbsp;=&nbsp;[OpenUDID&nbsp;value];</pre><p>
OpenUDID利用了一个非常巧妙的方法在不同程序间存储标示符 — 在粘贴板中用了一个特殊的名称来存储标示符。通过这种方法,别的程序(同样使用了OpenUDID)知道去什么地方获取已经生成的标示符(而不用再生成一个新的)。</p><p>
之前已经提到过,在将来,苹果将开始强制使用advertisingIdentifier 或identifierForVendor。如果这一天到来的话,即使OpenUDID看起来是非常不错的选择,但是你可能不得不过渡到苹果推出的方法。</p><p>
示例: 0d943976b24c85900c764dd9f75ce054dc5986ff</p><h3>2.4、MAC+MD5获取(ios7之后已经作废)</h3><p>从iOS7开始,获取MAC地址的方法统一返回02:00:00:00:00:00,所以使用MAC+MD5方法已无意义</p><h2>三、持久化保存状态</h2><p>因为一直不变的UDID已经被苹果移除,所有标志符是会因为操作改变的,这里总结下用户操作手机是否会修改保存状态,值是否会变,</p><p>√表示值不会变,×标识值会变,?表示未测试</p><table><tbody><tr class="firstRow"><td width="71" valign="top"><br/></td><td width="71" valign="top" style="word-break: break-all;">启动程序</td><td width="71" valign="top" style="word-break: break-all;">后台返回</td><td width="71" valign="top" style="word-break: break-all;">重置广告标志符</td><td width="71" valign="top" style="word-break: break-all;">重新安装程序</td><td width="71" valign="top" style="word-break: break-all;">重启手机</td><td width="71" valign="top" style="word-break: break-all;">系统还原</td><td width="71" valign="top" style="word-break: break-all;">升级系统</td><td width="71" valign="top" style="word-break: break-all;">重装系统</td></tr><tr><td width="71" valign="top" style="word-break: break-all;">UDID(已作废)</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top">√</td><td width="71" valign="top">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td></tr><tr><td width="71" valign="top" style="word-break: break-all;">mac+md5(已作废)</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td></tr><tr><td width="71" valign="top" style="word-break: break-all;"><p>CFUUID<br/></p></td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">×</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">NSUUID</td><td valign="top" colspan="1" rowspan="1">×</td><td valign="top" colspan="1" rowspan="1">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td></tr><tr><td width="71" valign="top" style="word-break: break-all;">IDFA</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td></tr><tr><td width="71" valign="top" style="word-break: break-all;">IDFV</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">√(?)</td><td width="71" valign="top" style="word-break: break-all;">×</td></tr><tr><td width="71" valign="top" style="word-break: break-all;">OpenUDID(已作废)</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td></tr><tr><td width="71" valign="top" style="word-break: break-all;">SecureUDID</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top">×</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td><td width="71" valign="top" style="word-break: break-all;">√</td><td width="71" valign="top" style="word-break: break-all;">×</td></tr><tr><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">SimulateIDFA</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">√</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">√</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">√</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">√</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td><td valign="top" colspan="1" rowspan="1">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td><td valign="top" colspan="1" rowspan="1" style="word-break: break-all;">×</td></tr></tbody></table><h2>四、总结</h2><p>SecureUDID是一个第三方库,是一个开源的基于沙箱机制的解决方案,是虚拟出来的,所以不能确保不同设备上的UDID不同,用户可以选择阻止SecureUDID收集UDID信息,如果用户备份A设备系统并将其恢复到B设备,则B设备将得到A设备的UDID,删除程序并清空剪切板可能会导致丢失,非苹果原生的API,所以使用的话还是最好使用idfa和idfv。</p><p>idfa在用户重置广告标志符的时候会变化,所以可以把第一次生成的idfa存放到keychain里面,以后就直接读取keychain值就可以了,这样就能避免用户重置广告标志符造成idfa的变化,而keychain的值只有在用户重置系统的时候才会删除,所以很适合用idfa+keychain的方案,keychain的使用方法《<a href="http://www.hudongdong.com/ios/356.html" target="_blank">IOS的keychain的三种使用方法</a>》</p><h2>五、参考文章</h2><ul class=" list-paddingleft-2" style="list-style-type: disc;"><li><p><a href="http://blog.it985.com/13570.html" target="_blank">iOS如何获取IDFA【原创】</a></p></li><li><p><a href="http://www.cocoachina.com/industry/20130422/6040.html" target="_blank">iOS唯一标示符引导</a></p></li><li><p><a href="http://www.2cto.com/kf/201506/412644.html" target="_blank">[iOS]iOS8可用的识别用户方式(idfa、UUID、idfv)</a></p></li><li><p><a href="http://blog.csdn.net/kaitiren/article/details/48087959" target="_blank">iOS唯一表示符获取方案</a></p></li><li><p><a href="http://www.oschina.net/p/secureudid" target="_blank">UDID 解决方案SecureUDID</a></p></li></ul>
Last modification:January 1st, 1970 at 08:00 am
如果觉得我的文章对你有用,请随意打赏: ☞已打赏列表