1. 程式人生 > >iOS-獲取iPhine的(相對)唯一標示

iOS-獲取iPhine的(相對)唯一標示

在非越獄的手機上獲取某個硬體資訊生成唯一標識,第一隻能找到蘋果的漏洞,第二就是呼叫一些私有介面,顯然這兩條路都比較艱難,並不可持續發展,所以網上 大部分的唯一標識都是從作業系統層面獲取的,在重置手機系統的時候都會被清除,在系統升級、解除安裝重灌、備份恢復都可以保留,現在本人尚未發現可以使用嚴格 意義上的唯一標識。接下來我想跟大家探討的是如何通過“合法”的手段來儘量拿到不會輕易發生變化的“唯一標識”。
在iOS5之前,蘋果提供了一個uniqueIdentifier的介面來獲取裝置的唯一標識,只是出於隱私保護,蘋果在iOS5.0之後變廢棄了,然後 大家應該都知道了,凡是用了uniqueIdentifier這個介面的,蘋果直接都給拒掉了。沒辦法,只能另闢蹊徑了。於是乎,iOS 6.0系統新增了兩個用於替換uniqueIdentifier的介面,分別 是:identifierForVendor,advertisingIdentifier。在現在比較流行的友盟與talkingData統計中,標識 裝置一個用的是OpenUUID+IDFA,一個用的是Keychain+IDFA。蘋果公司規定說如果你的應用如果不存在廣告那麼你是不被允許使用 advertisingIdentifier的。所以,綜上所述,最終從網上找到了解決方案:要麼openudid要麼Keychain+uuid。我個 人推薦第二種方案,至於為什麼,看下面吧

openudid是什麼?Openudid是一個github上一個開源的專案:地址
原理是利用iOS系統中的UIPasteboard剪貼簿類,它用 app-special pastboards 來儲存一160位的隨機字串,存取的方式類似字典的key-value。 app-special pastboards 可持久儲存字串,即使開關機、解除安裝應用,並能在app之間共享。Openudid的第一次訪問的時候用key去檢查剪貼簿內是否存在對應的 value(隨機數),如果不存在就生成一個並存儲在Pasteboard中,第二次訪問的時候就可以直接取到而不去生成新的隨機數。
但是iOS7之後,蘋果封堵了剪貼簿通訊的漏洞,iOS之前是所有的應用都可以共享同一個剪貼簿儲存內容,現在只有在同一 CFBundleIdentifier標識下的App才能共享內容,如com.koudai.a和com.koudai.b,它們的 com.mycompany部分是一樣的,就能共享(請用真機測試,模擬器會有偏差)。當你將裝置中同一Vendor(Vendor就是 CFBundleIdentifier的前兩部分com.xxxxxx)下的所有應用刪除後,再重新下載安裝(重新下載安裝!重新下載安裝!重要的事情說 三遍,別說你解除安裝瞭然後Xcode跑了發現沒變,那你就解除安裝之後下個別的應用,再執行,看看!),在你重新執行應用的時候便會重新生成一個新的 openudid串,所以說單用這個作為裝置的唯一標識顯然是不科學的,要保持標識的唯一顯然還是需要配合其他方案,但是在這裡說一下,蘋果都給你了 idfv作為標識,為什麼還要用這種方案呢,萬一哪天蘋果再一不高興,立馬不讓你用了,這不就傻比了麼,所以,我個人還是不建議用這個方法。
Keychain是什麼?相信用過Mac的人都知道鑰匙串這個東西,當我們使用者名稱密碼登陸某個網站時Mac總會彈出一個提示詢問我們是否儲存或者 更新賬號資訊,然後當我們登陸成功後,下次只要點選該輸入框,就會顯示出記錄的賬號密碼,那麼這些賬號密碼儲存在哪裡?那裡安全麼?其實大可放心,蘋果將 其資訊全部都儲存在鑰匙串裡了。鑰匙串,是蘋果用來儲存密碼和證書的一塊加密儲存區域,目的是為了幫助使用者安全儲存應用或者瀏覽器的密碼,省去了很多輸入 密碼和記密碼的麻煩。keychain不是儲存在手機的沙盒內,而是手機的某個公共區域,手機重啟和應用解除安裝,都不會對這片儲存區域造成影響,因為是加密 儲存不存在被其他應用修改的問題,所以就有人拿keychain來儲存唯一標識。
在Max OS上訪問keychian需要提供使用者的登入密碼,而在iOS上使用者原則上只能訪問本應用儲存的keychain,除非是同一個 provisioning 證書的兩個應用,比如美團的貓眼就能讀取美團app中的keychian,使用者第一次開啟貓眼app就會彈出提示,使用者可以讀取美團的賬號和密碼免登入進 入貓眼。keychain是根據provision 證書來鑑定許可權,所以app的版本需要使用同一個,否則版本之間會失效。使用者恢復出廠設定,機器上的keychain會被清除,但如果事先對手機進行了備 份,keychain儲存的內容依然有效。順便提一句keychain在越獄的機器上是可以被匯出的,所以儲存敏感資訊前請加密。
UUID。它是蘋果再iOS6後提供的一個獲取大隨機數的方法。UUID, 全球獨立標識(Universal Unique Identifier),據wiki說UUID隨機數演算法得到的數重複概率為170億分之一,170億分之一什麼概念?可以告訴你買一注雙色球的中獎概率 是1700萬分之一。隨機演算法有幾套,包括用時間戳、MD5什麼的,蘋果是遵循的RFC 4122 version 4,大家可以去google下。
NSString *uuid = [[NSUUID UUID] UUIDString];
這個每次呼叫此方法得到的UUID肯定是不一樣的,所以必須藉助於持久化儲存。
NSString *uuid =
[[UIDevice currentDevice].identifierForVendor UUIDString];
這個方法在你程式不解除安裝重灌的情況下獲取到的uuid是不變的,(裝置升級但應用未解除安裝情況下並沒有測試)。這個返回的也是一個NSUUIID的物件,至於這兩個方法的區別,我覺得應該是第二個又根據裝置某個獨有資訊做了一些加密操作返回的值。
本文中部分引用:

