開發(fā)中需要獲取設(shè)備的唯一標(biāo)識符,以便用于應(yīng)用統(tǒng)計或者產(chǎn)品的推廣,這是很常見的開發(fā)需求。然而很遺憾,傲嬌的蘋果很是注重用戶的隱私保護(hù),隨著系統(tǒng)的升級,各種能夠獲取設(shè)備標(biāo)識符的方法要不被禁止了,要不就是很多限制條件。
獲取設(shè)備標(biāo)識符的血淚歷程
- UDID(Unique Device Identifier),上古時代的方法,iOS5之前可以支持。
- MAC Address,MAC地址在網(wǎng)絡(luò)上用來區(qū)分設(shè)備的唯一性,所以可以用來作為設(shè)備的唯一標(biāo)識符,但在iOS7之后,請求Mac地址都只會得到一個固定值,所以該方法也廢了。
- UUID(Universally Unique Identifier),可生成應(yīng)用唯一標(biāo)識字符串,但在用戶刪除重裝應(yīng)用時,會生成新的字符串,所以不能保證唯一識別該設(shè)備。
- apple push token,依賴于APNS,而且蘋果push有時會抽風(fēng),該方法不可取。
- IDFA(advertisingIdentifier),廣告id,蘋果專門給各廣告提供商用來追蹤用戶而設(shè)的,有幾種情況下會重置:1、用戶完全重置系統(tǒng)(設(shè)置程序 -> 通用 -> 還原 -> 還原位置與隱私),2、還原廣告(設(shè)置程序-> 通用 -> 關(guān)于本機(jī) -> 廣告 -> 還原廣告標(biāo)示符) 。而且還有一點(diǎn):如果程序在后臺運(yùn)行,此時用戶“還原廣告標(biāo)示符”,然后再回到程序中,此時獲取廣 告標(biāo)示符并不會立即獲得還原后的標(biāo)示符。必須要終止程序,然后再重新啟動程序,才能獲得還原后的廣告標(biāo)示符。另外使用了IDFA的應(yīng)用提交審核時,必須要有廣告存在,不然被拒是必然的。所以該方法也不可取。
- IDFV(identifierForVendor)Vindor標(biāo)示符,每個設(shè)備在所屬同一個Vender的應(yīng)用里,都有相同的值。其中的Vender是指應(yīng)用提供商,但準(zhǔn)確點(diǎn)說,是通過BundleID的DNS反轉(zhuǎn)的前兩部分進(jìn)行匹配,如果相同就是同一個Vender,例如對于:com.company.appA,com.company.appB,就屬于同一個Vender,共享同一個idfv的值。idfv的值是一定能取到的,適合于作為內(nèi)部用戶行為分析的主id,來標(biāo)識用戶。但如果用戶將屬于此Vender的所有App卸載,則idfv的值會被重置。IDFV也不可取。
- OpenUDID,每臺iOS設(shè)備的OpenUDID是通過第一個帶有OpenUDID SDK包的App生成,如果完全刪除全部帶有OpenUDID SDK包的App(比如恢復(fù)系統(tǒng)等),OpenUDID會重置,這個方法也不保險。
可行的解決方案
iOS獲取設(shè)備唯一標(biāo)識符的一種可行的解決方案:是通過KeyChain來保存生成的設(shè)備唯一標(biāo)識符,這樣不管是在應(yīng)用刪除重裝,或者是系統(tǒng)升級時,都能夠保證標(biāo)識的唯一性。
下面是我在開發(fā)中封裝的一個獲取設(shè)備標(biāo)識符的庫keychainDeviceID
類中包含三個方法:
/**
* 獲取UUID作為設(shè)備唯一標(biāo)志符
*
* @return
*/
+ (NSString *)getUUID;
/**
* 獲取OpenUDID作為設(shè)備唯一標(biāo)志符
*
* @return
*/
+ (NSString *)getOpenUDID;
/**
* 從keychain刪除DeviceID,一般不會用到
*/
+ (void)deleteDeviceID;
調(diào)用getUUID和getOpenUDID會從KeyChain中讀取對應(yīng)的標(biāo)識符,如果是初次讀取,則會先生成標(biāo)識符存入KeyChain再返回。deleteDeviceID是刪除標(biāo)識符,很少情況會使用到。
庫的引用:
下載demo,將keychainDeviceID文件夾引用到項(xiàng)目中即可,代碼示例:
#import "keychainDeviceID.h"
NSString *UUID = [keychainDeviceID getUUID];
NSString *openUDID = [keychainDeviceID getOpenUDID];