在開發過程中,我們經常會被要求擷取每個裝置的唯一標示,以便後台做相應的處理。我們來看看有哪些方法來擷取裝置的唯一標示,然後再分析下這些方法的利弊。
具體可以分為如下幾種:
1、UUID
2、IDFA
3、IDFV
4、MAC
5、UUID
下面我們來具體分析下每種擷取方法的利弊 1、UDID
什麼是UDID
UDID 「Unique Device Identifier Description」是由子母和數字組成的40個字串的序號,用來區別每一個唯一的iOS裝置,包括 iPhones, iPads, 以及 iPod touches,這些編碼看起來是隨機的,實際上是跟硬體裝置特點相聯絡的。
UDID是用來幹什麼的。
UDID可以關聯其它各種資料到相關裝置上。例如,串連到開發人員帳號,可以允許在發布前讓裝置安裝或測試應用;也可以讓開發人員獲得iOS測試版進行體驗。蘋果用UDID串連到蘋果的ID,這些裝置可以自動下載和安裝從App Store購買的應用、儲存從iTunes購買的音樂、協助蘋果發送推播通知、立即訊息。 在iOS 應用早期,UDID被第三方應用開發人員和網路廣告商用來收集使用者資料,可以用來關聯地址、記錄應用使用習慣……以便推送精準廣告。
為什麼蘋果反對開發人員使用UDID。
iOS 2.0版本以後UIDevice提供一個擷取裝置唯一識別碼的方法uniqueIdentifier,通過該方法我們可以擷取裝置的序號,這個也是目前為止唯一可以確認唯一的標示符。 許多開發人員把UDID跟使用者的真實姓名、密碼、住址、其它資料關聯起來;網路窺探者會從多個應用收集這些資料,然後順藤摸瓜得到這個人的許多隱私資料。同時大部分應用確實在頻繁傳輸UDID和私人資訊。 為了避免集體訴訟,蘋果最終決定在iOS 5 的時候,將這一慣例廢除,開發人員被引導產生一個唯一的標識符,只能檢測應用程式,其他的資訊不提供。現在應用試圖擷取UDID已被禁止且不允許上架。
所以這個方法作廢。 2、IDFA
全名:advertisingIdentifier
擷取代碼:
#import <AdSupport/AdSupport.h> NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
1 2 1 2 來源:iOS6.0及以後 說明:直譯就是廣告id, 在同一個裝置上的所有App都會取到相同的值,是蘋果專門給各廣告供應商用來追蹤使用者而設的,使用者可以在 設定|隱私|廣告追蹤 裡重設此id的值,或限制此id的使用,故此id有可能會取不到值,但好在Apple預設是允許追蹤的,而且一般使用者都不知道有這麼個設定,所以基本上用來監測推廣效果,是戳戳有餘了。 注意:由於idfa會出現取不到的情況,故絕不可以作為業務分析的主id,來識別使用者。
3、IDFV
全名:identifierForVendor
擷取代碼:
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
1 1 來源:iOS6.0及以後 說明:顧名思義,是給Vendor標識使用者用的,每個裝置在所屬同一個Vender的應用裡,都有相同的值。其中的Vender是指應用供應商,但準確點說,是通過BundleID的反轉的前兩部分進行匹配,如果相同就是同一個Vender,例如對於com.taobao.app1, com.taobao.app2 這兩個BundleID來說,就屬於同一個Vender,共用同一個idfv的值。和idfa不同的是,idfv的值是一定能取到的,所以非常適合於作為內部使用者行為分析的主id,來標識使用者,替代OpenUDID。 注意:如果使用者將屬於此Vender的所有App卸載,則idfv的值會被重設,即再重裝此Vender的App,idfv的值和之前不同。
4、MAC地址
使用WiFi的mac地址來取代已經廢棄了的uniqueIdentifier方法。具體可見:http://stackoverflow.com/questions/677530/how-can-i-programmatically-get-the-mac-address-of-an-iphone
然而在iOS 7中蘋果再一次無情的封殺mac地址,使用之前的方法擷取到的mac地址全部都變成了02:00:00:00:00:00。 5、UUID
我們可以擷取到UUID,然後把UUID儲存到KeyChain裡面。
這樣以後即使APP刪了再裝回來,也可以從KeyChain中讀取回來。使用group還可以可以保證同一個開發商的所有程式針對同一台裝置能夠擷取到相同的不變的UDID。
但是刷機或重裝系統後uuid還是會改變。
使用Keychain,將UUID當做密碼資訊來儲存.
大致流程: 通過AdSupport擷取UUID(原因AdSupport可以跨應用)
1. (NSString *)appleIFA { NSString *ifa = nil; Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager"); if (ASIdentifierManagerClass) { // a dynamic way of checking if AdSupport.framework is available SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager"); id sharedManager = ((id (*)(id, SEL))[ASIdentifierManagerClass methodForSelector:sharedManagerSelector])(ASIdentifierManagerClass, sharedManagerSelector); SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier"); NSUUID *advertisingIdentifier = ((NSUUID* (*)(id, SEL))[sharedManager methodForSelector:advertisingIdentifierSelector])(sharedManager, advertisingIdentifierSelector); ifa = [advertisingIdentifier UUIDString]; } return ifa;}
1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12 如果不支援AdSupport,那就使用IFV/IDFV (Identifier for Vendor)
+ (NSString *)appleIFV { if(NSClassFromString(@"UIDevice") && [UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) { // only available in iOS >= 6.0 return [[UIDevice currentDevice].identifierForVendor UUIDString]; } return nil;}
1 2 3 4 5 6 7 1 2 3 4 5 6 7 如果以上的都不支援,使用CFUUIDRef手動建立UUID
+ (NSString *)randomUUID { if(NSClassFromString(@"NSUUID")) { // only available in iOS >= 6.0 return [[NSUUID UUID] UUIDString]; } CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); CFStringRef cfuuid = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); CFRelease(uuidRef); NSString *uuid = [((__bridge NSString *) cfuuid) copy]; CFRelease(cfuuid); return uuid;}
1 2 3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 最後,添加到Keychain
+ (void)setValue:(NSString *)value forKey:(NSString *)key inService:(NSString *)service { NSMutableDictionary *keychainItem = [[NSMutableDictionary alloc] init]; keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; keychainItem[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways; keychainItem[(__bridge id)kSecAttrAccount] = key; keychainItem[(__bridge id)kSecAttrService] = service; keychainItem[(__bridge id)kSecValueData] = [value dataUsingEncoding:NSUTF8StringEncoding]; SecItemAdd((__bridge CFDictionaryRef)keychainItem, NULL);}
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
如果更新了provisioning profile的話, Keychain data會丟失.所以我們應該將UUID在NSUserDefault備份.
[[NSUserDefaults standardUserDefaults] setObject:@”123456-1234-1234-12345678” forKey:@"deviceUID"];[[NSUserDefaults standardUserDefaults] synchronize];