Posts

Post not yet marked as solved
3 Replies
2.2k Views
Hi Team,We are facing an issue while testing an app in different iPads registered with the same Apple IDs. Both the iPads running on iOS 13 and above.The issue is both the devices returning the same "identifierForVendor" value when requested from the UIDevice API.Below is our code:@import UIKit; @implementation DeviceUID + (NSString *)uid { return [[[DeviceUID alloc] initWithKey:@"deviceUID"] uid]; } - (id)initWithKey:(NSString *)key { self = [super init]; if (self) { _uidKey = key; _uid = nil; } return self; } /*! Returns the Device UID. The UID is obtained in a chain of fallbacks: - Keychain - NSUserDefaults - Apple IFV (Identifier for Vendor) - Generate a random UUID if everything else is unavailable At last, the UID is persisted if needed to. */ - (NSString *)uid { if (!_uid) _uid = [[self class] valueForKeychainKey:_uidKey service:_uidKey]; if (!_uid) _uid = [[self class] valueForUserDefaultsKey:_uidKey]; if (!_uid) _uid = [[self class] appleIFV]; if (!_uid) _uid = [[self class] randomUUID]; [self save]; return _uid; } /*! Persist UID to NSUserDefaults and Keychain, if not yet saved */ - (void)save { if (![DeviceUID valueForUserDefaultsKey:_uidKey]) { [DeviceUID setValue:_uid forUserDefaultsKey:_uidKey]; } if (![DeviceUID valueForKeychainKey:_uidKey service:_uidKey]) { [DeviceUID setValue:_uid forKeychainKey:_uidKey inService:_uidKey]; } } /*! Create as generic NSDictionary to be used to query and update Keychain items. * param1 * param2 */ + (NSMutableDictionary *)keychainItemForKey:(NSString *)key service:(NSString *)service { NSMutableDictionary *keychainItem = [[NSMutableDictionary alloc] init]; keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword; keychainItem[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways; keychainItem[(__bridge id)kSecAttrAccount] = key; keychainItem[(__bridge id)kSecAttrService] = service; return keychainItem; } /*! Sets * param1 * param2 */ + (OSStatus)setValue:(NSString *)value forKeychainKey:(NSString *)key inService:(NSString *)service { NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service]; keychainItem[(__bridge id)kSecValueData] = [value dataUsingEncoding:NSUTF8StringEncoding]; return SecItemAdd((__bridge CFDictionaryRef)keychainItem, NULL); } + (NSString *)valueForKeychainKey:(NSString *)key service:(NSString *)service { OSStatus status; NSMutableDictionary *keychainItem = [[self class] keychainItemForKey:key service:service]; keychainItem[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue; keychainItem[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; CFDictionaryRef result = nil; status = SecItemCopyMatching((__bridge CFDictionaryRef)keychainItem, (CFTypeRef *)&result); if (status != noErr) { return nil; } NSDictionary *resultDict = (__bridge_transfer NSDictionary *)result; NSData *data = resultDict[(__bridge id)kSecValueData]; if (!data) { return nil; } return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } @end+ (NSString *)appleIFV { if(NSClassFromString(@"UIDevice") && [UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) { // only available in iOS >= 6.0 return [[UIDevice currentDevice].identifierForVendor UUIDString]; } return nil; }Usage:#import "DeviceUID.h"; NSString *deviceID = [DeviceUID uid];This "deviceID" returned from the DeviceUID class is always the same for different devices registered with the same Apple IDs and running on iOS 13.The DeviceID is saved in Keychain and UserDefaults once it is obtained from the UIDevice's "identifierForVendor" property. If it is not available from the property, then a random UUID is generated and saved. For subsequent installations of the app in the same device, the code checks for the DeviceID in Keychain and uses it if it is found.According to the Docs, the identifierForVendor should return new value irrespective of the Apple ID used in the device. But somehow the same value is being returned for the devices all the time.The keychain created doesn't provide the attribute "kSecAttrSynchronizable", hence they keychains should not get synced across devices using same Apple IDs.Could you please provide clarification to us why the same value is returned in this scenario?
Posted Last updated
.