UDID and UUID alternative for iOS

As of iOS5, Apple no longer want you to use the UDID (Unique Device Identifier) in your iOS apps, and would prefer you to use a UUID instead (I posted about how to get a UUID earlier). However, the disadvantage of this is that a UUID only identifies an installation instance of the app, and does not identify the device. If the app is deleted and reinstalled even on the same device then you will end up with a new UUID and have no way to link them.

There is another alternative. Since all iOS devices (iPhones, iPads and iPods) have at least one network interface they all have at least one MAC address, and this is unique to the device and does not change. Therefore, a MAC address can be used to uniquely identify a device. I’m not sure how Apple will feel about people using this in the future, but for now at least it does provide a way to do exactly what a UDID did before and it is permitted in app store apps.

Here is some code for how to get the MAC address off an iOS device. I originally had another version here but it stopped working after an iOS upgrade so this working version came from here. Make sure you include the imports too…

#import <sys/sysctl.h>
#import <net/if_dl.h>
#import <arpa/inet.h>
#import <net/if.h>

#if !defined(IFT_ETHER)
#define IFT_ETHER 0×6/* Ethernet CSMACD */
#endif

@implementation MACAddress

+ (NSString *)MACAddress
{
int mgmtInfoBase[6];
char *msgBuffer = NULL;
size_t length;
unsigned char macAddress[6];
struct if_msghdr *interfaceMsgStruct;
struct sockaddr_dl *socketStruct;
NSString *errorFlag = NULL;

// Setup the management Information Base (mib)
mgmtInfoBase[0] = CTL_NET; // Request network subsystem
mgmtInfoBase[1] = AF_ROUTE; // Routing table info
mgmtInfoBase[2] = 0;
mgmtInfoBase[3] = AF_LINK; // Request link layer information
mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces

// With all configured interfaces requested, get handle index
if ((mgmtInfoBase[5] = if_nametoindex(“en0″)) == 0)
errorFlag = @”if_nametoindex failure”;
else
{
// Get the size of the data available (store in len)
if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
errorFlag = @”sysctl mgmtInfoBase failure”;
else
{
// Alloc memory based on above call
if ((msgBuffer = malloc(length)) == NULL)
errorFlag = @”buffer allocation failure”;
else
{
// Get system information, store in buffer
if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
errorFlag = @”sysctl msgBuffer failure”;
}
}
}

// Befor going any further…
if (errorFlag != NULL)
{
NSLog(@”Error: %@”, errorFlag);
free(msgBuffer);
return errorFlag;
}

// Map msgbuffer to interface message structure
interfaceMsgStruct = (struct if_msghdr *) msgBuffer;

// Map to link-level socket structure
socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);

// Copy link layer address data in socket structure to an array
memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);

// Read from char array into a string object, into traditional Mac address format
NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
macAddress[0], macAddress[1], macAddress[2],
macAddress[3], macAddress[4], macAddress[5]];
NSLog(@”Mac Address: %@”, macAddressString);

// Release the buffer memory
free(msgBuffer);

return macAddressString;
}

  • http://www.msebera.cz Marek Sebera
  • ABC

    You can also generate a unique ID and store it in the keychain. That will persist even if you uninstall the app.

  • James

    There are a couple of mistakes in MAC address retrieval code.

    First of all one of your includes has a v instead of a closing angle bracket

    #import <unistd.hv

    the for loop is wrong and it looks like what you meant was this.

    for(i=0; i sdl_alen; i++)

    and the way the code i setup right now it will return all maca address on the device concatenated together.

    I put a break in after the for loop and that seemed to fix it.

    After those three things it seemed to work great for me. Thanks for the post.

  • James

    I just realized what probably happened to your post as it just happened to mine as well. The angle brackets in the code are being treated as html tags and are being removed, so my second fix with the for loop should come out looking like this
    for(i=0; i < dlAddr->sdl_alen; i++)

    I can’t preview my post so I don’t know if the escapes will turn out right.

  • Rabindra

    Sorry to say but I don’t think your line ” If the app is deleted and reinstalled even on the same device then you will end up with a new UUID and have no way to link them” is correct.
    For a particular device (say A) all IOS device generates different UUID’s. But every time a particular IOS device generates always same UUID for that A.

  • Dart

    This method is no longer valid for iOS7 devices. The returned value will always be 02:00:00:00:00:00.