UIDevice uniqueIdentifier en desuso: ¿qué hacer ahora?

501

Acaba de salir a la luz que la propiedad UIDevice uniqueIdentifier está en desuso en iOS 5 y no está disponible en iOS 7 y versiones posteriores. Ningún método o propiedad alternativa parece estar disponible o disponible.

Muchas de nuestras aplicaciones existentes dependen mucho de esta propiedad para identificar de forma exclusiva un dispositivo en particular. ¿Cómo podríamos manejar este problema en el futuro?

La sugerencia de la documentación en 2011-2012 fue:

Consideraciones Especiales

No use la propiedad uniqueIdentifier. Para crear un identificador único específico para su aplicación, puede llamar a la CFUUIDCreatefunción para crear un UUIDy escribirlo en la base de datos predeterminada utilizando la NSUserDefaultsclase.

Sin embargo, este valor no será el mismo si un usuario desinstala y vuelve a instalar la aplicación.

Oliver Pearmain
fuente
1
Para las aplicaciones que todavía usan uniqueIdentifier, iOS7 ahora devuelve FFFFFFFF + identifierForVendor que está rompiendo muchas aplicaciones de suscripción no renovables mal escritas.
Rhythmic Fistman
Si por suerte su aplicación usa Notificaciones Push, puede usar el token enviado desde el servicio push de Apple, también es único por dispositivo
Calin Chitu
@CalinChitu Si el usuario no acepta notificaciones push, ¿aún obtiene un pushID para ese usuario?
Chase Roberts

Respuestas:

272

Un UUID creado por CFUUIDCreate es único si un usuario desinstala y vuelve a instalar la aplicación: obtendrá uno nuevo cada vez.

Pero es posible que desee que no sea único, es decir, que permanezca igual cuando el usuario desinstale y vuelva a instalar la aplicación. Esto requiere un poco de esfuerzo, ya que el identificador por dispositivo más confiable parece ser la dirección MAC. Puede consultar el MAC y usarlo como UUID.

Editar: Uno siempre debe consultar el MAC de la misma interfaz, por supuesto. Supongo que la mejor apuesta es con en0. El MAC siempre está presente, incluso si la interfaz no tiene IP / está inactivo.

Edición 2: Como lo señalaron otros, la solución preferida desde iOS 6 es - [UIDevice identifierForVendor] . En la mayoría de los casos, debería poder usarlo como un reemplazo directo al anterior -[UIDevice uniqueIdentifier](pero Apple parece querer crear un UUID que se crea cuando se inicia por primera vez).

Edición 3: para que este punto principal no se pierda en el ruido del comentario: no use el MAC como UUID, cree un hash usando el MAC . Ese hash siempre creará el mismo resultado cada vez, incluso a través de reinstalaciones y aplicaciones (si el hash se realiza de la misma manera). De todos modos, hoy en día (2013) esto ya no es necesario, excepto si necesita un identificador de dispositivo "estable" en iOS <6.0.

Edición 4: en iOS 7, Apple ahora siempre devuelve un valor fijo cuando consulta el MAC para frustrar específicamente el MAC como base para un esquema de ID . Entonces, ahora realmente debería usar - [UIDevice identifierForVendor] o crear un UUID por instalación.

Polvo oscuro
fuente
8
¿La dirección mac no cambia dependiendo de si el usuario está conectado a través de Wifi o no?
Oliver Pearmain
1
@DarkDust: pero como la interfaz activa cambia cuando cambia de módem wifi a celular, la dirección MAC de la interfaz activa también debería cambiar; a menos que siempre elija una interfaz particular para obtener el MAC
user102008
3
@Roger Nolan: Por favor, no edite las respuestas de otras personas y agregue cosas que parezcan provenir del autor original. Gracias.
DarkDust
2
@RogerNolan Mientras la publicación no sea una respuesta de la comunidad, las ediciones son para corregir errores y esas cosas, no para agregar cosas nuevas. Hay una razón por la que te has ganado el privilegio. Imagina que edito tu respuesta y escribo algunas BS, la gente pensaría que lo hubieras escrito. Dudo que te guste eso :-) Pero no te notifican que ocurrió una edición, solo lo descubrí por accidente.
DarkDust
3
Apple ahora rechaza las aplicaciones que usan MAC hash.
Idan
91

