2

I am trying to access Mac OS X UUID in cocoa programming using this code.

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

here uuid returns a unique id every time whenever I am accessing uuid, it keeps changing even I am not reinstalling app .I need to know how to access UUID in Mac OS X which will be same whether I am reinstalling app or recompiling, it should remain same.

In Ios i am able to achieve the same by below code.

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

Here iosuuid returns uuid which will remain same even when I am reinstalling and recompiling my app.

Don't suggest me to use Mac address, which I don't want to access for some purpose in my app.

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • `[[NSUUID UUID] UUIDString];` generates **a** UUID. Of course it's different every time! it's *supposed* to be different every time! `[[[UIDevice currentDevice] identifierForVendor] UUIDString];`, on the other hand, returns **the** identifier specific to *this* `[UIDevice currentDevice]`. It doesn't change because it's *stored* somewhere on device. – Kreiri Nov 13 '18 at 11:02
  • @Kreiri I want to access same for Mac OS X programming, how can I get device unique identifier in Mac OS X programming. – Gurpal Singh Rajput Nov 13 '18 at 11:19
  • 2
    You need to find Hardware UUID. Read here https://stackoverflow.com/questions/933460/unique-hardware-id-in-mac-os-x – ares777 Nov 13 '18 at 12:51

1 Answers1

4

In case somebody runs into this question looking for simple Objective-C solution - implementation like below worked for me (tested on macOS 11.2):

#import <IOKit/IOKitLib.h>

- (NSString *) getUUID {
    io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,IOServiceMatching("IOPlatformExpertDevice"));
    if (!platformExpert) return nil;

    CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,CFSTR(kIOPlatformUUIDKey),kCFAllocatorDefault, 0);

    IOObjectRelease(platformExpert);

    if (!serialNumberAsCFString) return nil;

    return (__bridge NSString *)(serialNumberAsCFString);;
}

For compiling add IOKit framework:

gcc -fobjc-arc -framework Cocoa -framework IOKit -x objective-c sources/** main.m -o app.bin

You can call this function with as simple as:

int main () {
    ..
    NSString *uuid = self.getUUID;
    NSLog(@"uuid: %@", uuid);
    ..
}
deevee
  • 1,550
  • 15
  • 21
  • Naive question: shouldn't `IOObjectRelease()` be called too in case of `if (!serialNumberAsCFString) return nil;` execution? – Arnaud Bouchez Oct 05 '22 at 06:56
  • @ArnaudBouchez thanks for your input! You're right, all the objects should be released when not needed anymore to prevent memory leaks, and in this snippet code could end execution and leave this object. I actually moved `IOObjectRelease` one line up in update – deevee Dec 01 '22 at 13:29
  • Thanks for this solution, but Xcode 13.4.1 still shows a memory leak, since `serialNumberAsCFString` is not released. I have replaced the return line with the following 3 lines: 1) Extract as string: `NSString *uuid = (__bridge NSString *)(valueAsCFString);` 2) Release: `CFRelease(valueAsCFString);` 3) Return the extracted string: `return uuid;` – Martijn Dec 10 '22 at 13:06