1.已禁用-[UIDevice uniqueIdentifier]
蘋(píng)果總是把用戶(hù)的隱私看的很重要。-[UIDevice uniqueIdentifier]在iOS5實(shí)際在iOS5的時(shí)候已經(jīng)被遺棄了,但是iOS7中已經(jīng)完全的禁用了它。Xcode5甚至不會(huì)允許你編譯包含了指引到-[UIDevice uniqueIdentifier]的app。此外,iOS7之前的使用了-[UIDevice uniqueIdentifier] 的app如果在iOS7上運(yùn)行,它不會(huì)返回設(shè)備的UUID,而是會(huì)返回一串字符串,以FFFFFFFF開(kāi)頭,跟著-[UIDevice identifierForVendor]的十六進(jìn)制值。
2.MAC地址不能再用來(lái)設(shè)別設(shè)備
還有一個(gè)生成iOS設(shè)備唯一標(biāo)示符的方法是使用iOS設(shè)備的Media Access Control(MAC)地址。一個(gè)MAC地址是一個(gè)唯一的號(hào)碼,它是物理網(wǎng)絡(luò)層級(jí)方面分配給網(wǎng)絡(luò)適配器的。這個(gè)地址蘋(píng)果還有其他的名字,比如說(shuō)是硬件地址(Hardware Address)或是Wifi地址,都是指同樣的東西。
有很多工程和框架都使用這個(gè)方法來(lái)生成唯一的設(shè)備ID。比如說(shuō)ODIN。然而,蘋(píng)果并不希望有人通過(guò)MAC地址來(lái)分辨用戶(hù),所以如果你在iOS7系統(tǒng)上查詢(xún)MAC地址,它現(xiàn)在只會(huì)返回02:00:00:00:00:00。
3.現(xiàn)在蘋(píng)果明確的表明你應(yīng)該使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]來(lái)作為你框架和應(yīng)用的唯一標(biāo)示符。坦白的來(lái)說(shuō),應(yīng)對(duì)這些變化也不是那么的難,見(jiàn)以下代碼片段:
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
每種方法都適配一種特別的用法:
identifierForVendor對(duì)供應(yīng)商來(lái)說(shuō)是唯一的一個(gè)值,也就是說(shuō),由同一個(gè)公司發(fā)行的的app在相同的設(shè)備上運(yùn)行的時(shí)候都會(huì)有這個(gè)相同的標(biāo)識(shí)符。然而,如果用戶(hù)刪除了這個(gè)供應(yīng)商的app然后再重新安裝的話(huà),這個(gè)標(biāo)識(shí)符就會(huì)不一致。
advertisingIdentifier會(huì)返回給在這個(gè)設(shè)備上所有軟件供應(yīng)商相同的 一個(gè)值,所以只能在廣告的時(shí)候使用。這個(gè)值會(huì)因?yàn)楹芏嗲闆r而有所變化,比如說(shuō)用戶(hù)初始化設(shè)備的時(shí)候便會(huì)改變。
- 由于identifierForVendor刪除了這個(gè)供應(yīng)商的app然后再重新安裝的話(huà),這個(gè)標(biāo)識(shí)符就會(huì)不一致,所以要解決這個(gè)問(wèn)題可以把第一次生成的唯一標(biāo)示符,保存到keyChain(鑰匙串)中,當(dāng)應(yīng)用被刪除后keyChain中的數(shù)據(jù)還在,下次在從keyChain中取就OK了
廢話(huà)就講到這了,下面是代碼:
#define KEY_UDID @"KEY_UDID"
#define KEY_IN_KEYCHAIN @"KEY_IN_KEYCHAIN"
#import <Security/Security.h>
#import "APPIdentificationManage.h"
@implementation APPIdentificationManage
singleton_implementation(APPIdentificationManage)
#pragma mark 獲取UUID
/**
*此uuid在相同的一個(gè)程序里面-相同的vindor-相同的設(shè)備下是不會(huì)改變的
*此uuid是唯一的,但應(yīng)用刪除再重新安裝后會(huì)變化,采取的措施是:只獲取一次保存在鑰匙串中,之后就從鑰匙串中獲取
**/
- (NSString *)openUDID
{
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
return identifierForVendor;
}
#pragma mark 保存UUID到鑰匙串
- (void)saveUDID:(NSString *)udid
{
NSMutableDictionary *udidKVPairs = [NSMutableDictionary dictionary];
[udidKVPairs setObject:udid forKey:KEY_UDID];
[[APPIdentificationManage sharedAPPIdentificationManage] save:KEY_IN_KEYCHAIN data:udidKVPairs];
}
#pragma mark 讀取UUID
/**
*先從內(nèi)存中獲取uuid,如果沒(méi)有再?gòu)蔫€匙串中獲取,如果還沒(méi)有就生成一個(gè)新的uuid,并保存到鑰匙串中供以后使用
**/
- (id)readUDID
{
if (_uuid == nil || _uuid.length == 0) {
NSMutableDictionary *udidKVPairs = (NSMutableDictionary *)[[APPIdentificationManage sharedAPPIdentificationManage] load:KEY_IN_KEYCHAIN];
NSString *uuid = [udidKVPairs objectForKey:KEY_UDID];
if (uuid == nil || uuid.length == 0) {
uuid = [self openUDID];
[self saveUDID:uuid];
}
_uuid = uuid;
}
return _uuid;
}
#pragma mark 刪除UUID
- (void)deleteUUID
{
[APPIdentificationManage delete:KEY_IN_KEYCHAIN];
}
#pragma mark 查詢(xún)鑰匙串
- (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
service, (__bridge_transfer id)kSecAttrService,
service, (__bridge_transfer id)kSecAttrAccount,
(__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
nil nil];
}
#pragma mark 將數(shù)據(jù)保存到鑰匙串
- (void)save:(NSString *)service data:(id)data {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}
#pragma mark 加載鑰匙串中數(shù)據(jù)
- (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
[keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", service, e);
} @finally {
}
}
return ret;
}
#pragma mark 刪除鑰匙串中數(shù)據(jù)
- (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
@end