19非Ad应用,模拟获取设备的 idfa

0前言

像 UUID、UDID、IDFV, 这些比较老的唯一标识, 苹果早已经对外关闭,开发者是拿不到的, 详情不赘述
开发的过程中, 需要拿到设备的唯一标识或者是用户登录的唯一标识, 还是很重要的, 因为服务端会根据你的这个唯一的东西, 给你生成唯一的账号或者标识, 包括后续的"追踪定位"、进程异常、日志查询等, 都会很有很大的帮助

1.KeyChain

简介:iOS整个系统有一个KeyChain,每个程序都可以往KeyChain中记录数据,而且只能读取到自己程序记录在KeyChain中的数据。而且就算我们程序删除掉,系统经过升级以后再安装回来,依旧可以获取到与之前一致的UDID(系统还原、刷机除外)。因此我们可以将UUID的字符串存储到KeyChain中,然后下次直接从KeyChain获取UUID字符串。(本示例中使用KeychainItemWrapper工具类)

获取
+ (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;
}

2.AppleAccount

简介:虽然苹果在iOS6中禁用了获取uuid的方式,但是只要你研究下就知道这个API只是私有化了,使用私有API还是可以获取设备的uuid。但是这个方面也面临着风险:比如API变更使用以及AppStore审核问题,导致上架不了或者下架
但是在越狱设备上你还是可以尽情享用的

类:AADeviceInfo(dump出头文件)

@class NSObject, APSConnection, NSData;

@interface AADeviceInfo : NSObject {

APSConnection *_apsConnection;

BOOL _tokenDone;

NSData *_token;

NSObject *_tokenSema;

}

+ (id)userAgentHeader;

+ (id)signatureWithDictionary:(id)arg1;

+ (id)apnsToken;

+ (id)serialNumber;

+ (id)clientInfoHeader;

+ (id)appleIDClientIdentifier;

+ (id)productVersion;

+ (id)osVersion;

+ (id)udid;

+ (id)infoDictionary;

- (id)wifiMacAddress;

- (id)regionCode;

- (id)deviceClass;

- (id)osName;

- (id)productType;

- (id)apnsToken;

- (id)serialNumber;

- (id)deviceInfoDictionary;

- (id)appleIDClientIdentifier;

- (id)productVersion;

- (id)osVersion;

- (id)udid;

- (id)init;

- (void).cxx_destruct;

- (id)buildVersion;

@end

获取:

[AADeviceInfo udid]

使用方法:在项目中将真机上的AppleAccount.framework框架导出,引入Xcode工程中,利用runtime或者直接使用该类就行。
(细节补充:导出AppleAccount.framework后,进入AppleAccount.framework的根目录,新建Headers文件夹,然后将dump出的头文件放在Headers目录,就可以像引用第三方framework一样在项目中使用)

3.IDFA

简介:广告标示符,适用于对外:例如广告推广,换量等跨应用的用户追踪等。但如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。
注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广 告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。在同一个设备上的所有App都会取到相同的值,是苹果专门给各广告提供商用来追踪用户而设的,
用户可以在 设置 -> 隐私 -> 广告追踪 里重置此id的值,或限制此id的使用。

获取:

