1. 程式人生 > >各種獲取裝置唯一標識的方法介紹

各種獲取裝置唯一標識的方法介紹

//現在蘋果對隱私方面很嚴  很難獲取一種較好的裝置唯一識別符號方法,下面幾篇博文僅做參考:

使用UUID作為手機唯一識別符號在app刪除並重新安裝後會重新生成。當我們把第一次生成的UUID儲存到KeyChain中就能解決這個問題。 
推薦大家使用SFHFKeychainUtils來操作keychain。 
SFHFKeychainUtils的下載連結http://download.csdn.net/detail/u011173536/9452292

NSString *SERVICE_NAME = @"com.-----";//最好用程式的bundle id
NSString * str =  [SFHFKeychainUtils getPasswordForUsername:@"UUID"
andServiceName:SERVICE_NAME error:nil]; // 從keychain獲取資料 if ([str length]<=0) { str = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; // 儲存UUID作為手機唯一識別符號 [SFHFKeychainUtils storeUsername:@"UUID" andPassword:str forServiceName:SERVICE_NAME updateExisting:1
error:nil]; // 往keychain新增資料
一.UDID(Unique Device Identifier)

UDID的全稱是Unique Device Identifier,它就是蘋果iOS裝置的唯一識別碼,它由40位16進位制數的字母和數字組成(越獄的裝置通過某些工具可以改變裝置的UDID)。行動網路可利用UDID來識別移動裝置,但是,從IOS5.0(2011年8月份)開始,蘋果宣佈將不再支援用uniqueIdentifier方法獲取裝置的UDID,iOS5以下是可以用的。蘋果從iOS5開始就移除了通過程式碼訪問UDID的許可權。從2013年5月1日起,試圖訪問UIDIDs的程式將不再被稽核通過,替代的方案是開發者應該使用“在

ios 6中介紹的Vendor或Advertising標示符”。所以UDID是絕對是不能再使用了。

//UUID , 已廢除
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
  • 1
  • 2
  • 1
  • 2

為什麼蘋果反對開發人員使用UDID? 
iOS 2.0版本以後UIDevice提供一個獲取裝置唯一識別符號的方法uniqueIdentifier,通過該方法我們可以獲取裝置的序列號,這個也是目前為止唯一可以確認唯一的標示符。 許多開發者把UDID跟使用者的真實姓名、密碼、住址、其它資料關聯起來;網路窺探者會從多個應用收集這些資料,然後順藤摸瓜得到這個人的許多隱私資料。同時大部分應用確實在頻繁傳輸UDID和私人資訊。 為了避免集體訴訟,蘋果最終決定在iOS 5 的時候,將這一慣例廢除,開發者被引導生成一個唯一的識別符號,只能檢測應用程式,其他的資訊不提供。現在應用試圖獲取UDID已被禁止且不允許上架。

二.UUID(Universally Unique Identifier)

UUID是Universally Unique Identifier的縮寫,中文意思是通用唯一識別碼。它是讓分散式系統中的所有元素,都能有唯一的辨識資訊,而不需要透過中央控制端來做辨識資訊的指定。這樣,每個人都可以建立不與其它人衝突的 UUID。在此情況下,就不需考慮資料庫建立時的名稱重複問題。蘋果公司建議使用UUID為應用生成唯一標識字串。 
獲得的UUID值系統沒有儲存, 而且每次呼叫得到UUID,系統都會返回一個新的唯一標示符。如果你希望儲存這個標示符,那麼需要自己將其儲存到NSUserDefaults, Keychain, Pasteboard或其它地方。

1.CFUUID

從iOS2.0開始,CFUUID就已經出現了。它是CoreFoundatio包的一部分,因此API屬於C語言風格。CFUUIDCreate 方法用來建立CFUUIDRef,並且可以獲得一個相應的NSString,如下程式碼:

CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);NSString *cfuuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
  • 1
  • 1

獲得的這個CFUUID值系統並沒有儲存。每次呼叫CFUUIDCreate,系統都會返回一個新的唯一標示符。如果你希望儲存這個標示符,那麼需要自己將其儲存到NSUserDefaults, Keychain, Pasteboard或其它地方。

2.NSUUID

NSUUID在iOS 6中才出現,這跟CFUUID幾乎完全一樣,只不過它是Objective-C介面。+ (id)UUID 是一個類方法,呼叫該方法可以獲得一個UUID。通過下面的程式碼可以獲得一個UUID字串:

NSString *uuid = [[NSUUID UUID] UUIDString];
  • 1
  • 1

跟CFUUID一樣,這個值系統也不會儲存,每次呼叫的時候都會獲得一個新的唯一標示符。如果要儲存的話,你需要自己儲存。在我讀取NSUUID時,注意到獲取到的這個值跟CFUUID完全一樣(不過也可能不一樣)

三.open UDID

