iOS UDID與UUID
1.UDID
通用唯一識別碼 UDID(Unique Device Identifier)
是一串由40位16進制數組成的字符串,用以標識唯一的設備,現在想通過代碼獲取是不可能的了,如果你想看看你設備的UDID,可以通過iTunes來查看。
蘋果從iOS5開始就移除了通過代碼訪問UDID的權限,所以碼農想知道用戶設備的UDID,是不行的。
對於已越獄了的設備,UDID並不是唯一的。使用Cydia插件UDIDFaker,可以爲每一個應用分配不同的UDID。 所以UDID作爲標識唯一設備的用途已經不大了。
關於獲取UDID的代碼(iOS5之後已經廢掉並被AppStore封殺)
[[UIDevice currentDevice] uniqueIdentifier];
2.UUID
設備唯一標識 UUID(Universally Unique IDentifier)
是基於iOS設備上面某個單個的應用程序,只要用戶沒有完全刪除應用程序,則這個UUID在用戶使用該應用程序的時候一直保持不變。如果用戶刪除了這個應用程序,然後再重新安裝,那麼這個UUID已經發生了改變。
同一設備上的不同應用的UUID是互斥的,即能在改設備上標識應用。所以一些人推測,這個UUID應該是根據設備標識和應用標識生成唯一標識,再經過加密而來的(純推測)。
官方推薦的方法是,每個應用內創建一個UUID來作爲唯一標誌,並將之存儲,但是這個解決方法明顯不能接受!
你每次創建的UUID都是不一樣的,意味着,你卸載後重新安裝這個軟件,生成的UUID就不一樣了,無法達到我們將之作爲數據分析的唯一標識符的要求。
關於獲取UUID的代碼:
[[UIDevice currentDevice] identifierForVendor];
不過,設備唯一標示的問題仍然沒有解決:如果你刪除應用然後再次安裝,這個identifierForVendor的值就變了。
3.獲取設備唯一標識符的推薦新方案
思路
通過調用CFFUUIDCreate函數來生成機器唯一標識符UUID。但每次調用該函數返回的字符串都不一樣,所以第一次調用後需把該字符串存儲起來。
儘管CFFUUIDCreate每次獲取的UUID會發生變化,最理想的是可以保存在鑰匙串keychain裏面,並以此作爲標識用戶設備的唯一標識符。
3.1關於獲取UUID的官方方案
- (NSString *) uniqueString
{
CFUUIDRef unique = CFUUIDCreate(kCFAllocatorDefault);
NSString *result = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, unique) autorelease];
CFRelease(unique);
return result;
}
複製代碼
3.2基於SSKeychain的唯一識別碼方案
如上獲取的UUID,基於Git上的一個第三方庫SSKeychain,可以將UUID保存在keychain裏面,每次調用先檢查鑰匙串裏面有沒有,有則使用,沒有則寫進去,保證其唯一性.
參考代碼:
- (NSString *)getNewUniqueIdNum{
NSString *uuidStr = [SSKeychain passwordForService:@"com.test.app1" account:@"user"];
if (!uuidStr || [uuidStr isEqualToString:@""])
{
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
uuidStr = (__bridge NSString *)CFUUIDCreateString(kCFAllocatorDefault ,uuidRef);
[SSKeychain setPassword:[NSString stringWithFormat:@"%@", uuidStr] forService:@"com.test.app1"account:@"user"];
}
return uuidStr;
}
不同於上面調用的字符串轉換(__bridge NSString *),另一種寫法:
- (NSString *)getNewUniqueIdNum{
NSString *identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
CFUUIDRef uuidRef = CFUUIDCreate(NULL);
assert(uuidRef != NULL);
CFStringRef uuidStrRef = CFUUIDCreateString(NULL, uuidRef);
if (!identifierNumber){
[SSKeychain setPassword: [NSString stringWithFormat:@"%@", uuidStrRef] forService:@"com.test.app1"account:@"user"];
identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
}
return identifierNumber;
}
3.3其它方案
不同於如上SSKeychain,基於一個第三方庫SAMKeyChains。SAMKeyChains對蘋果安全框架API進行了簡單封裝,支持對存儲在鑰匙串中密碼、賬戶進行訪問,包括讀取、刪除和設置。SAMKeyChains使用簡單,通過實例代碼便可掌握。
基於SAMKeyChains方案的參考代碼:
+ (NSString *)getDeviceId
{
NSString * currentDeviceUUIDStr = [SAMKeychain passwordForService:@" "account:@"uuid"];
if (currentDeviceUUIDStr == nil || [currentDeviceUUIDStr isEqualToString:@""])
{
NSUUID * currentDeviceUUID =[[UIDevice currentDevice] identifierForVendor];
currentDeviceUUIDStr = [currentDeviceUUID UUIDString];
currentDeviceUUIDStr = [currentDeviceUUIDStr stringByReplacingOccurrencesOfString:@"-" withString:@""];
currentDeviceUUIDStr = [currentDeviceUUIDStr lowercaseString];
[SAMKeychain setPassword: currentDeviceUUIDStr forService:@" "account:@"uuid"];
}
return currentDeviceUUIDStr;
}