本文講訴的主要是爲何蘋果2011年8月發佈iOS 5後就開始拒絕App獲取設備的UDID以及UDID替補方案,特別提醒開發者蘋果App Store禁止訪問UDID的應用上架(相關推薦:APP被蘋果App Store拒絕的N個緣由),下面先來了解下UDID。html
UDID的全稱是Unique Device Identifier,顧名思義,它就是蘋果IOS設備的惟一識別碼,它由40個字符的字母和數字組成。git
移動網絡可利用UDID來識別移動設備,如iPhone和iPad。UDID對每臺設備而言都是惟一的,從而成爲了廣告公司、市場分析機構和APP測試系統跟蹤用戶行爲的實用工具。github
目前使用UDID主要緣由分爲:web
因而可知UDID對於IOS應用開發者說,是個很重要的信息(雖然越獄的設備經過某些工具能夠改變設備的UDID)。可是,從IOS5.0(2011年8月份)開始,蘋果宣佈將再也不支持用如下方法獲取設備的UDID。網絡
1
|
[UIDevice currentDevice
]
uniqueIdentifier
];
|
UDID原本是爲了方便一個應用來統計用戶行爲的,可是由於是一個惟一ID,並且直接看不到跟用戶隱私的關係,因此是開放出來的。可是,當有大量的App在市場中,而UDID對於每一個App都是同樣的時候,用戶的隱私其實受到了必定程度的侵犯。假設有不少App聯合在一塊兒,由於UDID是統一的,那麼他們就能夠拼湊出用戶的隱私出來。因此從這個角度蘋果去掉了UDID的支持,而每一個應用能夠自行生成本身的UUID,因此,單一app的統計仍舊不會發生問題。因此主要的緣由是隱私問題。app
一、蘋果公司建議的UUID替代方案dom
1
2 3 4 5 6 7 8 |
-
(
NSString
*
)
uuid
{
CFUUIDRef puuid = CFUUIDCreate ( nil ); CFStringRef uuidString = CFUUIDCreateString ( nil, puuid ); NSString * result = ( NSString * )CFStringCreateCopy ( NULL, uuidString ); CFRelease (puuid ); CFRelease (uuidString ); return [result autorelease ]; } |
蘋果公司建議採用上述代碼爲應用生成惟一標識字符串。開發者能夠在應用第一次啓動時調用一次,而後將該串存儲起來,以便之後替代UDID來使用。顯而易見,這種方法問題不少。若是用戶刪除該應用再次安裝時,又會生成新的字符串,因此不能保證惟一識別該設備;若是你從一臺舊設備中備份文件到新設備中,兩臺設備就擁有相同的CFUUID;若是你從臨時文件中備份操做系統,就會出現一個設備裏存在不一樣CFUUID的狀況。iphone
二、使用開源方案OpenUDID
貢獻者在readme文檔中說:ide
OpenUDID is a drop-in replacement for the deprecated [UIDevice uniqueIdentifier] a.k.a. UDID on iOS, and otherwise is an industry-friendly equivalent for iOS and Android.
The agenda for this community driven project is to: – Provide a reliable proxy and replacement for a universal unique device identifier. That is, persistent and sufficiently unique, on a per device basis. – NOT use an obvious other sensitive unique identifier (like the MAC address) to avoid further deprecation and to protect device-level privacy concerns – Enable the same OpenUDID to be accessed by any app on the same device – Supply open-source code to generate and access the OpenUDID, for iOS and Android – Incorporate, from the beginning, a system that will enable user opt-out to match Apple’s initial intent.工具
願景很好,也確實沒有用到MAC地址,同時能保證同一臺設備上的不一樣應用使用同一個OpenUDID。可是仔細分析,仍是能發現問題。
OpenUDID生成惟一識別碼的代碼是:
1
2 3 4 5 6 7 8 9 10 |
unsigned
char
result
[
16
];
const char *cStr = [ [ [ NSProcessInfo processInfo ] globallyUniqueString ] UTF8String ]; CC_MD5 ( cStr, strlen (cStr ), result ); _openUDID = [NSStringstringWithFormat : @ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08x", result [ 0 ], result [ 1 ], result [ 2 ], result [ 3 ], result [ 4 ], result [ 5 ], result [ 6 ], result [ 7 ], result [ 8 ], result [ 9 ], result [ 10 ], result [ 11 ], result [ 12 ], result [ 13 ], result [ 14 ], result [ 15 ], arc4random ( ) % 4294967295 ]; |
這裏使用了NSProcessInfo類。
當設備上第一個使用OpenUDID解決方案的應用第一次調用時,確實會生成一個惟一的識別碼。同時,爲了與官方的UDID位數相同,還在MD5值後面追加了8位隨機碼。而後,該方案使用到了NSUserDefaults類(應用設置)。應用將獲取到的惟一識別碼保存到應用的UserDefaults中,若是程序之後須要使用惟一識別碼,就從UserDefaults中獲取,這樣就保證能夠拿到同一個識別碼。可是,若是用戶刪除了應用,UserDefaults一樣會被清空,爲了不從新生成惟一識別碼,該方案還使用到了UIPasteboard類(設備剪切板)。應用在將惟一識別碼保存到UserDefaults的同時,也會將其保存到以特殊的key標識的UIPasteboard中。代碼如:
1
2 |
UIPasteboard
*
slotPB
=
[UIPasteboardpasteboardWithName
:availableSlotPBid create
:
YES
];
[slotPB setData : [ NSKeyedArchiver archivedDataWithRootObject :dict ] forPasteboardType :kOpenUDIDDomain ]; |
其中availableSlotPBid是一個字符串key,前綴是「org.OpenUDID.slot.」,點後面加上數字。這個數字默認是從0到99(固然你能夠修改源代碼使它更大或者更小)。
若是設備上安裝了第二個使用OpenUDID解決方案的應用,當應用調用生成OpenUDID的方法時,將會從UIPasteboard中獲取惟一識別碼(遍歷key從0到99的UIPasteboard),這裏取到的就是以前第一個應用保存到UIPasteboard中的。也就是說,只要用戶設備上有一個使用了OpenUDID的應用存在時,其餘後續安裝的應用若是獲取OpenUDID,都將會得到第一個應用生成的那個。
看起來彷佛很好,很複雜。可是仔細想一想,仍是有問題,若是把使用了OpenUDID方案的應用所有都刪除,再從新獲取OpenUDID,此時的OpenUDID就跟之前的不同了(本人測了一下,確實如此)。可見,這種方法仍是不保險。
三、開源方案SecureUDID
稍微看了下SecureUDID源碼,發現其與OpenUDID其實差很少,只是初始獲取的惟一識別碼稍有不一樣。同時,從做者的Readme文檔中可見,這個方案一樣存在不少問題。如原文:
Is this a true UDID replacement?
SecureUDID has two properties that you should know about before you use it. First, as indicated above, the identifier is not derived from hardware attributes. Second, the persistence of an identifier cannot be guaranteed in all situations. This means that, while unlikely, it is technically possible for two distinct devices to report the same identifier, and for the same device to report different identifiers. Consider this carefully in your application. Here is a list of situations where this identifier will not exhibit the uniqueness/persistence of a traditional UDID.
* The user has opted-out of the SecureUDID system, in which case you will receive a well-formed string of zeroes.
* Device A is backed up and then restored to Device B, which is an identical model. This is common when someone breaks their phone, for example, and is likely desirable: you will receive Device A’s SecureUDID.
* The SecureUDID data is removed, via user intervention, UIPasteboard data purge, or by a malicious application.
* The SecureUDID backing store becomes corrupt.
* All SecureUDID applications are uninstalled from a device, followed by a UIPasteboard data purge.
我發現,其實前面的OpenUDID也基本存在以上問題,只是做者沒寫出來。看來仍是SecureUDID的貢獻者比較厚道。
四、與WIFI MAC地址相關
網上一樣有一些與WIFI MAC地址相關的替代方案,主要分三種:第一種直接使用「MAC Address」;第二種,使用「MD5(MAC Address)」;第三種,「MD5(MAC Address+CFBundleIdentifier)」。github上有個開源項目(UIDevice-with-UniqueIdentifier-for-iOS-5)實現了這幾種方法。
使用這種方法也存在問題:一、市面上有部分機器(雖然數量極少,可是本人在使用過程當中確實發現過這種狀況)沒法得到MAC地址,有人說這部分機器是聯通閹割無WIFI版的,具體不得而知了。二、MAC地址跟UDID同樣,存在隱私問題。蘋果如今禁用UDID,不能保證之後不會禁用MAC地址。
五、部分大公司私有的解決方案,可是他們怎麼會告訴你呢?
因此,若是你想以一種萬無一失的方法追蹤某臺設備,如今尚未比UDID更合適的選擇。可是,蘋果如今不讓用了,苦逼的開發者們,該怎麼辦呢?
轉自:http://www.dapps.net/dev/iphone/whats-udid-and-how-to-replace-udid.html
by sschu