在iOS 5釋出時,uniqueIdentifier被棄用了,這引起了廣大開發者需要尋找一個可以替代UDID,並且不受蘋果控制的方案。由此OpenUDID成為了當時使用最廣泛的開源UDID替代方案。OpenUDID在工程中實現起來非常簡單,並且還支援一系列的廣告提供商。

OpenUDID利用了一個非常巧妙的方法在不同程式間儲存標示符 — 在貼上板中用了一個特殊的名稱來儲存標示符。通過這種方法,別的程式(同樣使用了OpenUDID)知道去什麼地方獲取已經生成的標示符(而不用再生成一個新的)。而且根據貢獻者的程式碼和方法,和一些開發者的經驗,如果把使用了OpenUDID方案的應用全部都刪除,再重新獲取OpenUDID,此時的OpenUDID就跟以前的不一樣。可見,這種方法還是不保險。 
但是OpenUDID庫早已經棄用了, 在其官方的部落格中也指明瞭, 停止維護OpenUDID的原因是為了更好的向蘋果的舉措靠攏, 還指明瞭MAC Address不是一個好的選擇。

四.MAC Address

1.這個MAC地址是指什麼?有什麼用?

MAC(Medium/Media Access Control)地址,用來表示網際網路上每一個站點的識別符號,採用十六進位制數表示,共六個位元組(48位)。其中,前三個位元組是由IEEE的註冊管理機構 RA負責給不同廠家分配的程式碼(高位24位),也稱為“編制上唯一的識別符號” (Organizationally Unique Identifier),後三個位元組(低位24位)由各廠家自行指派給生產的介面卡介面,稱為擴充套件識別符號(唯一性)。 
MAC地址在網路上用來區分裝置的唯一性,接入網路的裝置都有一個MAC地址,他們肯定都是不同的,是唯一的。一部iPhone上可能有多個MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一個WIFI的,因此只需獲取WIFI的MAC地址就好了,也就是en0的地址。 
形象的說,MAC地址就如同我們身份證上的身份證號碼,具有全球唯一性。這樣就可以非常好的標識裝置唯一性,類似與蘋果裝置的UDID號,通常的用途有: 
1)用於一些統計與分析目的,利用使用者的操作習慣和資料更好的規劃產品; 
2)作為使用者ID來唯一識別使用者,可以用遊客身份使用app又能在伺服器端儲存相應的資訊,省去使用者名稱、密碼等註冊過程。

2.如何使用Mac地址生成裝置的唯一標識呢?

主要分三種: 
1、直接使用“MAC Address” 
2、使用“MD5(MAC Address)” 
3、使用“MD5(Mac Address+bundle_id)”獲得“機器+應用”的唯一標識(bundle_id 是應用的唯一標識)

iOS7之前,因為Mac地址是唯一的, 一般app開發者會採取第3種方式來識別安裝對應app的裝置。為什麼會使用它?在iOS5之前,都是使用UDID的,後來被禁用。蘋果推薦使用UUID 但是也有諸多問題,從而使用MAC地址。而MAC地址跟UDID一樣,存在隱私問題,現在蘋果新發布的iOS7上,如果請求Mac地址都會返回一個固定值,那麼Mac Address+bundle_id這個值大家的裝置都變成一致的啦,跟UDID一樣相當於被禁用, 所以Mac Address 是不能夠被使用為獲取裝置唯一標識的。

五.廣告標示符(IDFA-identifierForIdentifier)

廣告標示符,在同一個裝置上的所有App都會取到相同的值,是蘋果專門給各廣告提供商用來追蹤使用者而設的。但好在Apple預設是允許追蹤的,而且一般使用者都不知道有這麼個設定,所以基本上用來監測推廣效果,是戳戳有餘了。 
它是iOS 6中另外一個新的方法,提供了一個方法advertisingIdentifier,通過呼叫該方法會返回一個NSUUID例項,最後可以獲得一個UUID,由系統儲存著的。

#import <AdSupport/AdSupport.h>
    NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
  • 1
  • 2
  • 1
  • 2

