Implementing Unique ID as UUID and saving it in Keychain

大憨熊 提交于 2020-01-02 10:03:50

问题


I need unique ID in my app and i know, we cannot use UDID anymore so as per my research, using UUID as device unique ID and saving it in keychain will ensure the unique id remain same even if user reinstalls my app.

I found the below code from one of the answer to similar question here on stackoverflow however, i need to know how to access keychainUtils and IDManager? Appreciate your help in advance.

+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:USER_NAME   andServiceName:SERVICE_NAME error:&error];
    if (error) {
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    }
    if (!uuid) {
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager GetUUID];
        uuid = [Util md5String:uuid];
        [KeychainUtils storeUsername:kBuyassUser andPassword:uuid forServiceName:kIdOgBetilngService updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

回答1:


I'd like to offer this as a solution. It requires no third party code. It reads or writes to the KeyChain if it absolutely needs to, so it's more efficient that the solutions provided so far. Also, the UUID is written to a keychain access group so that you can share this UUID between your apps. Simply change kKeyChainVendorIDAccessGroup at the start of the method.

+(NSUUID *)persistentIdentifierForVendor
{
    static NSString * const kKeyChainVendorID = @"co.cwbrn.PersistentIdentifier";
    static NSString * const kKeyChainVendorIDAccessGroup = @"<AppIdentifier>.<keychain-access-group-identifier>";

    // First, check NSUserDefaults so that we're not hitting the KeyChain every single time
    NSString *uuidString = [[NSUserDefaults standardUserDefaults] stringForKey:kKeyChainVendorIDGroup];
    BOOL vendorIDMissingFromUserDefaults = (uuidString == nil || uuidString.length == 0);

    if (vendorIDMissingFromUserDefaults) {
        // Check to see if a UUID is stored in the KeyChain
        NSDictionary *query = @{
                                (__bridge id)kSecClass:             (__bridge id)kSecClassGenericPassword,
                                (__bridge id)kSecAttrAccount:       kKeyChainVendorID,
                                (__bridge id)kSecAttrService:       kKeyChainVendorID,
                                (__bridge id)kSecAttrAccessGroup:   kKeyChainVendorIDAccessGroup,
                                (__bridge id)kSecMatchLimit:        (__bridge id)kSecMatchLimitOne,
                                (__bridge id)kSecReturnAttributes:  (__bridge id)kCFBooleanTrue
                               };
        CFTypeRef attributesRef = NULL;
        OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesRef);
        if (result == noErr) {
            // There is a UUID, so try to retrieve it
            NSDictionary *attributes = (__bridge_transfer NSDictionary *)attributesRef;
            NSMutableDictionary *valueQuery = [NSMutableDictionary dictionaryWithDictionary:attributes];

            [valueQuery setObject:(__bridge id)kSecClassGenericPassword  forKey:(__bridge id)kSecClass];
            [valueQuery setObject:(__bridge id)kCFBooleanTrue            forKey:(__bridge id)kSecReturnData];

            CFTypeRef passwordDataRef = NULL;
            OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)valueQuery, &passwordDataRef);
            if (result == noErr) {
                NSData *passwordData = (__bridge_transfer NSData *)passwordDataRef;
                uuidString = [[NSString alloc] initWithBytes:[passwordData bytes]
                                                      length:[passwordData length]
                                                    encoding:NSUTF8StringEncoding];
            }
        }
    }

    // Failed to read the UUID from the KeyChain, so create a new UUID and store it
    if (uuidString == nil || uuidString.length == 0) {
        // Generate the new UIID
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
        CFRelease(uuidRef);

        // Now store it in the KeyChain
        NSDictionary *query = @{    (__bridge id)kSecClass:             (__bridge id)kSecClassGenericPassword,
                                    (__bridge id)kSecAttrAccount:       kKeyChainVendorID,
                                    (__bridge id)kSecAttrService:       kKeyChainVendorID,
                                    (__bridge id)kSecAttrAccessGroup:   kKeyChainVendorIDAccessGroup,
                                    (__bridge id)kSecAttrLabel:         @"",
                                    (__bridge id)kSecAttrDescription:   @"",
                                    (__bridge id)kSecAttrAccessible:    (__bridge id)kSecAttrAccessibleAfterFirstUnlock,
                                    (__bridge id)kSecValueData:         [uuidString dataUsingEncoding:NSUTF8StringEncoding]
                                };

        OSStatus result = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
        if (result != noErr) {
            NSLog(@"ERROR: Couldn't add to the Keychain. Result = %ld; Query = %@", result, query);
            return nil;
        }
    }

    // Save UUID to NSUserDefaults so that we can avoid the KeyChain next time
    if (vendorIDMissingFromUserDefaults) {
        [[NSUserDefaults standardUserDefaults] setObject:uuidString forKey:kKeyChainVendorIDGroup];
    }

    return [[NSUUID alloc] initWithUUIDString:uuidString];
}



回答2:


This is what i have used for unique device ID and saving it in keychain using USHFKeychainUtils that is ARC compliant utility. it's a complete code that i hope will save you guys time!!

+ (NSString *) getUniqueUUID {
NSError * error;
NSString * uuid = [SFHFKeychainUtils getPasswordForUsername:USER_NAME andServiceName:SERVICE_NAME error:&error];
if (error) {
    NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
    return nil;
}
if (!uuid) {
    NSLog(@"No UUID found. Creating a new one.");
    uuid = [self GetUUID];
    uuid = [self md5String:uuid];
    [SFHFKeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
    if (error) {
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    }
}
return uuid;
}


+ (NSString *)md5String:(NSString *)plainText

{
    if(plainText == nil || [plainText length] == 0)
        return nil;

    const char *value = [plainText UTF8String];
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);

    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    NSString * retString = [NSString stringWithString:outputString];
    return retString;
}


+ (NSString *)GetUUID
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return (__bridge NSString *)string;
}



回答3:


I use a much simpler generator that doesn't require any outside library support.

    CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
    CFStringRef uuidStringRef = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
    CFRelease(uuidRef);

    /* save it to defaults, or whatever you want to do with it */
    [userDefaults setValue:(__bridge NSString *)uuidStringRef forKey:UNIQUE_DEVICE_ID];
    [userDefaults synchronize];

    CFRelease(uuidStringRef);


来源:https://stackoverflow.com/questions/20337480/implementing-unique-id-as-uuid-and-saving-it-in-keychain

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!