技 術(shù) 文 章 / 超 人
學(xué)無止境,人無完人,在不斷學(xué)習(xí)中成長。如果文章中有錯誤或者紕漏,感謝讀者提出,本人確認(rèn)后將會有小禮品送上??

IMEI說明
IMEI(International Mobile Equipment Identity):國際移動設(shè)備身份碼,在手機(jī)組裝完成后賦予的一個全球唯一的號碼,由于此時 iPhone 只支持單卡,所以 IMEI 和 iPhone 是一一對應(yīng)的。
iOS 2提供了一種方法獲取 IMEI,但是為了保護(hù)用戶隱私,iOS 5 以后蘋果不再允許獲取IMEI 了,如果你在應(yīng)用中獲取IMEI,可能會遭到 Apple Store 的拒絕
唯一標(biāo)識優(yōu)先級排序:
- 1.
IMEI(IOS5已被禁用) -
UDID( iOS 6[2013 年 5 月]已被禁用) 關(guān)于禁用的官方文檔
-
- 3.
Mac地址(IOS7已被禁用) 關(guān)于禁用的官方文檔 - 4.
IDFA(優(yōu)點:不同應(yīng)用獲取的IDFA相同。缺點:系統(tǒng)重置、(設(shè)置程序 -> 隱私 -> 廣告 -> 還原廣告標(biāo)識)會造成IDFA改變,用戶關(guān)閉IDFA標(biāo)識的獲取,將獲取不到。應(yīng)用獲取IDFA不符合蘋果要求,應(yīng)用將會被拒) -
IDFV + SSKeychain(優(yōu)點:不管是否卸載重裝,IDFV 都是不變的)
-
- 6.
(CFUUID或NSUUID) + SSKeychain(優(yōu)點:同一個開發(fā)者賬號創(chuàng)建的所有應(yīng)用獲取的設(shè)備碼都一樣。系統(tǒng)升級、應(yīng)用被刪除設(shè)備碼不變。缺點:不同開發(fā)者創(chuàng)建的應(yīng)用獲取的值不同,系統(tǒng)重置且不備份會重置該值。) - 7.
IDFV(Vindor標(biāo)示符) - 8.OpenUDID`(IOS7已被禁用,每個應(yīng)用獲取的設(shè)備碼不一樣。同一應(yīng)用每次獲取都一樣.應(yīng)用被刪除后設(shè)備碼改變.)
目前國內(nèi)兩大移動統(tǒng)計平臺友盟和TalkingData 的SDK分別用的是
友盟:Openudid+IDFA
TalkingData:Keychain+IDFV+IDFA
國外
FaceBook:IDFA
目前我自己使用的是(CFUUID或NSUUID) + SSKeychain的方法 + IDFA
IDFA(廣告標(biāo)識符)
IDFA(Identifier for Identifier),即廣告標(biāo)識符,多用于用戶的廣告追蹤,是每臺設(shè)備的唯一 ID,IDFA 存儲在用戶的系統(tǒng)上。Apple 是不允許開發(fā)者追蹤用戶設(shè)備的,但是為了監(jiān)控廣告效果,在 iOS 6 中提供這個折中方案,但 IDFA 也會發(fā)生變化,比如重置系統(tǒng)、還原廣告標(biāo)識符等。同時,用戶也可以選擇是否禁止廣告追蹤(即商家沒辦法根據(jù)用戶的行為偏好推送廣告),使用IDFA需要導(dǎo)入AdSupport.framework庫。
//獲取IDFA
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
跟CFUUID和NSUUID不一樣,廣告標(biāo)示符是由系統(tǒng)存儲著的。不過即使這是由系統(tǒng)存儲的,但是有幾種情況下,會重新生成廣告標(biāo)示符。如果用戶完全重置系統(tǒng)(設(shè)置程序 -> 通用 -> 還原 -> 還原位置與隱私) ,這個廣告標(biāo)示符會重新生成。另外如果用戶明確的還原廣告(設(shè)置程序-> 通用 -> 關(guān)于本機(jī) -> 廣告 -> 還原廣告標(biāo)示符) ,那么廣告標(biāo)示符也會重新生成。關(guān)于廣告標(biāo)示符的還原,有一點需要注意:如果程序在后臺運行,此時用戶“還原廣告標(biāo)示符”,然后再回到程序中,此時獲取廣告標(biāo)示符并不會立即獲得還原后的標(biāo)示符。必須要終止程序,然后再重新啟動程序,才能獲得還原后的廣告標(biāo)示符。之所以會這樣,我猜測是由于ASIdentifierManager是一個單例。
針對廣告標(biāo)示符用戶有一個可控的開關(guān)“限制廣告跟蹤”。Nick Arnott的文章中已經(jīng)指出了。將這個開關(guān)打開,實際上什么也沒有做,不過這是希望限制你訪問廣告標(biāo)示符。這個開關(guān)是一個簡單的boolean標(biāo)志,當(dāng)將廣告標(biāo)示符發(fā)到任意的服務(wù)器端時,你最好判斷一下這個值,然后再做決定。
UDID(Unique Device Identifier)
UDID(Unique Device Identifier):IOS 2.0版本以后UIDevice提供一個獲取設(shè)備唯一標(biāo)識符的方法uniqueIdentifier,通過該方法我們可以獲取設(shè)備的序列號,這個也是目前為止唯一可以確認(rèn)唯一的標(biāo)示符。 許多開發(fā)者把UDID跟用戶的真實姓名、密碼、住址、其它數(shù)據(jù)關(guān)聯(lián)起來;網(wǎng)絡(luò)窺探者會從多個應(yīng)用收集這些數(shù)據(jù),然后順藤摸瓜得到這個人的許多隱私數(shù)據(jù)。同時大部分應(yīng)用確實在頻繁傳輸UDID和私人信息。 為了避免集體訴訟在iOS5以前獲取唯一標(biāo)識,基本都是使用系統(tǒng)提供的方法UDID(Unique Device Identifier),后來被出于用戶隱私的考慮在IOS5被Apple官方禁止掉了。至于這個標(biāo)示符是轉(zhuǎn)為私有方法,或者完全從以后的iOS版本中移除,還有待觀察。不過,這個UDID在部署企業(yè)級簽名程序時,非常方便。獲取UDID的方法如下:
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
Mac(Medium/Media Access Control)
Mac(Medium/Media Access Control):網(wǎng)絡(luò)設(shè)備的物理地址,如果IMEI被認(rèn)為是設(shè)備的唯一標(biāo)識,那么 Mac就是網(wǎng)絡(luò)接口唯一標(biāo)識。學(xué)過計算機(jī)網(wǎng)絡(luò)都知道,在根據(jù) IP 進(jìn)行物理尋址的時候就是使用的 Mac 地址。
同樣由于隱私問題,在 iOS 7 之后無法通過 Mac 地址來標(biāo)識唯一設(shè)備,因為在 iOS 7 之后獲取到的 Mac 地址為固定值“02:00:00:00:00:00”。
Mac地址生成設(shè)備的唯一標(biāo)識主要分三種:
1、直接使用“
MAC Address”2、使用“
MD5(MAC Address)”3、使用“
MD5(Mac Address+bundle_id)”獲得“機(jī)器+應(yīng)用”的唯一標(biāo)識(bundle_id 是應(yīng)用的唯一標(biāo)識)
CFUUID
從iOS2.0開始,CFUUID就已經(jīng)出現(xiàn)了。它是CoreFoundatio包的一部分,因此API屬于C語言風(fēng)格。CFUUIDCreate方法用來創(chuàng)建CFUUIDRef,并且可以獲得一個相應(yīng)的NSString,如下代碼:
CFUUIDRef saveUUID = CFUUIDCreate(NULL);
assert(saveUUID != NULL);
CFStringRef uuidStr = CFUUIDCreateString(NULL, saveUUID);
assert(uuidStr != NULL);
deviceId = [NSString stringWithFormat:@"%@", uuidStr];
assert(deviceId != nil);
獲得的這個CFUUID值系統(tǒng)并沒有存儲。每次調(diào)用CFUUIDCreate,系統(tǒng)都會返回一個新的唯一標(biāo)示符。如果你希望存儲這個標(biāo)示符,那么需要自己將其存儲到NSUserDefaults, Keychain, Pasteboard或其它地方。
NSUUID
UUID(Universally Unique IDentifier):通用唯一識別碼
NSUUID 與之前的 CFUUID 是一致的,只是改成了 Objective-C 的接口而已,NSUUID 每次獲取的值都會發(fā)生變化,但是它會保持唯一性。
NSString *uuid = [[NSUUID UUID] UUIDString];
OpenUDID
Openudid是一個github上一個開源的項目:地址
原理是利用iOS系統(tǒng)中的UIPasteboard剪貼板類,它用app-special pastboards來存儲一160位的隨機(jī)字符串,存取的方式類似字典的key-value。app-special pastboards可持久存儲字符串,即使開關(guān)機(jī)、卸載應(yīng)用,并能在app之間共享。Openudid的第一次訪問的時候用key去檢查剪貼板內(nèi)是否存在對應(yīng)的value(隨機(jī)數(shù)),如果不存在就生成一個并存儲在Pasteboard中,第二次訪問的時候就可以直接取到而不去生成新的隨機(jī)數(shù)。但是iOS7之后,蘋果封堵了剪貼板通信的漏洞,iOS之前是所有的應(yīng)用都可以共享同一個剪貼板存儲內(nèi)容,現(xiàn)在只有在同一CFBundleIdentifier標(biāo)識下的App才能共享內(nèi)容,如com.demo.a和com.demo.b,它們的com.mycompany部分是一樣的,就能共享(請用真機(jī)測試,模擬器會有偏差)。
NSString *openUDID = [OpenUDID value];
推送token+bundle_id
網(wǎng)上有說使用 推送token+bundle_id
1、應(yīng)用中增加推送用來獲取token
2、獲取應(yīng)用bundle_id
3、根據(jù)token+bundle_id進(jìn)行散列運算
apple push token保證設(shè)備唯一,但必須有網(wǎng)絡(luò)情況下才能工作,該方法不依賴于設(shè)備本身,但依賴于apple push,而蘋果push有時候會抽風(fēng)的。
SSKeyChain
keychain中文翻譯為鑰匙串,是蘋果用來存儲密碼和證書的一塊加密存儲區(qū)域,目的是為了幫助用戶安全存儲應(yīng)用或者瀏覽器的密碼,省去了很多輸入密碼和記密碼的麻煩。keychain不是存儲在手機(jī)的沙盒內(nèi),而是手機(jī)的某個公共區(qū)域,手機(jī)重啟和應(yīng)用卸載,都不會對這片存儲區(qū)域造成影響,因為是加密存儲不存在被其他應(yīng)用修改的問題,所以就有人拿keychain來存儲唯一標(biāo)識。需要Security.framework支持。
再Max OS上訪問keychian需要提供用戶的登錄密碼,而在iOS上用戶原則上只能訪問本應(yīng)用存儲的keychain,除非是同一個provisioning 證書的兩個應(yīng)用,比如美團(tuán)的貓眼就能讀取美團(tuán)app中的keychian,用戶第一次打開貓眼app就會彈出提示,用戶可以讀取美團(tuán)的賬號和密碼免登錄進(jìn)入貓眼。keychain是根據(jù)provision 證書來鑒定權(quán)限,所以app的版本需要使用同一個,否則版本之間會失效。用戶恢復(fù)出廠設(shè)置,機(jī)器上的keychain會被清除,但如果事先對手機(jī)進(jìn)行了備份,keychain存儲的內(nèi)容依然有效。順便提一句keychain在越獄的機(jī)器上是可以被導(dǎo)出的,所以存儲敏感信息前請加密。
關(guān)于使用,(CFUUID或NSUUID) + SSKeychain后,開發(fā)者賬號發(fā)生改變,蘋果給出的相關(guān)說明

IDFV(identifierForVendor)
Vendor 標(biāo)示符,也被稱為廠商標(biāo)識符。只要用戶的設(shè)備中沒有卸載當(dāng)前 Vendor 的所有 APP,則不會發(fā)生變化。什么是 Vendor ?可以理解成 bundleID 的前兩部分,例如對于 com.joy.app_1 和 com.joy.app_2 這兩個 bundleID 來說,就屬于同一個 Vendor ,共享同一個 IDFV。
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
IDFV 比較適合追蹤用戶行為,目前多配合 Keychain 來搭配使用,來保證不管是否卸載重裝,IDFV 都是不變的。
總結(jié)
2017 年的我們想要通過UDID、Mac 地址、OpenUDID 來定位用戶設(shè)備已經(jīng)是不可能啦,因為它們要么是無效,要么是受到了 App Store 的限制。但是如果你想要追蹤廣告的話,可以使用 IDFA,想要用來分析用戶行為可以使用IDFV + SSKeychain或者 (CFUUID或NSUUID) + SSKeychain來解決。