不過即使這是由系統儲存的,但是有幾種情況下,會重新生成廣告標示符。如果使用者完全重置系統((設定程式 -> 通用 -> 還原 -> 還原位置與隱私) ,這個廣告標示符會重新生成。另外如果使用者明確的還原廣告(設定程式-> 通用 -> 關於本機 -> 廣告 -> 還原廣告標示符) ,那麼廣告標示符也會重新生成。 
關於廣告標示符的還原,有一點需要注意:如果程式在後臺執行,此時使用者“還原廣告標示符”,然後再回到程式中,此時獲取廣 告標示符並不會立即獲得還原後的標示符。必須要終止程式,然後再重新啟動程式,才能獲得還原後的廣告標示符。 
所以IDFA也不可以作為獲取唯一標識的方法,來識別使用者。

六.Vendor標示符 (IDFV-identifierForVendor)

Vendor標示符,是給Vendor標識使用者用的,每個裝置在所屬同一個Vender的應用裡,都有相同的值。其中的Vender是指應用提供商,但準確點說,是通過BundleID的反轉的前兩部分進行匹配,如果相同就是同一個Vender,例如對於com.taobao.app1, com.taobao.app2 這兩個BundleID來說,就屬於同一個Vender,共享同一個IDFV的值。和IDFA不同的是,IDFV的值是一定能取到的,所以非常適合於作為內部使用者行為分析的主id,來標識使用者,替代OpenUDID。 
它是iOS 6中新增的,跟advertisingIdentifier一樣,該方法返回的是一個 NSUUID物件,可以獲得一個UUID。如果滿足條件“相同的一個程式裡面-相同的vendor-相同的裝置”,那麼獲取到的這個屬性值就不會變。如果是“相同的程式-相同的裝置-不同的vendor,或者是相同的程式-不同的裝置-無論是否相同的vendor”這樣的情況,那麼這個值是不會相同的。

    NSString *strIDFV = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
  • 1
  • 1

但是如果使用者將屬於此Vender的所有App解除安裝,則IDFV的值會被重置,即再重灌此Vender的App,IDFV的值和之前不同。

七.推送token+bundle_id

推送token+bundle_id的方法: 
1、應用中增加推送用來獲取token 
2、獲取應用bundle_id 
3、根據token+bundle_id進行雜湊運算

apple push token保證裝置唯一,但必須有網路情況下才能工作,該方法並不是依賴於裝置本身,而是依賴於apple push機制,所以當蘋果push做出改變時, 你獲取所謂的唯一標識也就隨之失效了。所以此方法還是不可取的。

八. NSUUID, CFUUID, IDFA, IDFV獲取的標識對比

首次執行

NSUUID:9D820D3A-4429-4918-97F7-A69588B388A4 
CFUUID:80F961D0-1E6A-4ECD-A0A9-F58ED858FE20 
IDFA:687E6A90-50A3-4424-871C-BE255D050AFD 
IDFV:8E740A99-283B-4F6A-87EF-443FB7778488

二次執行

NSUUID:23AB8D3D-4F1D-45E2-8BD7-83B451125326 
CFUUID:14DDBFCF-67A6-46B7-BB48-4EF2ADC5429F 
IDFA:687E6A90-50A3-4424-871C-BE255D050AFD 
IDFV:8E740A99-283B-4F6A-87EF-443FB7778488

解除安裝後, 重新安裝執行

NSUUID:BD934F9C-B7EC-4BD1-B65E-964C66537CAB 
CFUUID:29654DE0-AC93-40F9-98AB-1E10A271AF8D 
IDFA:687E6A90-50A3-4424-871C-BE255D050AFD 
IDFV:8E740A99-283B-4F6A-87EF-443FB7778488

重啟後執行

NSUUID:82711557-3A17-4B82-8F18-09AADF9DD37B 
CFUUID:FFBC73EC-CFBE-414C-870E-77C0714E0347 
IDFA:687E6A90-50A3-4424-871C-BE255D050AFD 
IDFV:8E740A99-283B-4F6A-87EF-443FB7778488

總結

說了這麼多, 才發現原來沒有一種方法是可行的。沒錯, 其實自從蘋果廢除UDID後, 就不能達到獲取裝置真正的唯一標識了。因為這些方法中導致獲取的唯一標示產生改變的原因, 或是重新呼叫方法, 或是重啟裝置, 或是解除安裝應用, 或是還原某些標識, 或者刷新系統… 
所以, 不能達到從根本上獲取唯一標識, 我們只能做到儘可能接近。下面是我用過的方法。

如何正確的獲取裝置的唯一標識

我用的方法是將獲取的UUID永久儲存在裝置的KeyChain中, 這個方法在應用第一次啟動時, 將獲取的UUID儲存進KeyChain中, 每次取的時候, 檢查本地鑰匙串中有沒有, 如果沒有則需要將獲取的UUID儲存進去。當你重啟裝置, 解除安裝應用再次安裝,都不影響, 只是當裝置刷機時, KeyChain會清空, 才會消失, 才會失效。 
不只是這一種方法, 你也可以儲存除UUID之外,其他合適的標識, 但利用KeyChain去儲存標識的方式應該是最接近的。

由於蘋果對安全的加強,現在通過

NSString *identifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; 
  • 1
  • 1

獲取唯一標示的方法不可行了。 
需要將唯一標示儲存到KeyChain中,這樣即便是應用解除安裝了,然後使用者在安裝也是獲取到的唯一的UUID。

需要設定的東西: 
這裡寫圖片描述

使用起來非常的方便,

    //儲存到keychain
    if([AppUntils readUUIDFromKeyChain]){
        [AppUntils saveUUIDToKeyChain];
    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

獲取

NSString *adUuid = [AppUntils readUUIDFromKeyChain];
  • 1
  • 1