UIDevice uniqueIdentifier deprecated - What to do now?
Asked Answered
A

31

511

It has just come to light that the UIDevice uniqueIdentifier property is deprecated in iOS 5 and unavailable in iOS 7 and above. No alternative method or property appears to be available or forthcoming.

Many of our existing apps are tightly dependent on this property for uniquely identifying a particular device. How might we handle this problem going forward?

The suggestion from the documentation in 2011-2012 was:

Special Considerations

Do not use the uniqueIdentifier property. To create a unique identifier specific to your app, you can call the CFUUIDCreate function to create a UUID, and write it to the defaults database using the NSUserDefaults class.

However this value won't be the same if a user uninstalls and re-installs the app.

Apostrophe answered 9/8, 2011 at 8:27 Comment(3)
For apps still using uniqueIdentifier, iOS7 now returns FFFFFFFF + identifierForVendor which is breaking a lot of badly written non-renewing subscription apps.Quiet
If by luck your app uses Push Notifications, you can use the token sent back from apple's push service, it's unique per device as wellCallery
@CalinChitu If the user doesn't accept push notifications do you still get a pushID for that user?Vinculum
H
274

A UUID created by CFUUIDCreate is unique if a user uninstalls and re-installs the app: you will get a new one each time.

But you might want it to be not unique, i. e. it should stay the same when the user uninstalls and re-installs the app. This requires a bit of effort, since the most reliable per-device-identifier seems to be the MAC address. You could query the MAC and use that as UUID.

Edit: One needs to always query the MAC of the same interface, of course. I guess the best bet is with en0. The MAC is always present, even if the interface has no IP/is down.

Edit 2: As was pointed out by others, the preferred solution since iOS 6 is -[UIDevice identifierForVendor]. In most cases, you should be able use it as a drop-in replacement to the old -[UIDevice uniqueIdentifier] (but a UUID that is created when the app starts for the first time is what Apple seems to want you to use).

Edit 3: So this major point doesn't get lost in the comment noise: do not use the MAC as UUID, create a hash using the MAC. That hash will always create the same result every time, even across reinstalls and apps (if the hashing is done in the same way). Anyways, nowadays (2013) this isn't necessary any more except if you need a "stable" device identifier on iOS < 6.0.

Edit 4: In iOS 7, Apple now always returns a fixed value when querying the MAC to specifically thwart the MAC as base for an ID scheme. So you now really should use -[UIDevice identifierForVendor] or create a per-install UUID.

