簡介
還在假期中便收到了來自產品狗們的需求文檔,然后在火車上的時候便看了一下他們提出的幾點需求。因為是版本迭代,所以說大功能並沒有變多少,只是小 修小補,但是有兩個問題我還是比較關注的,一個是蘋果對中國開放Apple Pay,要求可以內部充值或者付款,第二就是,要同一設備記錄登陸過的手機號。第一個在上面的文章中已經部分介紹,下面主要介紹如果獲得設備的唯一標識, 以及當該軟件被刪除重新安裝以及更新后,如何保持唯一標識不變。
在非越獄的手機上獲取某個硬件信息生成唯一標識,第一只能找到蘋果的漏洞,第二就是調用一些私有接口,顯然這兩條路都比較艱難,並不可持續發展,所以網上 大部分的唯一標識都是從操作系統層面獲取的,在重置手機系統的時候都會被清除,在系統升級、卸載重裝、備份恢復都可以保留,現在本人尚未發現可以使用嚴格 意義上的唯一標識。接下來我想跟大家探討的是如何通過“合法”的手段來盡量拿到不會輕易發生變化的“唯一標識”。
在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
實現
根據Keychain+UUID實現獲取設備唯一標識,地址:
https://github.com/TripleStoneCheng/keychain-uuid.git
部分重要屬性講解
請參考上面的鏈接中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會返回相應的碼來告訴你,該操作是錯誤的以及錯誤原因。
錯誤:如果出現存取錯誤:-34018錯誤,那么很可能是你的證書或者配置文件出現了問題。
轉自:http://blog.csdn.net/chenglei9128/article/details/50727149