Ya puedes usar tu alternativa para Apple UDID. Kind Guy Gekitz escribió una categoría en la UIDeviceque generará algún tipo de UDIDdirección de dispositivo basada en la dirección MAC y el identificador de paquete.

Puedes encontrar el código en github

Serhii Mamontov
fuente
3
Esta implementación es única (dirección MAC) para un dispositivo a través de reinstalaciones, como el ID único de Apple, pero también respeta la privacidad, al ser también única para una aplicación (también use bundleId) ... A mi parecer, Apple debe incluirla en sus API. .. en lugar de despreciar sin ninguna alternativa.
Vincent Guerci
8
Aunque utiliza la licencia bsd de estilo antiguo con la cláusula publicitaria, qué asco.
jbtule
8
Para cualquier otra persona que ahora encuentre esta publicación, la licencia ha cambiado desde el comentario anterior de jbtule.
James
1
Como se discutió en este comentario de confirmación, la biblioteca tal como está plantea un grave problema de fuga de privacidad y no debe usarse:
Será
15
A partir de iOS 7, el sistema siempre devuelve el valor 02:00:00:00:00:00cuando solicita la dirección MAC en cualquier dispositivo. Verifique aquí: developer.apple.com/library/prerelease/ios/releasenotes/General/…
Hejazi
61

Basado en el enlace propuesto por @moonlight, hice varias pruebas y parece ser la mejor solución. Como dice @DarkDust, el método va a verificar en0cuál está siempre disponible.
Hay 2 opciones:
uniqueDeviceIdentifier(MD5 de MAC + CFBundleIdentifier)
y uniqueGlobalDeviceIdentifier(MD5 de MAC), estas siempre devuelven los mismos valores.
Debajo de las pruebas que he hecho (con el dispositivo real):

#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 - (Modo avión) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (Modo avión) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) después de quitar y reinstalar la aplicación XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) después de quitar e instalar la aplicación

Espero que sea útil.

EDITAR:
como señalaron otros, esta solución en iOS 7 ya no es útil ya uniqueIdentifierque ya no está disponible y la consulta de la dirección MAC ahora siempre devuelve 02: 00: 00: 00: 00: 00

Estera
fuente
13
esto no funcionará en iOS7, Apple elimina el uso de la dirección MAC.
Sarim Sidd
@SarimSidd Por ahora, la información sobre iOS 7 está bajo NDA, no podemos discutir aquí.
Mat
57

mira esto,

podemos usar Keychain en lugar de NSUserDefaultsclass, para almacenar UUIDcreado por CFUUIDCreate.

de esta manera podríamos evitar la UUIDrecreación con la reinstalación, y obtener siempre lo mismo UUIDpara la misma aplicación, incluso la desinstalación y reinstalación del usuario nuevamente.

UUID se recreará justo cuando el usuario reinicie el dispositivo.

Probé este método con SFHFKeychainUtils y funciona de maravilla .

por el momento
fuente
33
Este método es un reemplazo sólido para UDID. También tiene el beneficio adicional de recrear el identificador según el formato del dispositivo (por ejemplo, si el dispositivo cambia de propietario). Sin embargo, es importante tener en cuenta que el llavero se puede restaurar a otros dispositivos si el usuario cifra su copia de seguridad. Esto puede dar como resultado una situación en la que varios dispositivos comparten el mismo UUID. Para evitar esto, configure la accesibilidad de su artículo de llavero a kSecAttrAccessibleAlwaysThisDeviceOnly. Esto asegurará que su UUID no migre a ningún otro dispositivo. Para acceder a su UUID desde otras aplicaciones, utilice la kSecAttrAccessGroupclave.
Jeevan Takhar
¿Dónde exactamente (qué clave) se supone que debes usar para almacenar el UUID en el llavero?
lostintranslation
Opps! el enlace está roto
COVID19
48

Cree su propio UUID y luego guárdelo en el llavero. Por lo tanto, persiste incluso cuando su aplicación se desinstala. En muchos casos, también persiste incluso si el usuario migra entre dispositivos (por ejemplo, copia de seguridad completa y restauración a otro dispositivo).