Heinrik answered 9/8, 2011 at 8:37 Comment(23)
Does the mac address not change depending on whether the user is connected via Wifi or not?Apostrophe
No, the IP does, but not the MAC. The MAC is unique to the interface.Heinrik
@DarkDust: but since the active interface changes when you switch from wifi to cellular modem, the MAC address of the active interface should also change; unless you always pick a particular interface to get the MACAlmallah
@user102008: I assumed it to be obvious to always query, say, en0, since the MAC is present even if the interface is down. But you're right, it probably isn't obvious.Heinrik
Just check it the first time, then stash it in the Keychain. It will persist even if the user uninstall/reinstalls the application. Someone mentioned this in another answer as well.Scintillation
Using MAC address is no longer a solution. Apple is going to crack down on it's usage, along with UDID. Apple is telling developers that MAC address is not the solution.Deify
Unique means it's the only one in existence. Unique does not mean it has to be changing every time. So either way if the UUID changes or not every time the app is re-installed or not, it is still unique if there are no other instances of the app with the same ID in existence.Preachy
And now please somebody tell me a way to use an identifier I can ask the customer to tell me, becaus i do not have the device and need to register his device...Fortification
@Jay Imerman: To get a UDID, you can simply hash the MAC of en0 just like suggested. It will identify the device and stay the same across apps and when you reinstall your app. Querying the UDID like you can see in iTunes is deprecated and might disappear soon (AFAIK Apple has even started rejecting apps using uniqueIdentifier, but I don't know for sure).Heinrik
Has anyone researched on legality aspect of Mac Address usage? If UUID were a problem with privacy for Apple, then MacAddresses can be even bigger problem.Worcestershire
@Roger Nolan: Please don't edit other people's answers and add stuff that looks like it came from the original author. Thanks.Heinrik
@AlfeG: With the proposed hashing of a MAC, the MAC itself would never be transmitted. But using a real UUID that you create on the first app start is considered to be the best solution.Heinrik
@Heinrik why? Isn't Stack OVerflow a community resource? I would guess that if SO wanted that behaviour they would enforce it. Still, you are free to edit on top of the other edits to show the history at the expense of readability if it's important to you.Speaks
@RogerNolan As long as post is not a community answer, the edits are for correcting mistakes and such things, not for adding new stuff. There's a reason you have earn the privilege. Imagine I edit your answer and write some BS, people would think you would've written that. I doubt you'd like that :-) But you don't get notified that an edit happened, I only found out by accident.Heinrik
@Heinrik I think that you earn the right so you don't edit in BS (as I didn't) but do add sensible upgrades that contribute to the greater resource. I think you are mistaken: SO is about knowledge and making answers as good as they can be, it is not about the sanctity of original postings. That said, I don't think it's worth carrying on the discussion :-)Speaks
Apple now rejects apps that uses hashed MAC.Burgle
@Burgle Not only that, if you check iOS 7 API changes, you won't be able to get MAC address at all.Henrique
@Heinrik So, in new iOS 7 and if i using CFUUIDCReate, i will not have any problems? Because, it seems, identifierForVendor is not work at perfectly, in some case will return a nil or 0x0Brood
@Heinrik There was a is not alternative of old UDID function. When user is reinstall app, then CFUUID is changing to another, so this CFUUID is just simple variable. Thanks for answerBrood
Of note: identifierForVendor became available in iOS 6.0 so it doesn't require iOS 7. To get a string from identifierForVendor you can use [[[UIDevice currentDevice] identifierForVendor] UUIDString]Rescissory
@Heinrik If I create UUID using CFUUIDCreate or use identifierForVendor, then it is getting changed on app re-install (removing app and installing again). Can you guide me what should I use as part of this to get life-time id on iOS6 onwards ?Cranio
In SWIFT this is the syntax UIDevice.currentDevice().identifierForVendor or if you want a string UIDevice.currentDevice().identifierForVendor!.UUIDString via How to get a unique device ID in SwiftHagiolatry
I believe the identifierForVendor changes upon app update.Diahann
P
92

You can use your alternative for Apple UDID already. Kind guy gekitz wrote category on UIDevice which will generate some kind of UDID based on device mac-address and bundle identifier.

You can find code on github

Polymath answered 22/8, 2011 at 8:40 Comment(9)
This implementation is unique (MAC address) for a device across reinstallations, like Apple's uniqueId, but also respect privacy, being also unique for an application (also use bundleId)... A must have imho, that Apple should include in its APIs... instead of deprecating w/o any alternatives.Ledda
Although it uses the old style bsd license with the advertising clause, yuck.Ajar
For anyone else now finding this post, the license has been changed since the above comment by jbtule.Soppy
I don't think that this is too secure. (it may not matter to you) There are 10^14 mac addresses possible. Going through all of them is only about an hour on a fast machine to get the Mac address given the hash. whitepixel.zorinaq.com. Adding the bundle ID does not help, as most would know the bundleID to check.Reeva
@TomAndersen there are also some formula about how to calculate real device UDID, so if someone would like to find something, he could do so. This code was suggested for developers, to somehow get unique device ID, it doesn't take into account all those who want to trick backends.Polymath
What about when the phone is sold? What about when you buy a new phone and transfer all your data?Hankow
As discussed in this commit comment, the library as-is poses a serious privacy leak issue and should not be used:Drown
As mentioned by others, this library does pose a serious privacy leaks: github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5/…Kragh
Starting from iOS 7, the system always returns the value 02:00:00:00:00:00 when you ask for the MAC address on any device. Check here: developer.apple.com/library/prerelease/ios/releasenotes/General/…Emmanuelemmeline
C
61

Based on the link proposed by @moonlight, i did several tests and it seems to be the best solution. As @DarkDust says the method goes to check en0 which is always available.
There are 2 options:
uniqueDeviceIdentifier (MD5 of MAC+CFBundleIdentifier)
and uniqueGlobalDeviceIdentifier(MD5 of the MAC), these always returns the same values.
Below the tests i've done (with the real device):

