IOS unique identifier

I am writing an iphone application that communicates with my server using REST. The main problem is that I need to somehow identify the user. Not so long ago we were allowed to use the UDID, but now it is no longer allowed. So what should I use instead? I need some kind of identifier on iphone, so the user will uninstall the application, install it again, and he will get the same identifier.

+86
ios objective-c iphone
Sep 01 '11 at 15:57
source share
7 answers

Firstly, the UDID is only deprecated in iOS 5. This does not mean that it has left (for now).

Secondly, you should ask yourself if you really need such a thing. What if the user receives a new device and installs your application? The same user, but the UDID has changed. Meanwhile, the original user may have sold his old device, so now a completely new user installs your application, and you think that this is a different person based on the UDID.

If you do not need a UDID, use CFUUIDCreate() to create a unique identifier and secure it by default for the user on first run (use CFUUIDCreateString() to convert the UUID to string first). It will take backups and restore them, and even come with the original user when switching to a new device. This is in many ways the best option, which is the UDID.

If you really need a unique device identifier (it doesn’t look like you), go to the MAC address provided in Suhail's answer.

+67
Sep 01 '11 at 16:05
source share

I used CFUUIDCreate() to create the UUID:

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

Then set the above UUID to my NSString:

 NSString *UUID = [nameofclasswhereGetUUIDclassmethodresides UUID]; 

Then I saved this UUID in the keychain using SSKeyChain

To set the UUID using SSKeyChain:

 [SSKeychain setPassword:UUID forService:@"com.yourapp.yourcompany" account:@"user"]; 

To get it:

 NSString *retrieveuuid = [SSKeychain passwordForService:@"com.yourapp.yourcompany" account:@"user"]; 

When you set the UUID in the keychain, it will be saved even if the user completely uninstalls the application and then installs it again.

So that all devices have the same UUID in the key chain.

  • Configure the app to use iCloud.
  • Save the UUID that is in Keychain and NSUserDefaults.
  • Transfer the UUIDs to NSUserDefaults to the cloud with the data warehouse with the key.
  • On the first launch of the application, check if cloud data is available and set the UUID in the keychain on the new device.

You now have a unique identifier that is permanent and shared / synchronized with all devices.

+182
Dec 30 '11 at 7:21
source share

I updated the application that worked only with a unique identifier that supported iOS 4.3 and higher. So,

1) I was unable to use [UIDevice currentDevice].uniqueIdentifier; since it was no longer available

2) I could not use [UIDevice currentDevice].identifierForVendor.UUIDString because it was only available in iOS 6.0 and later and could not use it for lower versions of iOS.

3) The mac address was not an option since it was not allowed in iOS-7

4) OpenUDID was deprecated a while ago, and there were also problems with iOS-6.

5) Ad IDs are also not available for iOS-5 and below.

Finally, this is what I did

a) Added SFHFKeychainUtils to the project

b) Generated CFUUID key String

  CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault); udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid)); 

c) saved it in Key Chain Utils , otherwise it will generate a new unique every time

Final code

 + (NSString *)GetDeviceID { NSString *udidString; udidString = [self objectForKey:@"deviceID"]; if(!udidString) { CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault); udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid)); CFRelease(cfuuid); [self setObject:udidString forKey:@"deviceID"]; } return udidString; } +(void) setObject:(NSString*) object forKey:(NSString*) key { NSString *objectString = object; NSError *error = nil; [SFHFKeychainUtils storeUsername:key andPassword:objectString forServiceName:@"LIB" updateExisting:YES error:&error]; if(error) NSLog(@"%@", [error localizedDescription]); } +(NSString*) objectForKey:(NSString*) key { NSError *error = nil; NSString *object = [SFHFKeychainUtils getPasswordForUsername:key andServiceName:@"LIB" error:&error]; if(error) NSLog(@"%@", [error localizedDescription]); return object; } 

enter image description here

More details

+38
Oct 08 '13 at 12:10
source share

Some people want to know more about the different options available, and if so, take a look at the answer from @ NSQuamber.java. If you want to know how to use NSUUID and sync with iCloud, keep reading. This post turned out to be longer than I originally wanted, but I hope it makes it clear who will take these steps!