Efectivamente, se convierte en un identificador de usuario único en lo que a usted respecta. (incluso mejor que el identificador del dispositivo ).

Ejemplo:

Estoy definiendo un método personalizado para crear un UUIDcomo:

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

Luego puede almacenarlo en KEYCHAINel primer lanzamiento de su aplicación. De modo que después del primer lanzamiento, simplemente podemos usarlo desde el llavero, sin necesidad de regenerarlo. La razón principal para usar Keychain para almacenar es: cuando configuras el UUIDKeychain, persistirá incluso si el usuario desinstala completamente la aplicación y luego la instala nuevamente. . Entonces, esta es la forma permanente de almacenarlo, lo que significa que la clave será única en todo momento.

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

En el lanzamiento de la aplicación, incluya el siguiente código:

 // 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
}

Descargue el archivo SSKeychain.m y .h de sskeychain y arrastre el archivo SSKeychain.m y .h a su proyecto y agregue "Security.framework" a su proyecto. Para usar UUID luego simplemente use:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
Samir Jwarchan
fuente
Porque un identificadorForVendor está funcionando no es perfectamente. En algunos casos puede devolver un valor nulo o 0x0. Parece que este método funciona perfectamente
CReaTuS
3
alguien validado esto está funcionando en iOS7 después de desinstalar / reinstalar el ciclo + envío verificado de la aplicación de Apple?
mindbomb
Empecé a usar esta solución. Varias pruebas en 2 dispositivos (reconstrucción, reinstalación, apagado del dispositivo) me mostraron que la identificación es la misma. iOS 10.3.
deko
16

Quizás puedas usar:

[UIDevice currentDevice].identifierForVendor.UUIDString

La documentación de Apple describe identifierForVender de la siguiente manera:

El valor de esta propiedad es el mismo para las aplicaciones que provienen del mismo proveedor que se ejecuta en el mismo dispositivo. Se devuelve un valor diferente para aplicaciones en el mismo dispositivo que provienen de diferentes proveedores y para aplicaciones en diferentes dispositivos, independientemente del proveedor.

diadyne
fuente
Curioso por qué nadie mencionó esto hasta hace poco ... Y ahora veo que es nuevo con iOS 6.
James Boutcher
1
Si el usuario actualiza ios y / o instala nuevos ios, ¿el valor de identifierForVendor cambiará o permanecerá igual?
Sunil Zalavadiya
1
Después de eliminar todas las aplicaciones del mismo proveedor, este valor cambiará.
Mitesh Khatri
14

Es posible que desee considerar el uso de OpenUDIDun reemplazo directo para el obsoleto UDID.

Básicamente, para que coincida con UDID, se requieren las siguientes características:

  1. único o suficientemente único (una colisión de baja probabilidad es probablemente muy aceptable)
  2. persistencia entre reinicios, restaura, desinstala
  3. disponible en aplicaciones de diferentes proveedores (útil para adquirir usuarios a través de redes CPI) -

OpenUDID cumple con lo anterior e incluso tiene un mecanismo de exclusión incorporado para su posterior consideración.

Verifique http://OpenUDID.org , apunta al GitHub correspondiente. ¡Espero que esto ayude!

Como nota al margen, rehuiría cualquier alternativa de dirección MAC. Si bien la dirección MAC aparece como una solución tentadora y universal, asegúrese de que esta fruta baja esté envenenada. La dirección MAC es muy sensible, y Apple puede desaprobar el acceso a esta antes de que incluso puedas decir "ENVIAR ESTA APLICACIÓN" ... la dirección de red MAC se usa para autenticar ciertos dispositivos en redes privadas (WLAN) u otras redes privadas virtuales. redes (VPN). ¡Es aún más sensible que el antiguo UDID!