#import "UIDevice+IdentifierAddition.h"

NSLog(@"%@",[[UIDevice currentDevice] uniqueDeviceIdentifier]);
NSLog(@"%@",[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier]);

XXXX21f1f19edff198e2a2356bf4XXXX - (WIFI)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (WIFI)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (3G)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (3G)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (GPRS)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (GPRS)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (AirPlane mode)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (AirPlane mode)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi)after removing and reinstalling the app XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) after removing and installing the app

Hope it's useful.

EDIT:
As others pointed out, this solution in iOS 7 is no longer useful since uniqueIdentifier is no longer available and querying for MAC address now returns always 02:00:00:00:00:00

Casmey answered 24/10, 2011 at 9:32 Comment(2)
this wont work on iOS7, Apple eliminates the use of MAC address.Danikadanila
@SarimSidd For now informations about iOS 7 are under NDA, we can't discuss here.Casmey
G
57

check this out,

we can use Keychain instead of NSUserDefaults class, to store UUID created by CFUUIDCreate.

with this way we could avoid for UUID recreation with reinstallation, and obtain always same UUID for same application even user uninstall and reinstall again.

UUID will recreated just when device reset by user.

I tried this method with SFHFKeychainUtils and it's works like a charm.

Goalkeeper answered 6/3, 2012 at 15:16 Comment(3)
This method is a solid replacement for UDID. It also has the added benefit of recreating the identifier upon device format (eg. if the device changes owner). However, it's important to note that the keychain can be restored to other devices if the user encrypts their backup. This can result in a situation where multiple devices share the same UUID. To avoid this, set the accessibility of your keychain item to kSecAttrAccessibleAlwaysThisDeviceOnly. This will ensure that your UUID does not migrate to any other device. To access your UUID from other apps, utilise the kSecAttrAccessGroup key.Business
Where exactly (which key) are you supposed to use to store the UUID in keychain?Exsert
Opps! link is brokenMalena
V
48

Create your own UUID and then store it in the Keychain. Thus it persists even when your app gets uninstalled. In many cases it also persists even if the user migrates between devices (e.g. full backup and restore to another device).

Effectively it becomes a unique user identifier as far as you're concerned. (even better than device identifier).

Example:

I am defining a custom method for creating a UUID as :

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

You can then store it in KEYCHAIN on the very first launch of your app. So that after first launch, we can simply use it from keychain, no need to regenerate it. The main reason for using Keychain to store is: When you set the UUID to the Keychain, it will persist even if the user completely uninstalls the App and then installs it again. . So, this is the permanent way of storing it, which means the key will be unique all the way.

     #import "SSKeychain.h"
     #import <Security/Security.h>

On applictaion launch include the following code :

 // getting the unique key (if present ) from keychain , assuming "your app identifier" as a key
       NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
      if (retrieveuuid == nil) { // if this is the first time app lunching , create key for device
        NSString *uuid  = [self createNewUUID];
// save newly created key to Keychain
        [SSKeychain setPassword:uuid forService:@"your app identifier" account:@"user"];
// this is the one time process
}

Download SSKeychain.m and .h file from sskeychain and Drag SSKeychain.m and .h file to your project and add "Security.framework" to your project. To use UUID afterwards simply use :

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
Villatoro answered 20/9, 2012 at 11:3 Comment(3)
Because a identifierForVendor is working is not perfectly. In some case can return a nil or 0x0. This method it seems is working at perfectlyBrood
anyone validated this is working on iOS7 after uninstall/reinstall cycle + verified apple app submission?Skirt
I've started using this solution. Several tests on 2 devices (rebuild, reinstall, device shut down) showed me that id is the same. iOS 10.3.Sculpt
B
16

Perhaps you can use:

[UIDevice currentDevice].identifierForVendor.UUIDString

Apple's documentation describes identifierForVender as follows:

The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.

Boudreau answered 15/1, 2013 at 18:43 Comment(3)
Curious why nobody brought this up until recently... And now I see it's new with iOS 6.Hepner
If user update ios and/or install new ios then value of identifierForVendor will change or remain same?Formulism
After remove all apps from same vendor then this value will be changed.Clot
L
14

You may want to consider using OpenUDID which is a drop-in replacement for the deprecated UDID.