Using NSUUID

I use the NSUUID class to create the UUID:

 NSUUID *uuid = [NSUUID UUID]; 

Then, to create a string, you need to call the UUIDString method:

 NSString *uuidString = [uuid UUIDString]; 

or do it in one line:

 NSString *uuidString = [[NSUUID UUID] UUIDString]; 

IMHO, this is a lot easier than trying to use CFUUIDCreate and have a method that you must support.




EDIT: I am now using UICKeyChainStore

To set the UUID using UICKeyChainStore:

 UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"]; keychain[@"com.sample.MyApp.user"] = userID; 

To get it:

 UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"]; NSString *userID = keychain[@"com.sample.MyApp.user"]; 



Then I saved this UUID in the keychain using SSKeyChain

To set the UUID using SSKeyChain:

 [SSKeychain setPassword:userID forService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"]; 

To get it:

 NSString *userID = [SSKeychain passwordForService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"]; 

When you set the UUID in the keychain, it will be saved even if the user completely uninstalls the application and then installs it again.

Sync with iCloud

Therefore, it is useful to make sure that all user devices use the same UUID. This is done to ensure data synchronization on all devices, and not with each device that considers it a unique user.

In the comments to my answer there were several questions about how synchronization will work, so now that I have everything worked out, I will tell you more.

Configure iCloud / NSUbiquitousKeyValueStore Using

  • Click on your project at the top of Project Navigator in Xcode.
  • Choose features.
  • Enable iCloud.

Now it should look something like this: Screenshot of iCloud enabled

Using NSUbiquitousKeyValueStore

Using iCloud is pretty simple. To write:

 // create the UUID NSUUID *userUUID = [[NSUUID UUID]; // convert to string NSString *userID = [userUUID UUIDString]; // create the key to store the ID NSString *userKey = @"com.sample.MyApp.user"; // Save to iCloud [[NSUbiquitousKeyValueStore defaultStore] setString:userID forKey:userKey]; 

Count:

 // create the key to store the ID NSString *userKey = @"com.sample.MyApp.user"; // read from iCloud NSString *userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey]; 

Before you can write NSUbiquitousKeyValueStore documentation , you must first read iCloud. To force read, call the following method:

 [[NSUbiquitousKeyValueStore defaultStore] synchronize]; 

To get your application notified of changes in iCloud, add the following notification:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(iCloudStoreDidChange:) name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification object:[NSUbiquitousKeyValueStore defaultStore]]; 

Create UUIDs with iCloud

Combining NSUUID, SSKeychain and NSUbiquityKeyValueStore, here is my method for generating the user ID:

 - (NSUUID *)createUserID { NSString *userKey = @"com.sample.MyApp.user"; NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; NSString *userID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; if (userID) { return [[NSUUID UUID] initWithUUIDString:userID]; } // check iCloud userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey]; if (!userID) { // none in iCloud, create one NSUUID *newUUID = [NSUUID UUID]; userID = [newUUID UUIDString]; // save to iCloud [[NSUbiquitousKeyValueStore defaultStore] setString:userID forKey:userKey]; } // store the user ID locally [SSKeychain setPassword:userID forService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; return [[NSUUID UUID] initWithUUIDString:userID]; } 

How to keep your user ID in sync

Since writing to iCloud first requires loading any data into iCloud, I place the synchronization call at the beginning of the (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions . I also added registration posting there. This allows me to detect any changes from iCloud and process them accordingly.

Here is an example:

 NSString *const USER_KEY = @"com.sample.MyApp.user"; NSString *const KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; - (void)iCloudStoreDidChange:(NSNotification *)notification { NSDictionary *userInfo = notification.userInfo; NSNumber *changeReason = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey]; NSArray *keysChanged = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey]; if (changeReason) { switch ([changeReason intValue]) { default: case NSUbiquitousKeyValueStoreServerChange: case NSUbiquitousKeyValueStoreInitialSyncChange: // check changed keys for (NSString *keyChanged in keysChanged) { NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:keyChanged]; if (![keyChanged isEqualToString:USER_KEY]) { NSLog(@"Unknown key changed [%@:%@]", keyChanged, iCloudID); continue; } // get the local key NSString *localID = [SSKeychain passwordForService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER]; if (!iCloudID) { // no value from iCloud continue; } // local ID not created yet if (!localID) { // save the iCloud value locally [SSKeychain setPassword:iCloudID forService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER]; continue; // continue because there is no user information on the server, so no migration } if ([iCloudID isEqualToString:localID]) { // IDs match, so continue continue; } [self handleMigration:keyChanged from:localID to:iCloudID]; } break; case NSUbiquitousKeyValueStoreAccountChange: // need to delete all data and download new data from server break; } } } 

When the application starts or when it returns to the foreground, I force synchronization with iCloud and check the integrity of the UUID.

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [self configureSecKeyWrapper]; // synchronize data from iCloud first. If the User ID already exists, then we can initialize with it [[NSUbiquitousKeyValueStore defaultStore] synchronize]; [self checkUseriCloudSync]; } - (void)applicationWillEnterForeground:(UIApplication *)application { // synchronize changes from iCloud [[NSUbiquitousKeyValueStore defaultStore] synchronize]; [self checkUseriCloudSync]; } - (BOOL)checkUseriCloudSync { NSString *userKey = @"com.sample.MyApp.user"; NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; NSString *localID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey]; if (!iCloudID) { // iCloud does not have the key saved, so we write the key to iCloud [[NSUbiquitousKeyValueStore defaultStore] setString:localID forKey:userKey]; return YES; } if (!localID || [iCloudID isEqualToString:localID]) { return YES; } // both IDs exist, so we keep the one from iCloud since the functionality requires synchronization // before setting, so that means that it was the earliest one [self handleMigration:userKey from:localID to:iCloudID]; return NO; } 

If the first UUID came first

In my case of using my UserID, I suggested that the value in iCloud is what you need to save, as this will be the first UUID to be clicked on iCloud, regardless of which device generated the UUID first. Most of you are likely to follow the same path, since you won’t care which UUID it allows, as long as it allows one. For those of you who really care about what was first, I suggest you keep both the UUID and timestamp ( [[NSDate date] timeIntervalSince1970] ) so you can check which one is older:

 // using dates NSDate *uuid1Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp1]; NSDate *uuid2Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp2]; NSTimeInterval timeDifference = [uuid1 timeIntervalSinceDate:uuid2Timestamp]; // or just subtract double timeDifference = timestamp1 - timestamp2; 
+15
Jan 13 '14 at 17:13
source share

There is a good alternative on Github that generates a unique identifier based on a combination of MAC address and Bundle identifier, which works very well: UIDevice-with-UniqueIdentifier-for-iOS-5

+10
01 Sep '11 at 16:02
source share

In iOS7, Apple introduced the read only property, called the forVendor identifier, in the UIDevice class. If you decide to use it, you should pay attention to the following:

  • This value may be zero if it is accessed before the user unlocks the device.
  • The value changes when the user uninstalls all applications of these providers from the device and then reinstalls one or more of them.
  • The value may also change when installing test builds using Xcode or when installing an application on a device using ad-hoc distribution.

If you need an identifier for advertising purposes, use the advertisingIdentifier property of the ASIdentifierManager. However, note that the point discussed above remains true for this as well.

Source: https://developer.apple.com/library/ios/documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html#//apple_ref/occ/instp/UIDevice/identifierForVendor

+1
Sep 26 '13 at 5:36 on
source share

This is a really hot topic. I have an application that I have to run because it used the UDID to indicate the XML file that will be stored on the server. Then the device with the application will connect to the server and download its specific udid.xml and analyze its operation.

I thought that really, if the user switches to a new device, the application will break. So I really have to use something else. The fact is that I do not use a database for data. Data is simply stored in xml format, one xml file per device stored in the cloud.

I think that it would be best if the user filled in the data on the Internet, php would create a token on the fly, which would not be stored in the database, but rather sent to the user. The user can then enter the token on the target device and retrieve the corresponding XML request.

That would be my solution to the problem. Not sure how to implement all the “creation of unique tokens”.

0
Jan 06 2018-12-12T00:
source share



All Articles