iOS 設備的唯一標識符

1.已禁用-[UIDevice uniqueIdentifier]
  蘋果總是把用戶的隱私看的很重要。-[UIDevice uniqueIdentifier]在iOS5實際在iOS5的時候已經被遺棄了,但是iOS7中已經完全的禁用了它。Xcode5甚至不會允許你編譯包含了指引到-[UIDevice uniqueIdentifier]的app。此外,iOS7之前的使用了-[UIDevice uniqueIdentifier] 的app如果在iOS7上運行,它不會返回設備的UUID,而是會返回一串字符串,以FFFFFFFF開頭,跟著-[UIDevice identifierForVendor]的十六進制值。

2.MAC地址不能再用來設別設備
  還有一個生成iOS設備唯一標示符的方法是使用iOS設備的Media Access Control(MAC)地址。一個MAC地址是一個唯一的號碼,它是物理網絡層級方面分配給網絡適配器的。這個地址蘋果還有其他的名字,比如說是硬件地址(Hardware Address)或是Wifi地址,都是指同樣的東西。
  有很多工程和框架都使用這個方法來生成唯一的設備ID。比如說ODIN。然而,蘋果并不希望有人通過MAC地址來分辨用戶,所以如果你在iOS7系統上查詢MAC地址,它現在只會返回02:00:00:00:00:00。

3.現在蘋果明確的表明你應該使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]來作為你框架和應用的唯一標示符。坦白的來說,應對這些變化也不是那么的難,見以下代碼片段:

NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString]; 
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]; 

每種方法都適配一種特別的用法:
  identifierForVendor對供應商來說是唯一的一個值,也就是說,由同一個公司發行的的app在相同的設備上運行的時候都會有這個相同的標識符。然而,如果用戶刪除了這個供應商的app然后再重新安裝的話,這個標識符就會不一致。
  advertisingIdentifier會返回給在這個設備上所有軟件供應商相同的 一個值,所以只能在廣告的時候使用。這個值會因為很多情況而有所變化,比如說用戶初始化設備的時候便會改變。

  1. 由于identifierForVendor刪除了這個供應商的app然后再重新安裝的話,這個標識符就會不一致,所以要解決這個問題可以把第一次生成的唯一標示符,保存到keyChain(鑰匙串)中,當應用被刪除后keyChain中的數據還在,下次在從keyChain中取就OK了
    廢話就講到這了,下面是代碼:
#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在相同的一個程序里面-相同的vindor-相同的設備下是不會改變的 
 *此uuid是唯一的,但應用刪除再重新安裝后會變化,采取的措施是:只獲取一次保存在鑰匙串中,之后就從鑰匙串中獲取 
 **/  
- (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  
/** 
 *先從內存中獲取uuid,如果沒有再從鑰匙串中獲取,如果還沒有就生成一個新的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 查詢鑰匙串  
- (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 將數據保存到鑰匙串  
- (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 加載鑰匙串中數據  
- (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 刪除鑰匙串中數據  
- (void)delete:(NSString *)service {  
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];  
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);  
}  
@end  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容