Basically, to match the UDID, the following features are required:

  1. unique or sufficiently unique (a low probability collision is probably very acceptable)
  2. persistence across reboots, restores, uninstalls
  3. available across apps of different vendors (useful to acquire users via CPI networks) -

OpenUDID fulfills the above and even has a built-in Opt-Out mechanism for later consideration.

Check http://OpenUDID.org it points to the corresponding GitHub. Hope this helps!

As a side note, I would shy away from any MAC address alternative. While the MAC address appears like a tempting and universal solution, be sure that this low hanging fruit is poisoned. The MAC address is very sensitive, and Apple may very well deprecate access to this one before you can even say "SUBMIT THIS APP"... the MAC network address is used to authenticate certain devices on private lans (WLANs) or other virtual private networks (VPNs). .. it's even more sensitive than the former UDID!

Luong answered 28/3, 2012 at 19:16 Comment(4)
I'm really curious how this works? The code is written in Objective-C, but there is no other good solution that fits the requirements above, so what makes this framework different? The solution that this framework is using should also be possible to post as a suggested answer here...Preachy
I concur - MAC address can be manually configured as well ("cloned"), although it is not likely for the most part. I must protest the D in UDID. This is not a Device ID, it is a UUID (Universally Unique Identifier). The Device ID is stamped by Apple from the factory on each device in ROM.Pitiable
Best solution for iOS7 as well does whats actually needed to identify a device uniquelyLanguorous
OpenUDID is deprecated and not recommended to useJuryrig
H
11

I'm sure Apple have annoyed many people with this change. I develop a bookkeeping app for iOS and have an online service to sync changes made on different devices. The service maintains a database of all devices and the changes that need to be propagated to them. Therefore it's important to know which devices are which. I'm keeping track of devices using the UIDevice uniqueIdentifier and for what it's worth, here are my thoughts.

  • Generate a UUID and store in user defaults? No good because this does not persist when the user deletes the app. If they install again later the online service should not create a new device record, that would waste resources on the server and give a list of devices containing the same one two or more times. Users would see more than one "Bob's iPhone" listed if they re-installed the app.

  • Generate a UUID and store in the keychain? This was my plan, since it persists even when the app is uninstalled. But when restoring an iTunes backup to a new iOS device, the keychain is transferred if the backup is encrypted. This could lead to two devices containing the same device id if the old and new devices are both in service. These should be listed as two devices in the online service, even if the device name is the same.

  • Generate a hash the MAC address and bundle id? This looks like the best solution for what I need. By hashing with the bundle id, the generated device id is not going to enable the device to be tracked across apps and I get a unique ID for the app+device combination.

It's interesting to note that Apple's own documentation refers to validating Mac App Store receipts by computing a hash of the system MAC address plus the bundle id and version. So this seems allowable by policy, whether it passes through app review I don't yet know.

Hygrometer answered 13/4, 2012 at 15:10 Comment(2)
To avoid the situation described in your second point, set the accessibility of your keychain item to kSecAttrAccessibleAlwaysThisDeviceOnly. This will ensure that your UUID does not restore to other devices, even if the backup is encrypted.Business
This is indeed the behavior I have seen many times. For example, I register my iPhone for Google Sync. Then I got a new iPhone, register it, and voila - I now have 2 iPhones listed in my Sync settings.Pitiable
G
11

It looks like for iOS 6, Apple is recommending you use the NSUUID class.

From the message now in the UIDevice docs for uniqueIdentifier property:

Deprecated in iOS 5.0. Use the identifierForVendor property of this class or the advertisingIdentifier property of the ASIdentifierManager class instead, as appropriate, or use the UUID method of the NSUUID class to create a UUID and write it to the user defaults database.

Guidepost answered 1/10, 2012 at 9:27 Comment(0)
J
10

May help: use below code it will always Unique except you erase(Format) your device.

Objective-C:

Option 1: This will change on every install

UIDevice *uuid = [NSUUID UUID].UUIDString;

Option 2: This will be unique per vendor/Developer Apple Account

UIDevice *myDevice = [UIDevice currentDevice];
NSString *uuid = [[myDevice identifierForVendor] UUIDString];

Swift 5.X:

Option 1: This will change on every install

let uuid = UUID().uuidString

