一:
1.1 :UDID
簡(jiǎn)介:UDID的全稱是Unique Device Identifier,顧名思義,它就是蘋果IOS設(shè)備的唯一識(shí)別碼,它由40個(gè)字符的字母和數(shù)字組成。在很多需要限制一臺(tái)設(shè)備一個(gè)賬號(hào)的應(yīng)用中經(jīng)常會(huì)用到。在iOS5中可以獲取到設(shè)備的UDID,iOS7中已經(jīng)完全的禁用了它。iOS7之前的使用了的app如果在iOS7上運(yùn)行,它不會(huì)返回設(shè)備的UDID,而是會(huì)返回一串字符串,以FFFFFFFF開頭,跟著identifierForVendor的十六進(jìn)制值。
獲?。?code>[[UIDevice currentDevice] uniqueIdentifier]
廢棄:iOS6
1.2 IDFV
簡(jiǎn)介:iOS 6.0系統(tǒng)新增用于替換uniqueIdentifier的接口。是給Vendor標(biāo)識(shí)用戶用的,每個(gè)設(shè)備在所屬同一個(gè)Vender的應(yīng)用里,都有相同的值。其中的Vender是指應(yīng)用提供商,但準(zhǔn)確點(diǎn)說,是通過BundleID的DNS反轉(zhuǎn)的前兩部分進(jìn)行匹配,如果相同就是同一個(gè)Vender,例如對(duì)于com.somecompany.appone,com.somecompany.apptwo這兩個(gè)BundleID來說,就屬于同一個(gè)Vender,共享同一個(gè)idfv的值。和idfa不同的是,idfv的值是一定能取到的,所以非常適合于作為內(nèi)部用戶行為分析的主id,來標(biāo)識(shí)用戶,替代OpenUDID。如果用戶將屬于此Vender的所有App卸載,則idfv的值會(huì)被重置,即再重裝此Vender的App,idfv的值和之前不同。
獲?。?code>[[[UIDevice currentDevice] identifierForVendor] UUIDString]
適用:iOS6.0+
例子:95955F33-BFBD-48BA-A630-866D2DAE482D
1.3 IDFA
簡(jiǎn)介:廣告標(biāo)示符,適用于對(duì)外:例如廣告推廣,換量等跨應(yīng)用的用戶追蹤等。但如果用戶完全重置系統(tǒng)((設(shè)置程序 -> 通用 -> 還原 -> 還原位置與隱私) ,這個(gè)廣告標(biāo)示符會(huì)重新生成。另外如果用戶明確的還原廣告(設(shè)置程序-> 通用 -> 關(guān)于本機(jī) -> 廣告 -> 還原廣告標(biāo)示符) ,那么廣告標(biāo)示符也會(huì)重新生成。注意:如果程序在后臺(tái)運(yùn)行,此時(shí)用戶“還原廣告標(biāo)示符”,然后再回到程序中,此時(shí)獲取廣 告標(biāo)示符并不會(huì)立即獲得還原后的標(biāo)示符。必須要終止程序,然后再重新啟動(dòng)程序,才能獲得還原后的廣告標(biāo)示符。在同一個(gè)設(shè)備上的所有App都會(huì)取到相同的值,是蘋果專門給各廣告提供商用來追蹤用戶而設(shè)的,
用戶可以在 設(shè)置 -> 隱私 -> 廣告追蹤 里重置此id的值,或限制此id的使用。
獲?。?code>[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
適用:iOS6.0+
例子:9C287922-EE26-4501-94B5-DDE6F83E1475
1.4 MAC地址
簡(jiǎn)介:MAC地址在網(wǎng)絡(luò)上用來區(qū)分設(shè)備的唯一性,接入網(wǎng)絡(luò)的設(shè)備都有一個(gè)MAC地址,他們肯定都是不同的,是唯一的。一部iPhone上可能有多個(gè)MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一個(gè)WIFI的,因此只需獲取WIFI的MAC地址就好了,也就是en0的地址。MAC地址就如同我們身份證上的身份證號(hào)碼,具有全球唯一性。但在iOS7之后,如果請(qǐng)求Mac地址都會(huì)返回一個(gè)固定值。
注意:由于idfa會(huì)出現(xiàn)取不到的情況,故絕不可以作為業(yè)務(wù)分析的主id,來識(shí)別用戶。 比如開啟限制廣告追蹤
廢棄:iOS7.0+
獲?。?/p>
- (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) {
printf("Error: if_nametoindex error/n");
return NULL;
}
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];
}
1.5 KeyChain
簡(jiǎn)介:iOS整個(gè)系統(tǒng)有一個(gè)KeyChain,每個(gè)程序都可以往KeyChain中記錄數(shù)據(jù),而且只能讀取到自己程序記錄在KeyChain中的數(shù)據(jù)。而且就算我們程序刪除掉,系統(tǒng)經(jīng)過升級(jí)以后再安裝回來,依舊可以獲取到與之前一致的UDID(系統(tǒng)還原、刷機(jī)除外)。因此我們可以將UUID的字符串存儲(chǔ)到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;
}
1.6 AppleAccount
簡(jiǎn)介:雖然蘋果在iOS6中禁用了獲取uuid的方式,但是只要你研究下就知道這個(gè)API只是私有化了,使用私有API還是可以獲取設(shè)備的uuid。但是這個(gè)方面也面臨著風(fēng)險(xiǎn):比如API變更以及AppStore審核問題,但是在越獄設(shè)備上你還是可以盡情享用的。
類:AADeviceInfo(dump出頭文件)
@class NSObject<OS_dispatch_semaphore>, APSConnection, NSData;
@interface AADeviceInfo : NSObject {
APSConnection *_apsConnection;
BOOL _tokenDone;
NSData *_token;
NSObject<OS_dispatch_semaphore> *_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]
使用方法:在項(xiàng)目中將真機(jī)上的AppleAccount.framework框架導(dǎo)出,引入Xcode工程中,利用runtime或者直接使用該類就行。
(細(xì)節(jié)補(bǔ)充:導(dǎo)出AppleAccount.framework后,進(jìn)入AppleAccount.framework的根目錄,新建Headers文件夾,然后將dump出的頭文件放在Headers目錄,就可以像引用第三方framework一樣在項(xiàng)目中使用)
二: iOS10 獲取idfa的坑
ios10更新之后一旦開啟了 設(shè)置->隱私->廣告->限制廣告跟蹤之后 獲取到的idfa將會(huì)是一串00000 跟mac地址一個(gè)尿性,而且每次開啟在關(guān)閉之后 相應(yīng)的idfa也會(huì)重新生成,相當(dāng)于還原了一次廣告標(biāo)識(shí)符。
獲取idfa的方法:
#import <AdSupport/AdSupport.h>
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
ios10 之后最好加一個(gè)判斷[[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled] 返回值是BOOL值 如果返回的YES說明沒有 “開啟限制廣告跟蹤”,可以獲取到正確的idfa 如果返回的是NO,說明等待你的就是一串00000000000
三: IDFA的前世今生
為了保護(hù)用戶隱私,早在2012年就不再允許其生態(tài)中的玩家獲取用戶的唯一標(biāo)識(shí)符,但是商家在移動(dòng)端打廣告的時(shí)候又希望能監(jiān)控到每一次廣告投放的效果,因此,蘋果想出了折中的辦法,就是提供另外一套和硬件無關(guān)的標(biāo)識(shí)符,用于給商家監(jiān)測(cè)廣告效果,同時(shí)用戶可以在設(shè)置里改變這串字符,導(dǎo)致商家沒有辦法長(zhǎng)期跟蹤用戶行為。這個(gè)就叫做廣告標(biāo)識(shí)符(IDFA),設(shè)置路徑是“設(shè)置->隱私->廣告->還原廣告標(biāo)識(shí)符”,如下圖所示(iOS9)
因?yàn)檫@個(gè)IDFA不是唯一的,所以一開始行業(yè)內(nèi)是很抵觸的,想方設(shè)法去獲取UDID(跟手機(jī)綁定的,用戶不能改變),引起蘋果大怒,在13年時(shí)禁止所有App獲取UDID,否則不能上架,也正因?yàn)槠渖鷳B(tài)的封閉性,才能迫使大家就范。雖然IDFA不是唯一的,但是畢竟勝過沒有,況且也沒有多少用戶會(huì)去更改。因此,經(jīng)過幾番爭(zhēng)斗,IDFA已經(jīng)成為通用的iPhone用戶標(biāo)識(shí)符,這個(gè)過程分為6個(gè)階段,我用下圖總結(jié)
然而在今年iOS10推出后,廣告界大為震驚,因?yàn)樘O果推出了“限制廣告追蹤”功能,設(shè)置的路徑和iOS9一致??赡芗?xì)心的人注意到了,這個(gè)功能并非iOS10獨(dú)有啊,在之前的版本中也一樣存在。不過經(jīng)過實(shí)際的測(cè)試,在iOS10之前,即使用戶打開這個(gè)功能,商家一樣可以獲取IDFA,只不過與之前的不一樣了,每次切換這個(gè)開關(guān)與點(diǎn)擊“還原廣告標(biāo)識(shí)符”的效果一樣。而iOS10就不一樣了,當(dāng)用戶打開這個(gè)功能后,商家只能獲取到一連串無意義的0,這才是廣告界大為震驚的原因所在
四: iOS10 IDFA 獲取不到問題解決
4.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
4.2 SimulateIDFA
SimulateIDFA是根據(jù)一堆設(shè)備信息(每個(gè)app獲取的值都是一樣的)生成的一個(gè)MD5值。用于標(biāo)志不同設(shè)備。
#######4.2.1 使用:
CoreTelephony.framework
https://github.com/youmi/SimulateIDFA (下載代碼)
在需要獲取 SimulateIDFA的地方調(diào)用代碼:
NSString *simulateIDFA = [SimulateIDFA createSimulateIDFA];
simulateIDFA的格式跟IDFA的格式一樣
626363D0-90D4-06BF-C281-384E4E69D3E2
#######4.2.2 生成原理
生成的MD5值分兩部分。
以 626363D0-90D4-06BF-C281-384E4E69D3E2 為例:
前16位626363D0-90D4-06BF是由比較穩(wěn)定的參數(shù)組合獲得,這前16位只有在系統(tǒng)升級(jí)的情況下才會(huì)變。
后16位C281-384E4E69D3E2 由 一些比較容易被改變的參數(shù)組合生成,比較常見的值變化情況是系統(tǒng)重新啟動(dòng)。
- 1: 參與前16位計(jì)算的參數(shù)有:
系統(tǒng)版本(9.3.2)、
硬件信息(N53AP,iPhone6,2,中國(guó)移動(dòng)46002,1048576000)、
coreServices文件創(chuàng)建更新時(shí)間(2015-08-07 23:53:00 +0000,2016-06-07 23:53:09 +0000),
系統(tǒng)容量(12266725376)
這里有一些信息是升級(jí)的時(shí)候會(huì)變的,系統(tǒng)版本、coreServices文件創(chuàng)建更新時(shí)間、系統(tǒng)容量
- 2: 參與后16位計(jì)算的參數(shù)有:
系統(tǒng)開機(jī)時(shí)間(1473301191去掉后面的4位數(shù) 147330)、
國(guó)家代碼(CN)、
本地語言(zh-Hans-CN)、
設(shè)備名稱(XXXX)
這里的參數(shù)都是比較容易變化的,系統(tǒng)重啟離上次重啟有10000秒的話會(huì)變,其他參數(shù)在設(shè)置里面可以修改
4.3 SimulateIDFA與OpenIDFA對(duì)比
OpenIDFA 是 Yann Lechelle的一個(gè)開源庫(kù)。同是IDFA的替換方案
#######4.3.1 生成的ID重復(fù)的概率對(duì)比
假設(shè)一個(gè)情況。一天內(nèi)某個(gè)國(guó)家有10000000(1千萬)臺(tái)相同型號(hào)的設(shè)備升級(jí)到同一個(gè)系統(tǒng)。
1: SimulateIDFA
一天內(nèi)這個(gè)算法可能的值計(jì)算,24x3600(文件創(chuàng)建時(shí)間,單位秒)x 10(文件最后修改時(shí)間假設(shè)誤差在10秒)x 10000000(系統(tǒng)容量誤差范圍)x 1000000(設(shè)備名稱范圍,這里假設(shè)的是每100臺(tái)就有2個(gè)重復(fù))=8640000000000000000。
設(shè)備a的值為 K,那么設(shè)備b的值同為K的可能性為:1/8640000000000000000. 總共有10000000臺(tái)設(shè)備。因此,這10000000設(shè)備中有與a設(shè)備的值同為K的可能性為1/8640000000000000000 x 10000000 = 1/864000000000。2: OpenIDFA
先看一下OpenIDFA的生成算法,OpenIDFA是對(duì)下面的參數(shù)組合進(jìn)行MD5.
系統(tǒng)開機(jī)時(shí)間(1473241127 減去后四位值為 147324)、系統(tǒng)容量(29230571520)、
系統(tǒng)版本(9.3.4)、機(jī)型(N78AP,iPod5,1)、國(guó)家代碼(CN)、本地語言(zh-Hans-CN)、
一些預(yù)裝的App(由于用的是canOpenURL這個(gè)接口,iOS9就已經(jīng)廢了)、時(shí)區(qū)(Asia/Shanghai)、
當(dāng)天時(shí)間(160804, 16年8月4日,這個(gè)值是他每天值都會(huì)變化的原因)
一天內(nèi)可能的值為系統(tǒng)容量的誤差(10000000)。 ps: 系統(tǒng)啟動(dòng)時(shí)間在這種情況下對(duì)重復(fù)率的降低沒起到作用,因?yàn)镺penIDFA是減去了系統(tǒng)啟動(dòng)時(shí)間的后4位來計(jì)算的。同理當(dāng)天時(shí)間也是。
設(shè)備a的值為 K,那么設(shè)備b的值同為K的可能性為: 1/10000000. 總共有 10000000臺(tái)設(shè)備。因此,這10000000設(shè)備中有與a設(shè)備的值同為K的可能性為 1/10000000 x 10000000 = 1
#######4.3.2 時(shí)效性對(duì)比
1: OpenIDFA
每天獲取的值都不一樣2: SimulateIDFA
SimulateIDFA分兩部分,前16位是在系統(tǒng)升級(jí)的時(shí)候才會(huì)變化,后16位用戶的某些行為可能會(huì)導(dǎo)致值變化(例如:重啟手機(jī)、修改設(shè)備名稱、修改手機(jī)本地語言)
#######4.3.3 總結(jié):
OpenIDFA 有一些限制,生成的IDFA會(huì)每天變化,在一些極端條件下重復(fù)率比較高。 SimulateIDFA在這方面有更好的表現(xiàn)
五: iOS 提交審核之IDFA的介紹
在我們提交程序進(jìn)行審核的時(shí)候,最后會(huì)有兩個(gè)選項(xiàng)供我們選擇,一個(gè)是Export Compliance(該選項(xiàng)主要是說你的程序設(shè)計(jì)是否使用了加密,我一般上傳的時(shí)候都選擇No,這個(gè)根據(jù)你項(xiàng)目實(shí)際情況來選擇.);另一個(gè)就是Advertising Identifier(廣告標(biāo)示符).
#######5.1 檢查是否使用IDFA
檢查我們項(xiàng)目中是否使用廣告標(biāo)示符,其實(shí)就是查看我們-
1: framework中是否有個(gè)叫做
AdSupport.framework的框架;2: 如果檢查framework沒有,可能是我們接入的第三方里面有,用以下方法檢查第三方中是否包含有IDFA版本;
(1)打開終端cd到要檢查的文件的目錄;
(2)執(zhí)行命令:grep -r advertisingIdentifier .(注意別少了點(diǎn));
分別對(duì)我的項(xiàng)目中和ShareSDK里面進(jìn)行了檢查:
#######5.2 各個(gè)選項(xiàng)的含義
1、 在 App 內(nèi)投放廣告服務(wù)應(yīng)用中的廣告。
如果你的應(yīng)用中集成了廣告的時(shí)候,你需要勾選這一項(xiàng)。2、 將此 App 安裝歸因于先前投放的特定廣告
跟蹤廣告帶來的安裝。如果你使用了第三方的工具來跟蹤廣告帶來的激活以及一些其他事件,但是應(yīng)用里并沒有展示廣告你需要勾選這一項(xiàng)。3、將此 App 中發(fā)生的操作歸因于先前投放的特定廣告
跟蹤廣告帶來的用戶的后續(xù)行為。如果你使用了第三方的工具來跟蹤廣告帶來的激活以及一些其他事件。4、 iOS 中的“限制廣告
跟蹤”設(shè)置這一項(xiàng)下的內(nèi)容其實(shí)就是對(duì)你的應(yīng)用使用 IDFA 的目的做下確認(rèn),只要你選擇了采集 IDFA,那么這一項(xiàng)都是需要勾選的。
#######5.3 總結(jié)
1: 如果你的應(yīng)用里只是集成了廣告,不追蹤廣告帶來的激活行為,那么選擇1和4;
2: 如果你的應(yīng)用沒有廣告,而又獲取了IDFA。建議選擇2和4;
參考資料:
http://www.itdecent.cn/p/e222ff751a97
ios10 獲取idfa的坑
手機(jī)更新到Ios10后獲取的idfa全是0?
http://www.cnblogs.com/zxykit/p/5320259.html
iOS10 IDFA 獲取不到問題解決
http://www.ithao123.cn/content-8688001.html
http://blog.csdn.net/kaitiren/article/details/52562556
iOS 提交審核之IDFA的介紹