(絕對有用)iOS獲取UUID,並使用keychain存儲

UDID被棄用,使用UUID來做爲設備的惟一標識。獲取到UUID後,若是用NSUserDefaults存儲,當程序被卸載後重裝時,再得到的UUID和以前就不一樣了。使用keychain存儲能夠保證程序卸載重裝時,UUID不變。但當刷機或者升級系統後,UUID仍是會改變的。但這還是目前爲止最佳的解決辦法了,若是有更好的解決辦法,歡迎留言。 (我整理的解決辦法的參考來源:http://blog.k-res.net/archives/1081.html) 給你們兩個類:html

UUID.h中的代碼:ios

#import 尖括號(Foundation/Foundation.h)app

@interface UUID : NSObjectide

+(NSString *)getUUID;測試

@endui

UUID.m中的代碼:atom

#import "UUID.h" #import 尖括號(Foundation/Foundation.h) #import "KeychainItemWrapper.h".net

@implementation UUIDcode

+(NSString *)getUUID { KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc]orm

initWithIdentifier:@"UUID"
                                   
                                                                             accessGroup:@"YOUR_BUNDLE_SEED.com.yourcompany.userinfo"];


NSString *strUUID = [keychainItem objectForKey:(id)CFBridgingRelease(kSecValueData)];

//首次執行該方法時,uuid爲空
if ([strUUID isEqualToString:@""])

{
    CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);

    strUUID = (NSString *)CFBridgingRelease(CFUUIDCreateString (kCFAllocatorDefault,uuidRef));

    [keychainItem setObject:strUUID forKey:(id)CFBridgingRelease(kSecValueData)];

}
return strUUID;

}

@end

第二個類是蘋果官方的一個Demo裏封裝的,Demo的下載地址:http://developer.apple.com/library/ios/#samplecode/GenericKeychain/Listings/Classes_KeychainItemWrapper_h.html#//apple_ref/doc/uid/DTS40007797-Classes_KeychainItemWrapper_h-DontLinkElementID_9

KeychainItemWrapper.h中的代碼:

#import 尖括號(UIKit/UIKit.h)

@interface KeychainItemWrapper : NSObject { NSMutableDictionary *keychainItemData; NSMutableDictionary *genericPasswordQuery; }