Option 2: This will be unique per vendor/Developer Apple Account

let myDevice = UIDevice.current
let uuid = myDevice.identifierForVendor?.uuidString
Jerricajerrie answered 12/3, 2013 at 9:27 Comment(3)
I used this code. But when I deleted app and again installed I got new IdConsumer
this is a simple solution if you don't need a robust method. i'm using it in my app now.Summary
@Consumer : it will change always becuase its depend on vendor. For example : 1. If you have install a app with bundleidenedifier : com.abcd.com => then it will change. 2. If you have install two app with bundleidenedifier : com.abcd.com => Then it will not chnage (Keep any one app during)Jerricajerrie
D
7

I would also suggest changing over from uniqueIdentifier to this open source library (2 simple categories really) that utilize the device’s MAC Address along with the App Bundle Identifier to generate a unique ID in your applications that can be used as a UDID replacement.

Keep in mind that unlike the UDID this number will be different for every app.

You simply need to import the included NSString and UIDevice categories and call [[UIDevice currentDevice] uniqueDeviceIdentifier] like so:

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"
NSString *iosFiveUDID = [[UIDevice currentDevice] uniqueDeviceIdentifier]

You can find it on Github here:

UIDevice with UniqueIdentifier for iOS 5


Here are the categories (just the .m files - check the github project for the headers):

UIDevice+IdentifierAddition.m

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"

#include <sys/socket.h> // Per msqr
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>

@interface UIDevice(Private)

- (NSString *) macaddress;

@end

@implementation UIDevice (IdentifierAddition)

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Private Methods

// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb.
- (NSString *) macaddress{
    
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;
    
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    
    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
    
    if ((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. error!\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        return NULL;
    }
    
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    
    return outstring;
}

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Public Methods

- (NSString *) uniqueDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];  
    NSString *stringToHash = [NSString stringWithFormat:@"%@%@",macaddress,bundleIdentifier];
    NSString *uniqueIdentifier = [stringToHash stringFromMD5];  
    return uniqueIdentifier;
}

- (NSString *) uniqueGlobalDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *uniqueIdentifier = [macaddress stringFromMD5];    
    return uniqueIdentifier;
}

@end

NSString+MD5Addition.m:

#import "NSString+MD5Addition.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSString(MD5Addition)

- (NSString *) stringFromMD5{
    
    if(self == nil || [self length] == 0)
        return nil;
    
    const char *value = [self 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]];
    }
    return [outputString autorelease];
}

@end
Dentist answered 30/10, 2011 at 18:17 Comment(1)
Starting in iOS 7, Apple will return a constant value for the MAC address. It makes perfect sense. The MAC address is sensitive.Cyclohexane
B
4

The MAC address can be spoofed which makes such an approach useless for tying content to specific users or implementing security features like blacklists.

After some further research it appears to me that we're left without a proper alternative as of now. I seriously hope Apple will reconsider their decision.

Maybe it would be a good idea to email Apple about this topic and / or file a bug / feature request on this since maybe they are not even aware of the full consequences for developers.

Brachiopod answered 10/8, 2011 at 12:12 Comment(5)
A valid point however I believe the UUID can also be spoofed/swizzled on a jailbroken phone so technically the existing [UIDevice uniqueIdentifier] is just as flawed.Apostrophe
You can always create an identifier on server and save it on device. That's how most application do it. I don't understand why iOS programmers need something special.Henrique
@Henrique doesn't work on iOS because if you uninstall an app all its data is gone, so there is no way to guarantee an unique device identifier that way.Machmeter
Not if you save it to keychain. Anyway, I have never seen an app where this was a problem. If the app and data has been deleted, you don't need the same device identifier. If you want to identify the user, ask him for email.Henrique
MAC address access has also been banned by Apple in new release of iOS;Deepset
M
4

UIDevice identifierForVendor introduced in iOS 6 would work for your purposes.

identifierForVendor is an alphanumeric string that uniquely identifies a device to the app’s vendor. (read-only)

@property(nonatomic, readonly, retain) NSUUID *identifierForVendor

The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps onthe same device that come from different vendors, and for apps on different devices regardles of vendor.

Available in iOS 6.0 and later and declared in UIDevice.h

For iOS 5 refer this link UIDevice-with-UniqueIdentifier-for-iOS-5

