将唯一ID实现为UUID并将其保存在Keychain中
我需要在我的应用程序中使用唯一ID,我知道,根据我的研究,我们不能再使用UDID,使用UUID作为设备唯一ID并将其保存在钥匙串中将确保即使用户重新安装我的应用程序,唯一ID也保持不变。
我在stackoverflow上找到了类似问题的答案之一下面的代码,但是,我需要知道如何访问keychainUtils和IDManager? 提前感谢您的帮助。
+ (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; }
我想提供这个解决方案。 它不需要第三方代码。 如果它绝对需要,它会读取或写入KeyChain,因此到目前为止提供的解决方案效率更高。 此外,UUID将写入钥匙串访问组,以便您可以在应用程序之间共享此UUID。 只需在方法开头更改kKeyChainVendorIDAccessGroup
。
+(NSUUID *)persistentIdentifierForVendor { static NSString * const kKeyChainVendorID = @"co.cwbrn.PersistentIdentifier"; static NSString * const kKeyChainVendorIDAccessGroup = @"."; // 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]; }
这是我用于唯一设备ID并使用符合ARC的实用程序的USHFKeychainUtils将其保存在钥匙串中。 这是一个完整的代码,我希望能为您节省时间!
+ (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; }
我使用一个更简单的生成器,不需要任何外部库支持。
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);