@property (nonatomic, retain) NSMutableDictionary *keychainItemData; @property (nonatomic, retain) NSMutableDictionary *genericPasswordQuery;

  • (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup;
  • (void)setObject:(id)inObject forKey:(id)key;
  • (id)objectForKey:(id)key;
  • (void)resetKeychainItem;

@end

KeychainItemWrapper.m中的代碼:

#import "KeychainItemWrapper.h" #import 尖括號(Security/Security.h)

@interface KeychainItemWrapper (PrivateMethods)

  • (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert;

  • (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert;

  • (void)writeToKeychain;

@end

@implementation KeychainItemWrapper

@synthesize keychainItemData, genericPasswordQuery;

  • (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup; { if (self = [super init]) { genericPasswordQuery = [[NSMutableDictionary alloc] init];

[genericPasswordQuery setObject:(id)CFBridgingRelease(kSecClassGenericPassword) forKey:(id)kSecClass]; [genericPasswordQuery setObject:identifier forKey:(id)CFBridgingRelease(kSecAttrGeneric)];

if (accessGroup != nil) { #if TARGET_IPHONE_SIMULATOR

#else [genericPasswordQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup]; #endif }

[genericPasswordQuery setObject:(id)CFBridgingRelease(kSecMatchLimitOne) forKey:(id)kSecMatchLimit];
    [genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
    
    NSDictionary *tempQuery = [NSDictionary dictionaryWithDictionary:genericPasswordQuery];
    
    NSMutableDictionary *outDictionary = nil;
    
    if (! SecItemCopyMatching((CFDictionaryRef)tempQuery, (CFTypeRef *)&outDictionary) == noErr)
    {
        
        [self resetKeychainItem];

[keychainItemData setObject:identifier forKey:(id)kSecAttrGeneric]; if (accessGroup != nil) { #if TARGET_IPHONE_SIMULATOR

#else [keychainItemData setObject:accessGroup forKey:(id)kSecAttrAccessGroup]; #endif } } else { self.keychainItemData = [self secItemFormatToDictionary:outDictionary]; }

[outDictionary release]; }

return self; }

  • (void)dealloc { [keychainItemData release]; [genericPasswordQuery release];

[super dealloc]; }

  • (void)setObject:(id)inObject forKey:(id)key { if (inObject == nil) return; id currentObject = [keychainItemData objectForKey:key]; if (![currentObject isEqual:inObject]) { [keychainItemData setObject:inObject forKey:key]; [self writeToKeychain]; } }

  • (id)objectForKey:(id)key { return [keychainItemData objectForKey:key]; }

  • (void)resetKeychainItem { OSStatus junk = noErr; if (!keychainItemData) { self.keychainItemData = [[NSMutableDictionary alloc] init]; } else if (keychainItemData) { NSMutableDictionary *tempDictionary = [self dictionaryToSecItemFormat:keychainItemData]; junk = SecItemDelete((CFDictionaryRef)tempDictionary); NSAssert( junk == noErr || junk == errSecItemNotFound, @"Problem deleting current dictionary." ); }

    [keychainItemData setObject:@"" forKey:(id)kSecAttrAccount]; [keychainItemData setObject:@"" forKey:(id)kSecAttrLabel]; [keychainItemData setObject:@"" forKey:(id)kSecAttrDescription]; [keychainItemData setObject:@"" forKey:(id)kSecValueData]; }

  • (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert { NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; [returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; NSString *passwordString = [dictionaryToConvert objectForKey:(id)kSecValueData]; [returnDictionary setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];

    return returnDictionary; }

  • (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert { NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; [returnDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; [returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; NSData *passwordData = NULL; if (SecItemCopyMatching((CFDictionaryRef)returnDictionary, (CFTypeRef *)&passwordData) == noErr) { [returnDictionary removeObjectForKey:(id)kSecReturnData]; NSString *password = [[[NSString alloc] initWithBytes:[passwordData bytes] length:[passwordData length] encoding:NSUTF8StringEncoding] autorelease]; [returnDictionary setObject:password forKey:(id)kSecValueData]; } else { NSAssert(NO, @"Serious error, no matching item found in the keychain.\n"); }

    [passwordData release];

return returnDictionary; }

  • (void)writeToKeychain { NSDictionary *attributes = NULL; NSMutableDictionary *updateItem = NULL; OSStatus result;

    if (SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes) == noErr) { updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes]; [updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass]; NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData]; [tempCheck removeObjectForKey:(id)kSecClass];

#if TARGET_IPHONE_SIMULATOR

[tempCheck removeObjectForKey:(id)kSecAttrAccessGroup]; #endif result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck); NSAssert( result == noErr, @"Couldn't update the Keychain Item." ); } else { result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL); NSAssert( result == noErr, @"Couldn't add the Keychain Item." ); } }

@end

PS: 1. KeychainItemWrapper類在官方Demo裏面也有,若是我複製出錯了,你們能夠在上面的連接上下載官方Demo. 2.使用時要添加Security.framework 3. 尤其注意的是,UUID類下面這句代碼中group的設置方法。 KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc]

initWithIdentifier:@"UUID"
                                   
                                     accessGroup:@"YOUR_BUNDLE_SEED.com.yourcompany.userinfo"];
(1)在項目相同的目錄下建立KeychainAccessGroups.plist文件。
     (絕對有用)iOS獲取UUID,並使用keychain存儲

該文件的結構中最頂層的節點必須是一個名爲「keychain-access-groups」的Array,而且該Array中每一項都是一個描述分組的NSString。YOUR_BUNDLE_SEED.com.yourcompany.userinfo就是要設置的組名。 (2)在項目相同的目錄下建立KeychainAccessGroups.plist文件。在Target-Build Settings-Code Signing欄下的Code Signing Entitlements右側添加KeychainAccessGroups.plist,以下圖。 (絕對有用)iOS獲取UUID,並使用keychain存儲

到此,工做就完成了。 首次安裝程序時,打印出一個uuid,當把程序卸載後,再用getUUID得到 uuid,打印出來的結果和以前相同。證實達到目的。

測試代碼:

NSString * uuid= [UUID getUUID]; NSLog(@"uuid=%@",uuid); 測試結果: uuid=19AAB430-9CB8-4325-ACC5-D7D386B68960

相關文章
相關標籤/搜索