ylechelle
fuente
Tengo mucha curiosidad por cómo funciona esto? El código está escrito en Objective-C, pero no hay otra buena solución que se ajuste a los requisitos anteriores, entonces, ¿qué hace que este marco sea diferente? La solución que está utilizando este marco también debería ser posible publicar como una respuesta sugerida aquí ...
jake_hetfield
Estoy de acuerdo: la dirección MAC también se puede configurar manualmente ("clonada"), aunque no es probable en su mayor parte. Debo protestar contra la D en UDID. Esta no es una ID de dispositivo, es un UUID (Identificador único universal). Apple identifica la identificación del dispositivo de fábrica en cada dispositivo en ROM.
Jay Imerman
La mejor solución para iOS7 también es lo que realmente se necesita para identificar un dispositivo de manera única
vishal dharankar
1
OpenUDID está en desuso y no se recomienda su uso
mkll
11

Estoy seguro de que Apple ha molestado a muchas personas con este cambio. Desarrollo una aplicación de contabilidad para iOS y tengo un servicio en línea para sincronizar los cambios realizados en diferentes dispositivos. El servicio mantiene una base de datos de todos los dispositivos y los cambios que deben propagarse a ellos. Por lo tanto, es importante saber qué dispositivos son cuáles. Estoy haciendo un seguimiento de los dispositivos que usan el UIDevice uniqueIdentifier y, por lo que vale, aquí están mis pensamientos.

  • ¿Generar un UUID y almacenar en los valores predeterminados del usuario? No es bueno porque esto no persiste cuando el usuario elimina la aplicación. Si se instalan nuevamente más tarde, el servicio en línea no debería crear un nuevo registro de dispositivo, eso desperdiciaría recursos en el servidor y daría una lista de dispositivos que contienen el mismo dos o más veces. Los usuarios verán más de un "iPhone de Bob" en la lista si reinstalan la aplicación.

  • ¿Generar un UUID y almacenarlo en el llavero? Este era mi plan, ya que persiste incluso cuando la aplicación se desinstala. Pero cuando se restaura una copia de seguridad de iTunes en un nuevo dispositivo iOS, el llavero se transfiere si la copia de seguridad está encriptada. Esto podría llevar a dos dispositivos que contengan la misma identificación de dispositivo si los dispositivos antiguos y nuevos están en servicio. Estos deben aparecer como dos dispositivos en el servicio en línea, incluso si el nombre del dispositivo es el mismo.

  • ¿Generar un hash la dirección MAC y la identificación del paquete? Esta parece la mejor solución para lo que necesito. Al analizar el ID del paquete, el ID del dispositivo generado no permitirá que el dispositivo pueda rastrearse en todas las aplicaciones y obtengo una ID única para la combinación de la aplicación y el dispositivo.

Es interesante observar que la propia documentación de Apple se refiere a la validación de los recibos de la Mac App Store al calcular un hash de la dirección MAC del sistema más la identificación y la versión del paquete. Por lo tanto, esto parece permitido por la política, ya sea que pase por la revisión de la aplicación, aún no lo sé.

Mathew Waters
fuente
10
Para evitar la situación descrita en su segundo punto, configure la accesibilidad de su artículo de llavero en kSecAttrAccessibleAlwaysThisDeviceOnly. Esto asegurará que su UUID no se restaure a otros dispositivos, incluso si la copia de seguridad está encriptada.
Jeevan Takhar
Este es el comportamiento que he visto muchas veces. Por ejemplo, registro mi iPhone para Google Sync. Luego obtuve un nuevo iPhone, lo registré y listo, ahora tengo 2 iPhones en mi configuración de sincronización.
Jay Imerman
11

Parece que para iOS 6, Apple recomienda que uses la clase NSUUID .

Del mensaje ahora en los documentos UIDevice para la uniqueIdentifierpropiedad:

En desuso en iOS 5.0. Use la propiedad identifierForVendor de esta clase o la propiedad advertisingIdentifier de la clase ASIdentifierManager en su lugar, según corresponda, o use el método UUID de la clase NSUUID para crear un UUID y escribirlo en la base de datos predeterminada del usuario.

Nate
fuente
10

Puede ayudar: use el siguiente código, siempre será Único, excepto que borre (Formatee) su dispositivo.

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];
Ashvin Ajadiya
fuente
1
Usé este código. Pero cuando he eliminado aplicación y otra vez instalado llegué nueva Id
Durgaprasad
1
Esta es una solución simple si no necesita un método robusto. Lo estoy usando en mi aplicación ahora.
Reuben L.
@ Durgaprasad: cambiará siempre porque depende del proveedor. Por ejemplo: 1. Si ha instalado una aplicación con bundleidenedifier: com.abcd.com =>, cambiará. 2. Si ha instalado dos aplicaciones con bundleidenedifier: com.abcd.com => Entonces no cambiará (Mantenga una aplicación durante)
Ashvin Ajadiya
7

