2009-06-01 16 views
26

El desarrollo de Mac OS X es un animal bastante nuevo para mí, y estoy en el proceso de migrar a través de algún software. Para la licencia de software y el registro, debo ser capaz de generar algún tipo de identificación de hardware. No tiene que ser nada sofisticado; Dirección MAC de Ethernet, serie de disco duro, serie de CPU, algo así.ID de hardware único en Mac OS X

Lo tengo cubierto en Windows, pero no tengo ni idea en Mac. ¡Cualquier idea de lo que tengo que hacer, o dónde puedo obtener información sobre esto sería genial!

Editar:

Para cualquier otra persona que esté interesada en esto, este es el código que terminé usando con la clase QProcess de Qt:

QProcess proc; 

QStringList args; 
args << "-c" << "ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { print $3; }'"; 
proc.start("/bin/bash", args); 
proc.waitForFinished(); 

QString uID = proc.readAll(); 

Nota: Estoy usando C++.

Respuesta

14

Prueba este comando en el terminal:

ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { split($0, line, "\""); printf("%s\n", line[4]); }' 

De here

aquí es que comando envuelto en Cacao (que probablemente se podría hacer un poco más limpio):

NSArray * args = [NSArray arrayWithObjects:@"-rd1", @"-c", @"IOPlatformExpertDevice", @"|", @"grep", @"model", nil]; 
NSTask * task = [NSTask new]; 
[task setLaunchPath:@"/usr/sbin/ioreg"]; 
[task setArguments:args]; 

NSPipe * pipe = [NSPipe new]; 
[task setStandardOutput:pipe]; 
[task launch]; 

NSArray * args2 = [NSArray arrayWithObjects:@"/IOPlatformUUID/ { split($0, line, \"\\\"\"); printf(\"%s\\n\", line[4]); }", nil]; 
NSTask * task2 = [NSTask new]; 
[task2 setLaunchPath:@"/usr/bin/awk"]; 
[task2 setArguments:args2]; 

NSPipe * pipe2 = [NSPipe new]; 
[task2 setStandardInput:pipe]; 
[task2 setStandardOutput:pipe2]; 
NSFileHandle * fileHandle2 = [pipe2 fileHandleForReading]; 
[task2 launch]; 

NSData * data = [fileHandle2 readDataToEndOfFile]; 
NSString * uuid = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
+0

Gracias, esta parece ser la forma en que funciona mejor. La salida de System Profiler parece variar en diferentes sistemas, por lo que me da miedo que una avalancha de llamadas de soporte no pueda registrar el software. – Gerald

+0

Sin embargo, esta técnica es fácil de descifrar: simplemente reemplace '/ usr/sbin/ioreg' con un script que devuelva un UUID conocido (en lugar de un UUID específico de la máquina). Llamar directamente a las bibliotecas del sistema (por ejemplo, la respuesta de @ yairchu) hará que el crackeo sea menos trivial. – smokris

+0

@smokris de lo contrario, ¿es equivalente a IORegistryEntryFromPath? – tofutim

1

de reproducción:

system_profiler | grep 'Serial Number (system)' 

en un terminal devuelve lo que es probable que un identificador único. Eso funciona en mi caja 10.5, no estoy seguro de cuál será la cadena correcta en otras versiones de OS X.

+1

En realidad, hay algunos Macs que se han enviado sin un número de serie, por lo que no deben hacer nada que se basa 100% en tener un número de serie único disponible. – smorgan

+1

'system_profiler' también tomará un tiempo. Si tiene un disco en la unidad de DVD, girará, por ejemplo. –

+2

He visto algunas de esas Mac sin Número de Serie (y tuve problemas con mi licencia de software), pero el UUID siempre está ahí. Deberías estar enfermo con UUID. – TCB13

0

Profiler del sistema (en Aplicaciones - Utilidades) contiene la mayor parte de este tipo de información. Tiene su número de serie y su dirección MAC (sin relación con Mac. Todas las computadoras tienen una dirección MAC que es prácticamente única para cada tarjeta de red).

1

Como algunas personas más arriba ha insinuado, puede usar un comando de Terminal para obtener una identificación de hardware.

Supongo que quiere hacer esto en el código sin embargo así que echaría un vistazo a la clase NSTask en Cocoa. Básicamente, le permite ejecutar comandos de terminal dentro de su aplicación.

Este código es un ejemplo de cómo usar NSTask en Cocoa. Configura el entorno para ejecutar el comando "killall". Lo pasa el argumento "Buscador".

Es el equivalente de ejecutar "killall Finder" en la línea de comandos, lo que matará obviamente al buscador.

NSTask *aTask = [[NSTask alloc] init]; 
NSMutableArray *args = [NSMutableArray array]; 

