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

來源:互聯網
上載者:User

標籤:

UDID被棄用,使用UUID來作為裝置的唯一標識。擷取到UUID後,如果用NSUserDefaults儲存,當程式被卸載後重裝時,再獲得的UUID和之前就不同了。使用keychain儲存可以保證程式卸載重裝時,UUID不變。但當刷機或者升級系統後,UUID還是會改變的。但這仍是目前為止最佳的解決辦法了,如果有更好的解決辦法,歡迎留言。

(我整理的解決辦法的參考來源:http://blog.k-res.net/archives/1081.html)給大家兩個類: UUID.h中的代碼: 

#import 角括弧(Foundation/Foundation.h)

 

@interface UUID : NSObject

 

+(NSString *)getUUID;

 

@end

 

 

 UUID.m中的代碼: 

#import "UUID.h"

#import 角括弧(Foundation/Foundation.h)

#import "KeychainItemWrapper.h"

 

 

@implementation UUID

 

+(NSString *)getUUID

{

    KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc]

                                        

                                    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 = [NSMutableDictionarydictionaryWithDictionary: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檔案。

         


該檔案的結構中最頂層的節點必須是一個名為“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,如。          
 到此,工作就完成了。   首次安裝程式時,列印出一個uuid,當把程式卸載後,再用getUUID獲得uuid,列印出來的結果和之前相同。證明達到目的。     測試代碼:

  NSString * uuid= [UUID getUUID];

  NSLog(@"uuid=%@",uuid);

  測試結果:   uuid=19AAB430-9CB8-4325-ACC5-D7D386B68960

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.