Milinda answered 8/4, 2013 at 11:56 Comment(0)
H
4

Using the SSKeychain and code mentioned above. Here's code to copy/paste (add SSKeychain module):

+(NSString *) getUUID {

//Use the bundle name as the App identifier. No need to get the localized version.

NSString *Appname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];    

//Check if we have UUID already

NSString *retrieveuuid = [SSKeychain passwordForService:Appname account:@"user"];

if (retrieveuuid == NULL)
{

    //Create new key for this app/device

    CFUUIDRef newUniqueId = CFUUIDCreate(kCFAllocatorDefault);

    retrieveuuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, newUniqueId);

    CFRelease(newUniqueId);

    //Save key to Keychain
    [SSKeychain setPassword:retrieveuuid forService:Appname account:@"user"];
}

return retrieveuuid;

}

Handwriting answered 4/9, 2013 at 12:9 Comment(0)
V
3

Following code helps to get UDID:

        udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
        NSLog(@"UDID : %@", udid);
Villager answered 9/8, 2013 at 18:40 Comment(0)
I
3

This is code I'm using to get ID for both iOS 5 and iOS 6, 7:

- (NSString *) advertisingIdentifier
{
    if (!NSClassFromString(@"ASIdentifierManager")) {
        SEL selector = NSSelectorFromString(@"uniqueIdentifier");
        if ([[UIDevice currentDevice] respondsToSelector:selector]) {
            return [[UIDevice currentDevice] performSelector:selector];
        }
    }
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}
Irritate answered 17/9, 2013 at 10:15 Comment(2)
What do you do about the compiler warning PerformSelector may cause a leak because its selector is unknown?Portsalut
You can no more use advertisingIdentifier for this purpose as Apple will reject it. More info: techcrunch.com/2014/02/03/…Marolda
V
2

From iOS 6 onwards, we have NSUUID class which complies RFC4122

Apple Link : apple_ref for NSUUID

Varve answered 17/10, 2012 at 11:57 Comment(0)
M
2

iOS 11 has introduced the DeviceCheck framework. It has a fullproof solution for uniquely identifying the device.

Mixon answered 21/6, 2017 at 4:56 Comment(0)
R
1

You can use

NSString *sID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

Which is unique for the device in all application.

Renferd answered 25/2, 2014 at 5:34 Comment(0)
B
1

A working way to get UDID:

  1. Launch a web server inside the app with two pages: one should return specially crafted MobileConfiguration profile and another should collect UDID. More info here, here and here.
  2. You open the first page in Mobile Safari from inside the app and it redirects you to Settings.app asking to install configuration profile. After you install the profile, UDID is sent to the second web page and you can access it from inside the app. (Settings.app has all necessary entitlements and different sandbox rules).

An example using RoutingHTTPServer:

import UIKit
import RoutingHTTPServer

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var bgTask = UIBackgroundTaskInvalid
    let server = HTTPServer()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        application.openURL(NSURL(string: "http://localhost:55555")!)
        return true
    }

    func applicationDidEnterBackground(application: UIApplication) {
        bgTask = application.beginBackgroundTaskWithExpirationHandler() {
            dispatch_async(dispatch_get_main_queue()) {[unowned self] in
                application.endBackgroundTask(self.bgTask)
                self.bgTask = UIBackgroundTaskInvalid
            }
        }
    }
}

class HTTPServer: RoutingHTTPServer {
    override init() {
        super.init()
        setPort(55555)
        handleMethod("GET", withPath: "/") {
            $1.setHeader("Content-Type", value: "application/x-apple-aspen-config")
            $1.respondWithData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("udid", ofType: "mobileconfig")!)!)
        }
        handleMethod("POST", withPath: "/") {
            let raw = NSString(data:$0.body(), encoding:NSISOLatin1StringEncoding) as! String
            let plistString = raw.substringWithRange(Range(start: raw.rangeOfString("<?xml")!.startIndex,end: raw.rangeOfString("</plist>")!.endIndex))
            let plist = NSPropertyListSerialization.propertyListWithData(plistString.dataUsingEncoding(NSISOLatin1StringEncoding)!, options: .allZeros, format: nil, error: nil) as! [String:String]

            let udid = plist["UDID"]! 
            println(udid) // Here is your UDID!

            $1.statusCode = 200
            $1.respondWithString("see https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html")
        }
        start(nil)
    }
}