[aTask setLaunchPath: @"/usr/bin/killall"]; 
[args addObject:[@"/Applications/Finder" lastPathComponent]]; 
[aTask setArguments:args]; 
[aTask launch]; 

[aTask release]; 
+2

¿Qué hay con el elenco en 'NSString *', y por qué llamar 'lastPathComponent'? Esa línea es equivalente a '[args addObject: @" Finder "]'. – dreamlax

7

Esto sería más fácil de responder si nos diga qué idioma está utilizando. La información se puede obtener sin comandos de shell a través del marco de trabajo SystemConfiguration, y también a través de IOKit si quiere ensuciarse las manos.

- (NSString*) getMACAddress: (BOOL)stripColons { 
    NSMutableString   *macAddress   = nil; 
    NSArray     *allInterfaces  = (NSArray*)SCNetworkInterfaceCopyAll(); 
    NSEnumerator   *interfaceWalker = [allInterfaces objectEnumerator]; 
    SCNetworkInterfaceRef curInterface  = nil; 

    while (curInterface = (SCNetworkInterfaceRef)[interfaceWalker nextObject]) { 
     if ([(NSString*)SCNetworkInterfaceGetBSDName(curInterface) isEqualToString:@"en0"]) { 
      macAddress = [[(NSString*)SCNetworkInterfaceGetHardwareAddressString(curInterface) mutableCopy] autorelease]; 

      if (stripColons == YES) { 
       [macAddress replaceOccurrencesOfString: @":" withString: @"" options: NSLiteralSearch range: NSMakeRange(0, [macAddress length])]; 
      } 

      break; 
     } 
    } 

    return [[macAddress copy] autorelease]; 
} 
+0

Tienes razón, debería haber especificado el idioma. Actualicé la pregunta y las etiquetas. Estoy usando C++ y el marco de Qt para el desarrollo multiplataforma. – Gerald

+0

Luego SCNetworkInterfaceGetHardwareAddressString lo obtendrá por usted sin forzar otro proceso para ejecutar un script de shell. –

+0

asignación de macAddress en la línea 12 requiere una liberación automática – Colin

31

para C/C++:

void get_platform_uuid(char * buf, int bufSize) { 
    io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); 
    CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); 
    IOObjectRelease(ioRegistryRoot); 
    CFStringGetCString(uuidCf, buf, bufSize, kCFStringEncodingMacRoman); 
    CFRelease(uuidCf);  
} 
+1

Esto funcionó para mí con XCode 5.1 y Mac OS X 10.8.5 –

+1

Esta debería ser la respuesta aceptada – shawn

+0

¿puede esta función devolver el mismo UUID incluso la versión de mac actualizada en el futuro? . (supongamos que esta función funcionará en la futura versión de mac ahora) –

5
/* 
g++ mac_uuid.cpp -framework CoreFoundation -lIOKit 
*/ 


#include <iostream> 
#include <IOKit/IOKitLib.h> 

using namespace std; 

void get_platform_uuid(char * buf, int bufSize) 
{ 
    io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); 
    CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); 
    IOObjectRelease(ioRegistryRoot); 
    CFStringGetCString(uuidCf, buf, bufSize, kCFStringEncodingMacRoman); 
    CFRelease(uuidCf); 
} 

int main() 
{ 
    char buf[512] = ""; 
    get_platform_uuid(buf, sizeof(buf)); 
    cout << buf << endl; 
} 
+1

usando el código de @ yairchu dado anteriormente :) :) –

+1

'$ C++ mac_uuid.cpp -framework CoreFoundation -lIOKit' lleva a:' ld: biblioteca no encontrada para - lIOKit clang: error: el comando del enlazador falló con el código de salida 1 (use -v para ver la invocación) ' – malat

+0

' g ++ mac_uuid.cpp -o mac_uuid -framework CoreFoundation -framework IOKit' funciona para mí –

7

Por qué no pruebas gethostuuid()?Aquí está la documentación del Sistema de Mac OS X llamadas Manual:

NOMBRE:

gethostuuid -- return a unique identifier for the current machine 

SINOPSIS:

#include <unistd.h> 

int gethostuuid(uuid_t id, const struct timespec *wait); 

DESCRIPCIÓN:

The gethostuuid() function returns a 16-byte uuid_t specified by id, that uniquely identifies the current machine. Be aware that the hardware identifiers that gethostuuid() uses to generate the UUID can themselves be modified.

The wait argument is a pointer to a struct timespec that specifies the maximum time to wait for the result. Setting the tv_sec and tv_nsec fields to zero means to wait indefinitely until it completes.

VALORES DE RETORNO:

The gethostuuid() function returns zero on success or -1 on error.

ERRORES

The gethostuuid() functions fails if:

[EFAULT]   wait points to memory that is not a valid part of the 
        process address space. 

[EWOULDBLOCK]  The wait timeout expired before the UUID could be 
        obtained.