[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

适用:iOS6.0+

例子:9C287922-EE26-4501-94B5-DDE6F83E1475

4.IDFA 的前世今生

为了保护用户隐私,早在2012年就不再允许其生态中的玩家获取用户的唯一标识符,但是商家在移动端打广告的时候又希望能监控到每一次广告投放的效果,因此,苹果想出了折中的办法,就是提供另外一套和硬件无关的标识符,用于给商家监测广告效果,同时用户可以在设置里改变这串字符,导致商家没有办法长期跟踪用户行为。这个就叫做广告标识符(IDFA),设置路径是“设置->隐私->广告->还原广告标识符”,如下图所示(iOS9)

19非Ad应用,模拟获取设备的 idfa_第1张图片
image.png

因为这个IDFA不是唯一的,所以一开始行业内是很抵触的,想方设法去获取UDID(跟手机绑定的,用户不能改变),引起苹果大怒,在13年时禁止所有App获取UDID,否则不能上架,也正因为其生态的封闭性,才能迫使大家就范。虽然IDFA不是唯一的,但是毕竟胜过没有,况且也没有多少用户会去更改。因此,经过几番争斗,IDFA已经成为通用的iPhone用户标识符,这个过程分为6个阶段,我用下图总结

19非Ad应用,模拟获取设备的 idfa_第2张图片
image.png

然而在今年iOS10推出后,广告界大为震惊,因为苹果推出了“限制广告追踪”功能,设置的路径和iOS9一致。可能细心的人注意到了,这个功能并非iOS10独有啊,在之前的版本中也一样存在。不过经过实际的测试,在iOS10之前,即使用户打开这个功能,商家一样可以获取IDFA,只不过与之前的不一样了,每次切换这个开关与点击“还原广告标识符”的效果一样。而iOS10就不一样了,当用户打开这个功能后,商家只能获取到一连串无意义的0,这才是广告界大为震惊的原因所在

19非Ad应用,模拟获取设备的 idfa_第3张图片
image.png

5. iOS10获取idfa的坑

iOS10更新之后一旦开启了 设置->隐私->广告->限制广告跟踪之后 获取到的idfa将会是一串00000 跟mac地址一个尿性,而且每次开启在关闭之后 相应的idfa也会重新生成,相当于还原了一次广告标识符。

19非Ad应用,模拟获取设备的 idfa_第4张图片
广告标识符.png

获取idfa的方法:

#import 

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

iOS10 之后最好加一个判断[[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled] 返回值是BOOL值 如果返回的YES说明没有 “开启限制广告跟踪”,可以获取到正确的idfa 如果返回的是NO,说明等待你的就是一串00000000000

6.非Ad,模拟获取设备的 idfa

6.1 限制广告跟踪背景

中文说明文档

Important

In iOS 10.0 and later, the value of advertisingIdentifier is all 
zeroes when the user has limited ad tracking.

也就是说在iOS10上,用户如果开启了 限制广告跟踪 , 获取的idfa将是一串00000000-0000-0000-0000-000000000000

6.2 SimulateIDFA

SimulateIDFA是根据一堆设备信息(每个app获取的值都是一样的)生成的一个MD5值。用于标志不同设备。

6.2.1 使用

先去github下载代码

https://github.com/youmi/SimulateIDFA 

调用的方法

NSString *simulateIDFA = [SimulateIDFA createSimulateIDFA];

simulateIDFA的格式跟IDFA的格式一样

626363D0-90D4-06BF-C281-384E4E69D3E2
6.2.2 生成原理

生成的类似MD5值一样, 保持唯一性, 分两部分。

以 626363D0-90D4-06BF-C281-384E4E69D3E2 为例:

前16位626363D0-90D4-06BF是由比较稳定的参数组合获得,这前16位只有在系统升级的情况下才会变。

后16位C281-384E4E69D3E2 由 一些比较容易被改变的参数组合生成,比较常见的值变化情况是系统重新启动。

  • 1: 参与前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文件创建更新时间、系统容量

  • 2: 参与后16位计算的参数有:
系统开机时间(1473301191去掉后面的4位数 147330)、
国家代码(CN)、
本地语言(zh-Hans-CN)、
设备名称(XXXX)

这里的参数都是比较容易变化的,系统重启离上次重启有10000秒的话会变,其他参数在设置里面可以修改

6.2.3 SimulateIDFA与OpenIDFA对比

OpenIDFA 是 Yann Lechelle的一个开源库。同是IDFA的替换方案

假设一个情况。一天内某个国家有10000000(1千万)台相同型号的设备升级到同一个系统。
1: SimulateIDFA一天内这个算法可能的值计算, 24x3600
(文件创建时间,单位秒)x 10
(文件最后修改时间假设误差在10秒)x 10000000
(系统容量误差范围)x 1000000
(设备名称范围,这里假设的是每100台就有2个重复)= 8640000000000000000
。设备a的值为 K,那么设备b的值同为K的可能性为: 1/8640000000000000000
. 总共有 10000000
台设备。因此,这10000000设备中有与a设备的值同为K的可能性为 1/8640000000000000000 x 10000000 = 1/864000000000。

A. 生成的ID重复的概率对比

假设一个情况。一天内某个国家有10000000(1千万)台相同型号的设备升级到同一个系统。

  • 1: SimulateIDFA一天内这个算法可能的值计算, 24x3600
    (文件创建时间,单位秒)x 10
    (文件最后修改时间假设误差在10秒)x 10000000
    (系统容量误差范围)x 1000000
    (设备名称范围,这里假设的是每100台就有2个重复)= 8640000000000000000
    。设备a的值为 K,那么设备b的值同为K的可能性为: 1/8640000000000000000
    . 总共有 10000000
    台设备。因此,这10000000设备中有与a设备的值同为K的可能性为 1/8640000000000000000 x 10000000 = 1/864000000000。

  • 2: OpenIDFA
    先看一下OpenIDFA的生成算法,OpenIDFA是对下面的参数组合进行MD5.

1.系统开机时间(1473241127 减去后四位值为 147324)、系统容量(29230571520)、
2.系统版本(9.3.4)、机型(N78AP,iPod5,1)、国家代码(CN)、本地语言(zh-Hans-CN)、
3.一些预装的App(由于用的是canOpenURL这个接口,iOS9就已经废了)、时区(Asia/Shanghai)、
4.当天时间(160804, 16年8月4日,这个值是他每天值都会变化的原因)

一天内可能的值为系统容量的误差(10000000)。 ps: 系统启动时间在这种情况下对重复率的降低没起到作用,因为OpenIDFA是减去了系统启动时间的后4位来计算的。同理当天时间也是。

设备a的值为 K,那么设备b的值同为K的可能性为: 1/10000000. 总共有 10000000台设备。因此,这10000000设备中有与a设备的值同为K的可能性为 1/10000000 x 10000000 = 1

B.时效性对比
  • 1: OpenIDFA
    每天获取的值都不一样

  • 2: SimulateIDFA
    SimulateIDFA分两部分,前16位是在系统升级的时候才会变化,后16位用户的某些行为可能会导致值变化(例如:重启手机、修改设备名称、修改手机本地语言)

6.2.4 总结:

OpenIDFA 有一些限制,生成的IDFA会每天变化,在一些极端条件下重复率比较高。 SimulateIDFA在这方面有更好的表现

7.iOS 提交审核之IDFA的介绍

7.1 提交审核

在我们提交程序进行审核的时候,最后会有两个选项供我们选择,一个是Export Compliance(该选项主要是说你的程序设计是否使用了加密,我一般上传的时候都选择No,这个根据你项目实际情况来选择.);另一个就是Advertising Identifier(广告标示符).

19非Ad应用,模拟获取设备的 idfa_第5张图片
image.png
19非Ad应用,模拟获取设备的 idfa_第6张图片
image.png
各个选项的含义

1、 在 App 内投放广告服务应用中的广告。如果你的应用中集成了广告的时候,你需要勾选这一项。

2、 将此 App 安装归因于先前投放的特定广告跟踪广告带来的安装。如果你使用了第三方的工具来跟踪广告带来的激活以及一些其他事件,但是应用里并没有展示广告你需要勾选这一项。

3、将此 App 中发生的操作归因于先前投放的特定广告跟踪广告带来的用户的后续行为。如果你使用了第三方的工具来跟踪广告带来的激活以及一些其他事件。

4、 iOS 中的“限制广告跟踪”设置这一项下的内容其实就是对你的应用使用 IDFA 的目的做下确认,只要你选择了采集 IDFA,那么这一项都是需要勾选的。

总结

1: 如果你的应用里只是集成了广告,不追踪广告带来的激活行为,那么选择1和4;

2: 如果你的应用没有广告,而又获取了IDFA。建议选择2和4;

7.2检查是否使用IDFA

检查我们项目中是否使用广告标示符,其实就是查看我们-

  • 1: framework中是否有个叫做AdSupport.framework的框架;

  • 2: 如果检查framework没有,可能是我们接入的第三方里面有,用以下方法检查第三方中是否包含有IDFA版本;

(1)打开终端cd到要检查的文件的目录;
(2)执行命令:grep -r advertisingIdentifier .(注意别少了点);

分别对我的项目中和ShareSDK里面进行了检查:

image.png

总结写在后面

对于获取设备的唯一标识, 是一件众说纷纭的事情
因为从用户来角度说, 为了隐私和安全, 肯定不希望有任何数据泄露
但是从开发者(前端和服务端)角度来说, 拿到这个标识, 用于追踪数据和操作日志, 又是多么的重要的, 能快速定位到问题.
因为本人任职游戏研发, 有游客这个功能, 信息量是很少的, 根据 idfa 就能定位到很多问题, 总之
如果你的应用是广告类应用, 放心大胆的去获取苹果的 idfa 就可以
如果你的应用是非广告类的应该, 建议去用模拟 idfa 这个算法, 知名度和认可度较高,总之看需求

你可能感兴趣的:(19非Ad应用,模拟获取设备的 idfa)