Here are the contents of udid.mobileconfig:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>PayloadContent</key>
        <dict>
            <key>URL</key>
            <string>http://localhost:55555</string>
            <key>DeviceAttributes</key>
            <array>
                <string>IMEI</string>
                <string>UDID</string>
                <string>PRODUCT</string>
                <string>VERSION</string>
                <string>SERIAL</string>
            </array>
        </dict>
        <key>PayloadOrganization</key>
        <string>udid</string>
        <key>PayloadDisplayName</key>
        <string>Get Your UDID</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>PayloadUUID</key>
        <string>9CF421B3-9853-9999-BC8A-982CBD3C907C</string>
        <key>PayloadIdentifier</key>
        <string>udid</string>
        <key>PayloadDescription</key>
        <string>Install this temporary profile to find and display your current device's UDID. It is automatically removed from device right after you get your UDID.</string>
        <key>PayloadType</key>
        <string>Profile Service</string>
    </dict>
</plist>

The profile installation will fail (I didn't bother to implement an expected response, see documentation), but the app will get a correct UDID. And you should also sign the mobileconfig.

Bergh answered 4/6, 2015 at 17:55 Comment(0)
C
1

For Swift 3.0 please use below code.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)
Cribb answered 17/9, 2016 at 5:22 Comment(1)
iOS 11 has introduced the DeviceCheck framework. It has a fullproof solution for uniquely identifying the device.Mixon
M
1

Apple has added a new framework in iOS 11 called DeviceCheck which will help you to get the unique identifier very easily. Read this form more information. https://medium.com/@santoshbotre01/unique-identifier-for-the-ios-devices-590bb778290d

Mixon answered 24/8, 2017 at 5:28 Comment(2)
But it needs an internet connection, isn't it?Natty
Yes it needs an internet connection.Mixon
E
0

If someone stumble upon to this question, when searching for an alternative. I have followed this approach in IDManager class, This is a collection from different solutions. KeyChainUtil is a wrapper to read from keychain. You can also use the hashed MAC address as a kind of unique ID.

/*  Apple confirmed this bug in their system in response to a Technical Support Incident 
    request. They said that identifierForVendor and advertisingIdentifier sometimes 
    returning all zeros can be seen both in development builds and apps downloaded over the 
    air from the App Store. They have no work around and can't say when the problem will be fixed. */
#define kBuggyASIID             @"00000000-0000-0000-0000-000000000000"

+ (NSString *) getUniqueID {
    if (NSClassFromString(@"ASIdentifierManager")) {
        NSString * asiID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
        if ([asiID compare:kBuggyASIID] == NSOrderedSame) {
            NSLog(@"Error: This device return buggy advertisingIdentifier.");
            return [IDManager getUniqueUUID];
        } else {
            return asiID;
        }

    } else {
        return [IDManager getUniqueUUID];
    }
}


+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService 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:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

/* NSUUID is after iOS 6. */
+ (NSString *)GetUUID
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

#pragma mark - MAC address
// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Last fallback for unique identifier
+ (NSString *) getMACAddress
{
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;

    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;

    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }

    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }

    if ((buf = malloc(len)) == NULL) {
        printf("Error: Memory allocation error\n");
        return NULL;
    }

    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2\n");
        free(buf); // Thanks, Remy "Psy" Demerest
        return NULL;
    }

    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];

    free(buf);
    return outstring;
}

+ (NSString *) getHashedMACAddress
{
    NSString * mac = [IDManager getMACAddress];
    return [Util md5String:mac];
}

+ (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];
    [outputString release];
    return retString;
}
Eureka answered 13/5, 2013 at 15:8 Comment(0)
B
0
+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService 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:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}
Bonnice answered 26/11, 2013 at 9:25 Comment(0)
S
0

We can use identifierForVendor for ios7,

-(NSString*)uniqueIDForDevice
{
    NSString* uniqueIdentifier = nil;
    if( [UIDevice instancesRespondToSelector:@selector(identifierForVendor)] ) { // >=iOS 7
        uniqueIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    } else { //<=iOS6, Use UDID of Device       
            CFUUIDRef uuid = CFUUIDCreate(NULL);
            //uniqueIdentifier = ( NSString*)CFUUIDCreateString(NULL, uuid);- for non- ARC
            uniqueIdentifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));// for ARC
            CFRelease(uuid);
         }
    }