http://www.jianshu.com/p/4a31e2a30b78

部分重要屬性講解
請參考上面的連結中github中的Demo,仔細閱讀readme以及程式碼中的註釋進行操作。其中在使用官方提供的Demo時,
KeychainItemWrapper *itemWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@”com.chenglei” accessGroup:nil];進 行例項化以後一定要記得將kSecAttrService或kSecAttrAccount進行賦值,否則會一直插入失敗。但是經測試後發現如果用 @”UUID”這個字串作為關鍵字時,kSecAttrService或kSecAttrAccount不用賦值也沒問題,具體原因我也不造,等造了再 補上。

寫入
因為kSecAttrService、kSecAttrAccount這倆是作為主鍵存在,在存入的時候兩者必須一個不為 空,kSecAttrGeneric可有可無,當你建立有kSecAttrService或kSecAttrAccount時,必須對應的建立密碼。為了 使獲取的資料更加精確,我建議將kSecAttrService、kSecAttrAccount兩個屬性以及kSecAttrGeneric都寫上。

讀取
在讀取的時候有以下幾種情況
1. kSecAttrGeneric有值
在讀取的時候,當鑰匙串只利用kSecAttrGeneric這個關鍵字對本應用內的Keychain進行搜尋時,當寫入Keychain時只是設定不同 的kSecAttrService或者kSecAttrService,而設定相同的kSecAttrGeneric,則讀出最近一次寫入或更改的值,即 鑰匙串最後一次修改同一kSecAttrGeneric所對應的值。如果不同,則取出對應的值。
2. kSecAttrGeneric沒有值
當kSecAttrGeneric沒有設定的時候,則查詢條件可根據kSecAttrService或者kSecAttrAccount或者兩者結合。
3. kSecAttrService或kSecAttrAccount有值
當kSecAttrService有值時,如果只查詢kSecAttrService這個條件,則也是Keychain最近一次修改的所對應的同一kSecAttrService的值。kSecAttrAccount亦然。
所以為了使查詢結果更精確,則查詢條件就得更加精確,最好是三個條件都寫。這樣不管是增刪改查都不會造成誤刪資料。
哦,對了,在這裡說一下,如果你鑰匙串中沒有該值則呼叫查詢或者刪除API會返回相應的碼來告訴你,該操作是錯誤的以及錯誤原因。