2

I want to use an alternative to the UDID and found this:

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

but in the simulator the method gives me different results every session?

Is this only in simulator?

I need to be sure that on actual devices the method returns me always the same string to identify a user.

Is it true or not?

Mirza

6 Answers6

1

CFUUIDCreate gives you a Universally Unique Identifier every time you call that function, so each time you will get a different result (by definition).

What you can do is persist this in between sessions using, for example, NSUserDefaults, to uniquely identify a particular user (or bunch of user's settings).

David Doyle
  • 1,697
  • 10
  • 22
1

CFUUIDRef will create different values at each session.

Solution 1:

Save the value in NSUserDefaults and next time onwards use it from the NSUserDefaults.

Solution 2:

You can use identifierForVendor for doing this.

NSString *udidVendor = [[[UIDevice currentDevice] identifierForVendor] UUIDString];

According to UIDevice Class Reference:

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.

Please check Unique Identifier In iOS 6

Midhun MP
  • 90,682
  • 30
  • 147
  • 191
0

CFUUID is not persisted at all.

Every time you call CFUUIDCreate the system will return to you a brand new unique identifier.

If you want to persist this identifier you will need to do that yourself using NSUserDefaults, Keychain, Pasteboard or some other means.

CRDave
  • 9,133
  • 5
  • 38
  • 58
0

Read the code one line at a time and try to understand what it does. The CFUUIDCreate function creates a new UUID every time you call it. That would explain your finding. You need to save the value in NSUserDefaults* the first time and use that value the next time you launch the app:

+ (NSString *)GetUUID
{
    NSString *string = [[NSUserDefaults standardUserDefaults] objectForKey: @"UUID"];
    if (!string)
    {
        CFUUIDRef theUUID = CFUUIDCreate(NULL);
        string = (NSString*)[CFUUIDCreateString(NULL, theUUID) autorelease];
        CFRelease(theUUID);
        [[NSUserDefaults standardUserDefaults] setObject: string forKey: @"UUID"];
    }
    return string;
}

*There are one small caveat of using NSUserDefaults - UUID will be created again if user uninstalls and reinstalls the app again. If you can't live with this, look into saving it in Keychain. Alternatively, you might want to look at OpenUDID.

Mar0ux
  • 3,654
  • 3
  • 21
  • 30
0

It is always different. UUID includes timestamps, so every time you call this function, you will get a different (random) one. I have followed this approach in IDManager class, This is a collection from different solutions. KeyChainUtil is a wrapper to read from keychain. A similar keychain util is found in github.

//  IDManager.m


/*
 A replacement for deprecated uniqueIdentifier API. Apple restrict using this from 1st May, 2013.

 We have to consider,
    * iOS <6 have not the ASIIdentifer API
    * When the user upgrade from iOS < 6 to >6
        - Check if there is a UUID already stored in keychain. Then use that. 
            - In that case, this UUID is constant for whole device lifetime. Keychain item is not deleted with application deletion.
 */

#import "IDManager.h"
#import "KeychainUtils.h"
#import "CommonUtil.h"

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
    #import <AdSupport/AdSupport.h>
#endif

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



/*  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"


#pragma mark 


#pragma mark 

@implementation IDManager

+ (NSString *) getUniqueID {

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000

    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 {

#endif

        return [IDManager getUniqueUUID];

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
    }
#endif

}

+ (NSString *) getUniqueUUID 
{
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:@"UserName" andServiceName:@"YourServiceName" 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 = [CommonUtil md5String:uuid]; // create md5 hash for security reason
        [KeychainUtils storeUsername:@"UserName" andPassword:uuid forServiceName:@"YourServiceName" updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

+ (NSString *) readUUIDFromKeyChain {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:@"UserName" andServiceName:@"YourServiceName" error:&error];
    if (error) {
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    }
    return uuid;
}

/* NSUUID is after iOS 6. So we are using CFUUID for compatibility with iOS 4.3 */
+ (NSString *)getUUID
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

#pragma mark - MAC address

/* THIS WILL NOT WORK IN iOS 7. IT WILL RETURN A CONSTANT MAC ADDRESS ALL THE TIME.
 SEE - https://developer.apple.com/news/?id=8222013a
 */

// Return the local MAC address
// 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 [CommonUtil md5String:mac];
}

@end
karim
  • 14,810
  • 7
  • 55
  • 92
0

The method will always return a unique string. If the app will only ever have a single user, run this method once when the user first launches the app and persist that string in a plist, or NSUserDefaults, or core data if you've already using it.

The link below may help with this UUID persistence logic: UUID for app on iOS5

However, if the user then uninstalls and reinstalls the app, this persisted UUID will still be lost and need will be generated again.

Device IDs are also no longer allowed by Apple.

Assuming the UUID is required because the app connects to a server, as far as I know, you need the user log in to the server with a user name and password.

Community
  • 1
  • 1
Steve
  • 948
  • 1
  • 11
  • 23