return uniqueIdentifier;
}

--Important Note ---

UDID and identifierForVendor are different:---

1.) On uninstalling  and reinstalling the app identifierForVendor will change.

2.) The value of identifierForVendor remains the same for all the apps installed from the same vendor on the device.

3.) The value of identifierForVendor also changes for all the apps if any of the app (from same vendor) is reinstalled.
Silberman answered 3/12, 2013 at 9:19 Comment(1)
are you sure ? can we use identifierForVendor for ios7,?Sump
P
0

Apple has hidden the UDID from all public APIs, starting with iOS 7. Any UDID that begins with FFFF is a fake ID. The "Send UDID" apps that previously worked can no longer be used to gather UDID for test devices. (sigh!)

The UDID is shown when a device is connected to XCode (in the organizer), and when the device is connected to iTunes (although you have to click on 'Serial Number' to get the Identifier to display.

If you need to get the UDID for a device to add to a provisioning profile, and can't do it yourself in XCode, you will have to walk them through the steps to copy/paste it from iTunes.

Is there a way since (iOS 7's release) to get the UDID without using iTunes on a PC/Mac?

Publisher answered 23/1, 2014 at 8:26 Comment(0)
Q
0

I had got some issue too, and solution is simple:

    // Get Bundle Info for Remote Registration (handy if you have more than one app)
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];


    // Get the users Device Model, Display Name, Unique ID, Token & Version Number
    UIDevice *dev = [UIDevice currentDevice];
    NSString *deviceUuid=[dev.identifierForVendor  UUIDString];

    NSString *deviceName = dev.name;
Quackenbush answered 18/4, 2014 at 19:39 Comment(0)
B
0

A not perfect but one of the best and closest alternative to UDID (in Swift using iOS 8.1 and Xcode 6.1):

Generating a random UUID

let strUUID: String = NSUUID().UUIDString

And use KeychainWrapper library:

Add a string value to keychain:

let saveSuccessful: Bool = KeychainWrapper.setString("Some String", forKey: "myKey")

Retrieve a string value from keychain:

let retrievedString: String? = KeychainWrapper.stringForKey("myKey")

Remove a string value from keychain:

let removeSuccessful: Bool = KeychainWrapper.removeObjectForKey("myKey")

This solution uses the keychain, thus the record stored in the keychain will be persisted, even after the app is uninstalled and reinstalled. The only way of deleting this record is to Reset all contents and settings of the device. That is why I mentioned that this solution of substitution is not perfect but stays one of the best solution of replacement for UDID on iOS 8.1 using Swift.

Barbitone answered 1/12, 2014 at 1:52 Comment(0)
M
-1

Dont use these libraries - libOmnitureAppMeasurement, It does use uniqueIdentifier which apple doesnt support anymore

Marlo answered 5/6, 2013 at 14:41 Comment(0)
E
-1

NSLog(@"%@",[[UIDevice currentDevice]identifierForVendor]);

Ehrlich answered 30/12, 2016 at 16:24 Comment(0)
E
-2

Little hack for you:

/**
 @method uniqueDeviceIdentifier
 @abstract A unique device identifier is a hash value composed from various hardware identifiers such
 as the device’s serial number. It is guaranteed to be unique for every device but cannot 
 be tied to a user account. [UIDevice Class Reference]
 @return An 1-way hashed identifier unique to this device.
 */
+ (NSString *)uniqueDeviceIdentifier {      
    NSString *systemId = nil;
    // We collect it as long as it is available along with a randomly generated ID.
    // This way, when this becomes unavailable we can map existing users so the
    // new vs returning counts do not break.
    if (([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0f)) {
        SEL udidSelector = NSSelectorFromString(@"uniqueIdentifier");
        if ([[UIDevice currentDevice] respondsToSelector:udidSelector]) {
            systemId = [[UIDevice currentDevice] performSelector:udidSelector];
        }
    }
    else {
        systemId = [NSUUID UUID];
    }
    return systemId;
}
Exophthalmos answered 17/5, 2013 at 8:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.