iOS-用UUID+KeyChain实现设备唯一标识

设备唯一标识UDID被弃用后的一种替代方法,生成一个随机数--UUID,并用KeyChain存储,这样就可以保证程序卸载重装时,这个UUID不变,这UUID就可以作为我们的设备唯一标识。

注意刷机或者升级系统后的情况,UUID还是会改变的。

QCUUID类的实现:
#import 
@class QCKeyChain;

@interface QCUUID : NSObject
// 获取设备唯一标识
+ (NSString *)getDeviceID;
@end

#import "QCUUID.h"
#import "QCKeyChain.h"

@implementation QCUUID

+ (NSString *)getDeviceID {
    // 读取keyChain存储的UUID
    NSString * strUUID = (NSString *)[QCKeyChain loadForKey: KEY_DEVICE];
    // 首次运行生成一个UUID并用keyChain存储
    if ([strUUID isEqualToString: @""] || !strUUID) {
        // 生成uuid
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        strUUID = (NSString *)CFBridgingRelease(CFUUIDCreateString (kCFAllocatorDefault,uuidRef));
        // 将该uuid用keychain存储
        [QCKeyChain saveData: strUUID forKey: KEY_DEVICE];
    }
    return strUUID;
}

@end
QCKeyChain类的实现
#import 

@interface QCKeyChain : NSObject

+ (void)saveData:(id)data forKey:(NSString *)key;

+ (id)loadForKey:(NSString *)key;

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

@end
#import "QCKeyChain.h"

@implementation QCKeyChain

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)key {
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (id)kSecClassGenericPassword,(id)kSecClass,
             key, (id)kSecAttrService,
             key, (id)kSecAttrAccount,
            (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible, nil];
}

+ (void)saveData:(id)data forKey:(NSString *)key {
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];

    //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)loadForKey:(NSString *)key {

    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];

    //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(@"存储失败,key-- %@  exception-- %@", key, e);
        } @finally {
        }
    }

    if (keyData) {
      CFRelease(keyData);
    }

    return ret;
}

+ (void)deleteKeyData:(NSString *)key {
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];
    SecItemDelete((CFDictionaryRef)keychainQuery);
}

@end
使用:

先导入QCUUID.h

// 设备唯一标识
NSString *deviceID = [QCUUID getDeviceID];

你可能感兴趣的:(iOS-用UUID+KeyChain实现设备唯一标识)