También sugeriría cambiar uniqueIdentifiera esta biblioteca de código abierto (2 categorías simples realmente) que utilizan la dirección MAC del dispositivo junto con el identificador de paquete de aplicaciones para generar una identificación única en sus aplicaciones que se puede usar como reemplazo de UDID.

Tenga en cuenta que, a diferencia del UDID, este número será diferente para cada aplicación.

Usted sólo tendrá que importar los incluidos NSStringy UIDevicecategorías y llamada [[UIDevice currentDevice] uniqueDeviceIdentifier]así:

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

Puedes encontrarlo en Github aquí:

UIDevice con UniqueIdentifier para iOS 5


Aquí están las categorías (solo los archivos .m - verifique el proyecto github para los encabezados):

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
chown
fuente
3
A partir de iOS 7, Apple devolverá un valor constante para la dirección MAC. Tiene mucho sentido La dirección MAC es sensible.
Roberto
4

La dirección MAC puede ser falsificada, lo que hace que este enfoque sea inútil para vincular contenido a usuarios específicos o implementar características de seguridad como listas negras.

Después de algunas investigaciones adicionales, me parece que nos quedamos sin una alternativa adecuada a partir de ahora. Espero seriamente que Apple reconsidere su decisión.

Tal vez sería una buena idea enviar un correo electrónico a Apple sobre este tema y / o presentar una solicitud de error / función sobre esto, ya que tal vez ni siquiera son conscientes de las consecuencias completas para los desarrolladores.

Toastor
fuente
13
Un punto válido, sin embargo, creo que el UUID también puede ser falsificado / rociado en un teléfono con jailbreak, por lo que técnicamente el [UIDevice uniqueIdentifier] existente es igual de defectuoso.
Oliver Pearmain
3
Siempre puede crear un identificador en el servidor y guardarlo en el dispositivo. Así es como la mayoría de las aplicaciones lo hacen. No entiendo por qué los programadores de iOS necesitan algo especial.
Sulthan
1
@Sulthan no funciona en iOS porque si desinstala una aplicación, todos sus datos desaparecen, por lo que no hay forma de garantizar un identificador de dispositivo único de esa manera.
lkraider
44
No si lo guarda en el llavero. De todos modos, nunca he visto una aplicación donde esto sea un problema. Si la aplicación y los datos se han eliminado, no necesita el mismo identificador de dispositivo. Si desea identificar al usuario, solicítele un correo electrónico.
Sulthan
El acceso a la dirección MAC también ha sido prohibido por Apple en la nueva versión de iOS;
Respuesta del
4

UIDevice identifierForVendor introducido en iOS 6 funcionaría para sus propósitos.

identifierForVendores una cadena alfanumérica que identifica de forma exclusiva un dispositivo para el proveedor de la aplicación. (solo lectura)

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

El valor de esta propiedad es el mismo para las aplicaciones que provienen del mismo proveedor que se ejecuta en el mismo dispositivo. Se devuelve un valor diferente para aplicaciones en el mismo dispositivo que provienen de diferentes proveedores, y para aplicaciones en diferentes dispositivos con respecto al proveedor.

Disponible en iOS 6.0 y posterior y declarado en UIDevice.h

Para iOS 5, consulte este enlace UIDevice-with-UniqueIdentifier-for-iOS-5

Mahendra Liya
fuente
4

Usando el SSKeychain y el código mencionado anteriormente. Aquí hay código para copiar / pegar (agregar el módulo SSKeychain):

+(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;

}

Komposr
fuente
3

El siguiente código ayuda a obtener UDID:

        udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
        NSLog(@"UDID : %@", udid);
santificar
fuente
3

