iOS gets UUID and uses keychain to store it

UDID is deprecated and UUID is used as the unique identifier of the device. After obtaining the UUID, if it is stored using NSUserDefaults, when the program is uninstalled and then reinstalled, the UUID obtained will be different from before. Using keychain storage can ensure that the UUID remains unchanged when the program is uninstalled and reinstalled. But when the machine is flashed or the system is upgraded, the UUID will still change. But this is still the best solution so far


1. Create a new project and take a look at your Bundle Id. This Bundle Id must match the Bundle Id on the certificate when you use the real machine to test.

(Definitely useful) iOS gets the UUID and stores it using keychain

For example, mine is house.xianrou.xianrou


2.Target - Capabilities - Keychain Sharing - ON


(Definitely useful) iOS gets the UUID and stores it using keychain

 


(Definitely useful) iOS gets the UUID and stores it using keychain

The main purpose of this step is to turn on Keychain Sharing and change it from gray OFF to blue ON.

The changes after opening are as follows:


(Definitely useful) iOS gets the UUID and stores it using keychain



(Definitely useful) iOS gets the UUID and stores it using keychain

The directory on the left will automatically generate the Entitlements file, so there is no need to create it yourself.


In other words, the first element of the Bundle Identifier, the Keychain Groups of Keychain Sharing, and the Keychain Access Groups of the Entitlements file must maintain the consistency shown in the above figure.

After setting up, you can run the program. If there is no problem, you can proceed to the next step.


3.uuid class and keychain class

Since Apple's keychain method crashes and is a bit complicated, if we only save one uuid we can use the following simple method:

(This is also my own Baidu keychain copied from others, and then modified)

UUID.h

#import   angle brackets ( Foundation/Foundation.h )


@interface UUID : NSObject


+(NSString *)getUUID;


 

@end


UUID.m


#import "UUID.h"

#import "KeyChainStore.h"



@implementation UUID


+(NSString *)getUUID

{

    NSString * strUUID = (NSString *)[KeyChainStore load:@"com.company.app.usernamepassword"];

    

    //首次执行该方法时,uuid为空

    if ([strUUID isEqualToString:@""] || !strUUID)

    {

        //生成一个uuid的方法

        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);

        

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

   

        //将该uuid保存到keychain

        [KeyChainStore save:KEY_USERNAME_PASSWORD data:strUUID];

        

    }

    return strUUID;

}

 

@end


KeyChainStore.h


#import 尖括号(Foundation/Foundation.h


@interface KeyChainStore : NSObject


+ (void)save:(NSString *)service data:(id)data;

+ (id)load:(NSString *)service;

+ (void)deleteKeyData:(NSString *)service;

 

@end


KeyChainStore.m

#import "KeyChainStore.h"



@implementation KeyChainStore


+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {

    return [NSMutableDictionary dictionaryWithObjectsAndKeys:

            (id)kSecClassGenericPassword,(id)kSecClass,

            service, (id)kSecAttrService,

            service, (id)kSecAttrAccount,

            (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,

            nil];

}


+ (void)save:(NSString *)service data:(id)data {

    //Get search dictionary

    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];

    //Delete old item before add new item

    SecItemDelete((CFDictionaryRef)keychainQuery);

    //Add new object to search dictionary(Attention:the data format)

    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];

    //Add item to keychain with the search dictionary

    SecItemAdd((CFDictionaryRef)keychainQuery, NULL);

}


+ (id)load:(NSString *)service {

    id ret = nil;

    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];

    //Configure the search setting

    //Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue

    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];

    [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];

    CFDataRef keyData = NULL;

    if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {

        @try {

            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];

        } @catch (NSException *e) {

            NSLog(@"Unarchive of %@ failed: %@", service, e);

        } @finally {

        }

    }

    if (keyData)

        CFRelease(keyData);

    return ret;

}


+ (void)deleteKeyData:(NSString *)service {

    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];

    SecItemDelete((CFDictionaryRef)keychainQuery);

}


 

@end


将这两个类添加到工程中

4.新建一个pch文件,然后pch文件的内容如下:


#ifndef PrefixHeader_pch

#define PrefixHeader_pch


#define  KEY_USERNAME_PASSWORD @"com.company.app.usernamepassword"

#define  KEY_USERNAME @"com.company.app.username"

#define  KEY_PASSWORD @"com.company.app.password"


#endif


pch文件的创建方法可参考:http://blog.csdn.net/huang2009303513/article/details/40375235
有可能会在填Prefix Header 即pch文件的路径那里报错,最近又学习到一种更好的方式$(SRCROOT)/$(PROJECT_NAME)/PrefixHeader.pch,其中$(PROJECT_NAME)是相对工程名,比上面的方法更便捷.


5.在viewcontroller.m里面执行如下代码

  NSString * uuid= [UUID getUUID];

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

  得到的uuid类似于这种
  uuid=19AAB430-9CB8-4325-ACC5-D7D386B68960
  
然后卸载掉,再重新运行,看前后得到的uuid是不是一样

Reprinted from: http://blog.sina.com.cn/s/blog_5971cdd00102vqgy.html

Guess you like

Origin blog.csdn.net/baidu_33298752/article/details/51656096