IDFA全稱是identifier for advertisers,在了解IDFA之前埋哟,我們需要了解另一個概念,叫UDID郎汪。UDID是蘋果設(shè)備設(shè)備的唯一設(shè)備識別符赤赊,早期的時候移動廣告商往往需要通過UDID用來識別用戶闯狱,并對用戶活動進行跟蹤,從而投放廣告
在iOS應(yīng)用早期抛计,UDID被第三方應(yīng)用開發(fā)者和網(wǎng)絡(luò)廣告商用來收集用戶數(shù)據(jù)哄孤,可以用來關(guān)聯(lián)地址、記錄應(yīng)用使用習(xí)慣……以便推送精準(zhǔn)廣告吹截。不少用戶也對此表示蘋果侵犯消費者隱私瘦陈,蘋果為了保護用戶隱私,早在2012年就不再允許其生態(tài)中的APP獲取用戶的唯一標(biāo)識符饭弓,但是廣告主希望在移動端打廣告的時候又希望能監(jiān)控到每一次廣告投放的效果双饥,因此,蘋果想出了折中的辦法弟断,就是提供另外一套和硬件無關(guān)的標(biāo)識符咏花,用于給商家監(jiān)測廣告效果,同時用戶可以在設(shè)置里改變這串字符阀趴,導(dǎo)致商家沒有辦法長期跟蹤用戶行為昏翰。這個就叫做廣告標(biāo)識符(IDFA),設(shè)置路徑是“設(shè)置->隱私->廣告->還原廣告標(biāo)識符”刘急,這個IDFA是可以關(guān)閉和修改的棚菊,據(jù)某知名檢測機構(gòu)調(diào)研,在國內(nèi)關(guān)閉這個功能的不足1%叔汁,一旦關(guān)閉统求,廣告還能投放,但是沒辦法按照興趣等屬性去投放了
iOS設(shè)備有多少ID据块?
iOS設(shè)備ID有很多码邻,通常用到的大概有以下六個,例如UDID另假、IMEI像屋、ICCID、MEID边篮、IDFA己莺、MAC地址等,一臺蘋果手機的標(biāo)識方式很多戈轿,不同標(biāo)識方式又有不同的參數(shù)信息凌受。
隨著iOS系統(tǒng)的升級,很多設(shè)備ID蘋果禁止開發(fā)者獲取凶杖,或者給用戶諸多人性選擇空間胁艰。下面詳細說說參數(shù)的定位及用途,其中最為大家關(guān)注的就是IDFA。
UDID
UDID(UniqueDevice Identifier)是蘋果iOS設(shè)備的唯一識別碼腾么,由40個字符的字母和數(shù)字組成奈梳。移動廣告商、游戲網(wǎng)絡(luò)運營商或CP往往需要通過UDID用來識別玩家解虱、用戶攘须,并對用戶活動進行跟蹤;也經(jīng)常會用于一臺設(shè)備一個賬號功能實現(xiàn)殴泰。
iOS 6及以前系統(tǒng)是可以獲取到設(shè)備的UDID于宙,iOS 7中已經(jīng)完全的禁用。
UUID
UUID是Universally Unique Identifier的縮寫悍汛,中文意思是通用唯一識別碼捞魁。它是讓分布式系統(tǒng)中的所有元素,都能有唯一的辨識資訊离咐,而不需要透過中央控制端來做辨識資訊的指定谱俭。這樣,每個人都可以建立不與其它人沖突的 UUID宵蛀。在此情況下昆著,就不需考慮數(shù)據(jù)庫建立時的名稱重復(fù)問題。蘋果公司建議使用UUID為應(yīng)用生成唯一標(biāo)識字符串术陶。
開發(fā)者可以在應(yīng)用第一次啟動時調(diào)用一 次凑懂,然后將該串存儲起來,替代UDID來使用梧宫。但是接谨,如果用戶刪除該應(yīng)用再次安裝時,又會生成新的字符串塘匣,所以不能保證唯一識別該設(shè)備疤坝。使用UUID,就要考慮應(yīng)用被刪除后再重新安裝時的處理馆铁。一個解決的辦法是:UUID一般只生成一次,保存在iOS系統(tǒng)里面锅睛,如果應(yīng)用刪除了埠巨,重裝應(yīng)用之后它的UUID還是一樣的,除非系統(tǒng)重置 现拒。但是不能保證在以后的系統(tǒng)升級后還能用(如果系統(tǒng)保存了該信息就能用)辣垒。
MAC Address
用來表示互聯(lián)網(wǎng)上每一個站點的標(biāo)識符,采用十六進制數(shù)表示印蔬,共六個字節(jié)(48位)。其中,前三個字節(jié)是由IEEE的注冊管理機構(gòu) RA負責(zé)給不同廠家分配的代碼(高位24位)例驹,也稱為“編制上唯一的標(biāo)識符” (Organizationally Unique Identifier)捐韩,后三個字節(jié)(低位24位)由各廠家自行指派給生產(chǎn)的適配器接口,稱為擴展標(biāo)識符(唯一性)鹃锈。
MAC地址在網(wǎng)絡(luò)上用來區(qū)分設(shè)備的唯一性荤胁,接入網(wǎng)絡(luò)的設(shè)備都有一個MAC地址,他們肯定都是不同的屎债,是唯一的仅政。一部iPhone上可能有多個MAC地址,包括WIFI的盆驹、SIM的等圆丹,但是iTouch和iPad上就有一個WIFI的,因此只需獲取WIFI的MAC地址就好了躯喇,也就是en0的地址辫封。
MAC地址就如同我們身份證上的身份證號碼,具有全球唯一性玖瘸。這樣就可以非常好的標(biāo)識設(shè)備唯一性秸讹,類似與蘋果設(shè)備的UDID號,通常的用途有:1)用于一些統(tǒng)計與分析目的雅倒,利用用戶的操作習(xí)慣和數(shù)據(jù)更好的規(guī)劃產(chǎn)品璃诀;2)作為用戶ID來唯一識別用戶,可以用游客身份使用app又能在服務(wù)器端保存相應(yīng)的信息蔑匣,省去用戶名劣欢、密碼等注冊過程。
使用Mac地址生成設(shè)備的唯一標(biāo)識主要分三種:
1裁良、直接使用“MAC Address”
2凿将、使用“MD5(MAC Address)”
3、使用“MD5(Mac Address+bundle_id)”獲得“機器+應(yīng)用”的唯一標(biāo)識(bundle_id 是應(yīng)用的唯一標(biāo)識)
在iOS7之后价脾,如果請求Mac地址都會返回一個固定值牧抵。
IMEI
IMEI(International Mobile Equipment Identity)是國際移動裝備辨識碼,是由15位數(shù)字組成的"電子串號"侨把,它與每臺移動電設(shè)備一一對應(yīng)绩蜻,而且該碼是全世界唯一的看疗。每一只移動電話機在組裝完成后都將被賦予一個全球唯一的一組號碼丈挟,這個號碼從生產(chǎn)到交付使用都將被制造生產(chǎn)的廠商所記錄积蜻。
iOS 6及以后系統(tǒng)就不能正規(guī)獲取IMEI,但可以通過私有API獲取手機的IMEI號骇笔,一般蘋果發(fā)現(xiàn)有通過私有API獲取設(shè)備ID省店,上架時會予以拒絕嚣崭。如果在線產(chǎn)品被發(fā)現(xiàn)會立馬下架,2015年有米SDK下架風(fēng)波就是因為通過私有API獲取設(shè)備ID懦傍,觸動了蘋果的底線雹舀,導(dǎo)致一夜之間近300款應(yīng)用被下架,其中不乏大產(chǎn)品谎脯。
MEID
MEID(Mobile Equipment Identifier)移動設(shè)備識別碼葱跋,是CDMA手機的身份識別碼,也是每臺手機唯一的識別碼源梭。通過這個識別碼娱俺,網(wǎng)絡(luò)端可以對該手機進行跟蹤和監(jiān)管,適用于CDMA制式的手機废麻。MEID的數(shù)字范圍是十六進制荠卷,和IMEI的格式類似。
IDFA
廣告標(biāo)示符烛愧,適用于對外:例如廣告推廣油宜,換量等跨應(yīng)用的用戶追蹤等。
是iOS 6中另外一個新的方法怜姿,提供了一個方法advertisingIdentifier慎冤,通過調(diào)用該方法會返回一個NSUUID實例,最后可以獲得一個UUID沧卢,由系統(tǒng)存儲著的蚁堤。不過即使這是由系統(tǒng)存儲的,
但是有幾種情況下但狭,會重新生成廣告標(biāo)示符披诗。
如果用戶完全重置系統(tǒng)((設(shè)置程序 -> 通用 -> 還原 -> 還原位置與隱私) ,這個廣告標(biāo)示符會重新生成立磁。
如果用戶明確的還原廣告(設(shè)置程序-> 通用 -> 關(guān)于本機 -> 廣告 -> 還原廣告標(biāo)示符) 呈队,那么廣告標(biāo)示符也會重新生成。
關(guān)于廣告標(biāo)示符的還原唱歧,有一點需要注意:如果程序在后臺運行宪摧,此時用戶“還原廣告標(biāo)示符”,然后再回到程序中颅崩,此時獲取廣 告標(biāo)示符并不會立即獲得還原后的標(biāo)示符绍刮。必須要終止程序,然后再重新啟動程序挨摸,才能獲得還原后的廣告標(biāo)示符。
在同一個設(shè)備上的所有App都會取到相同的值岁歉,是蘋果專門給各廣告提供商用來追蹤用戶而設(shè)的得运,用戶可以在 設(shè)置|隱私|廣告追蹤 里重置此id的值膝蜈,或限制此id的使用,故此id有可能會取不到值熔掺,但好在Apple默認(rèn)是允許追蹤的饱搏,而且一般用戶都不知道有這么個設(shè)置,所以基本上用來監(jiān)測推廣效果置逻,是戳戳有余了推沸。
注意:由于idfa會出現(xiàn)取不到的情況,故絕不可以作為業(yè)務(wù)分析的主id券坞,來識別用戶鬓催。
代碼:
#import <AdSupport/AdSupport.h>
NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
IDFV(identifierForVendor)
Vindor標(biāo)示符,適用于對內(nèi):例如分析用戶在應(yīng)用內(nèi)的行為等恨锚。
是給Vendor標(biāo)識用戶用的宇驾,每個設(shè)備在所屬同一個Vender的應(yīng)用里,都有相同的值猴伶。其中的Vender是指應(yīng)用提供商课舍,但準(zhǔn)確點說,是通過BundleID的DNS反轉(zhuǎn)的前兩部分進行匹配他挎,如果相同就是同一個Vender筝尾,例如對于com.somecompany.appone,com.somecompany.apptwo 這兩個BundleID來說,就屬于同一個Vender办桨,共享同一個idfv的值筹淫。和idfa不同的是,idfv的值是一定能取到的崔挖,所以非常適合于作為內(nèi)部用戶行為分析的主id贸街,來標(biāo)識用戶,替代OpenUDID狸相。
注意:如果用戶將屬于此Vender的所有App卸載薛匪,則idfv的值會被重置,即再重裝此Vender的App脓鹃,idfv的值和之前不同逸尖。
代碼:
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
OPEN UDID
每臺iOS設(shè)備的OpenUDID是通過第一個帶有OpenUDID SDK包的App生成,如果你完全刪除全部帶有OpenUDID SDK包的App(比如恢復(fù)系統(tǒng)等)瘸右,那么OpenUDID會重新生成娇跟,而且和之前的值會不同,相當(dāng)于新設(shè)備太颤;
優(yōu)點是沒有用到MAC地址苞俘;不同設(shè)備能夠獲取各自唯一的識別碼,保證了唯一性龄章,可以用于以往UDID的相關(guān)用途吃谣;從代碼分析OpenUDID的獲取乞封,識別碼獲取方便并且保存謹(jǐn)慎。
缺點是當(dāng)將設(shè)備上所有使用了OpenUDID方案的應(yīng)用程序刪除岗憋,且設(shè)備關(guān)機重啟肃晚,xcode徹底清除并重啟,重裝應(yīng)用程序去獲取OpenUDID仔戈,此時OpenUDID變化关串,與之前不一樣了,所有OpenUDID應(yīng)用卸載后监徘,由UIPasteboard保存的數(shù)據(jù)即被清除晋修,重裝故會重新獲取新的OpenUDID。
那么當(dāng)因為用戶干預(yù)或者惡意程序耐量,致使UIPasteboard數(shù)據(jù)清除飞蚓,從而導(dǎo)致OpenUDID被刪除,重裝也會獲取新的OpenUDID廊蜒。
OpenUDID生成唯一識別碼的代碼:
unsigned char result[16];
const charchar *cStr = [[[NSProcessInfo processInfo] globallyUniqueString] UTF8String];
CC_MD5( cStr, strlen(cStr), result );
_openUDID = [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08x",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15],
arc4random() % 4294967295];
獲取ios設(shè)備唯一標(biāo)識方案
采取keychain存儲 + 獲取idfv + 自定義隨機數(shù)
核心代碼:
/**
* 新設(shè)備ID
*/
- (NSString *)deviceId {
static NSString *deviceId;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
deviceId = [NetKeychainWrapper keychainStringFromMatchingIdentifier:@"deviceId"];
if (!deviceId) {
deviceId = [[self identifierForVendor] UUIDString];
if (deviceId) {
[NetKeychainWrapper createKeychainValue:deviceId forIdentifier:@"deviceId"];
} else {
NSAssert(0, @"Device ID not found");
deviceId = [self randomDeviceId];
}
}
});
return deviceId;
}
- (void)removeKeychainDeviceId {
[NetKeychainWrapper deleteItemFromKeychainWithIdentifier:@"yztl_deviceId"];
}
- (NSString *)randomDeviceId {
srandom([[NSDate date] timeIntervalSince1970]);
NSString *uniqueId = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", (Byte)random(), (Byte)random(), (Byte)random(), (Byte)random(), (Byte)random(), (Byte)random()];
return uniqueId;
}