Este es el código que estoy usando para obtener ID tanto para iOS 5 como para 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];
}
Grzegorz Krukowski
fuente
¿Qué haces con la advertencia del compilador PerformSelector may cause a leak because its selector is unknown?
Basil Bourque
Ya no puede usar advertisingIdentifier para este propósito ya que Apple lo rechazará. Más información: techcrunch.com/2014/02/03/…
codeplasma
2

iOS 11 ha introducido el marco DeviceCheck. Tiene una solución a prueba de fallas para identificar de forma única el dispositivo.

Santosh Botre
fuente
1

Una forma de trabajar para obtener UDID:

  1. Inicie un servidor web dentro de la aplicación con dos páginas: una debe devolver el perfil MobileConfiguration especialmente diseñado y otra debe recopilar UDID. Más información aquí , aquí y aquí .
  2. Abre la primera página en Mobile Safari desde dentro de la aplicación y lo redirige a Settings.app solicitando instalar el perfil de configuración. Después de instalar el perfil, UDID se envía a la segunda página web y puede acceder a él desde la aplicación. (Settings.app tiene todos los derechos necesarios y diferentes reglas de sandbox).

Un ejemplo usando 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)
    }
}

Aquí están los contenidos de 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>

La instalación del perfil fallará (no me molesté en implementar una respuesta esperada, consulte la documentación ), pero la aplicación obtendrá un UDID correcto. Y también debe firmar la configuración móvil .

bzz
fuente
1

Para Swift 3.0, utilice el siguiente código.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)
Ganesh
fuente
1
iOS 11 ha introducido el marco DeviceCheck. Tiene una solución a prueba de fallas para identificar de forma única el dispositivo.
Santosh Botre
1

Puedes usar

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

Que es único para el dispositivo en todas las aplicaciones.

Dhaval
fuente
0

Si alguien se topa con esta pregunta, cuando busca una alternativa. He seguido este enfoque en IDManagerclase. Esta es una colección de diferentes soluciones. KeyChainUtil es un contenedor para leer del llavero. También puede usar el hashed MAC addresscomo una especie de identificación única.

/*  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;
}
karim
fuente
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;
}
mahesh chowdary
fuente
0

Podemos usar identifierForVendor para 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;
}

--Nota IMPORTANTE ---

UDID e identifierForVendor son diferentes: ---

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.
HDdeveloper
fuente
Estás seguro ? ¿podemos usar identifierForVendor para ios7?
Avis
0

Apple ha ocultado el UDID de todas las API públicas, comenzando con iOS 7. Cualquier UDID que comience con FFFF es una identificación falsa. Las aplicaciones "Enviar UDID" que funcionaban anteriormente ya no se pueden usar para recopilar UDID para dispositivos de prueba. (¡suspiro!)

El UDID se muestra cuando un dispositivo está conectado a XCode (en el organizador) y cuando el dispositivo está conectado a iTunes (aunque debe hacer clic en 'Número de serie' para que se muestre el identificador).

Si necesita obtener el UDID de un dispositivo para agregarlo a un perfil de aprovisionamiento, y no puede hacerlo usted mismo en XCode, deberá guiarlos a través de los pasos para copiarlo / pegarlo desde iTunes.

¿Existe alguna forma desde (lanzamiento de iOS 7) para obtener el UDID sin usar iTunes en una PC / Mac?

Saludar
fuente
0

También tuve un problema, y ​​la solución es 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;
Ahmet Kazim Günay
fuente
0

Una alternativa no perfecta pero una de las mejores y más cercanas a UDID (en Swift con iOS 8.1 y Xcode 6.1):

Generando un UUID aleatorio

let strUUID: String = NSUUID().UUIDString

Y use la biblioteca KeychainWrapper :

Agregue un valor de cadena al llavero:

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

Recupere un valor de cadena del llavero:

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

Eliminar un valor de cadena del llavero:

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

Esta solución utiliza el llavero, por lo que el registro almacenado en el llavero se mantendrá, incluso después de que la aplicación se desinstale y reinstale. La única forma de eliminar este registro es restablecer todos los contenidos y configuraciones del dispositivo. Es por eso que mencioné que esta solución de sustitución no es perfecta, pero sigue siendo una de las mejores soluciones de reemplazo para UDID en iOS 8.1 usando Swift.

Rey Mago
fuente
0

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

Ankit Garg
fuente