Identificador de usuario único de iOS

Estoy escribiendo una aplicación para iphone, que se comunica con mi servidor usando REST. El principal problema es que necesito identificar al usuario de alguna manera. No hace mucho tiempo, se nos permitía usar UDID, pero ahora ya no está permitido. Entonces, ¿qué debería usar en su lugar? Necesito algún tipo de identificador en el iPhone, por lo que el usuario eliminará la aplicación, la instalará de nuevo y obtendrá la misma identificación.

En primer lugar, el UDID solo está en desuso en iOS 5. Eso no significa que se haya ido (todavía).

En segundo lugar, debe preguntarse si realmente necesita tal cosa. ¿Qué pasa si el usuario obtiene un nuevo dispositivo e instala su aplicación en eso? Mismo usuario, pero el UDID ha cambiado. Mientras tanto, el usuario original podría haber vendido su dispositivo anterior, por lo que ahora un usuario completamente nuevo instala su aplicación y usted piensa que es una persona diferente basada en el UDID.

Si no necesita el UDID, use CFUUIDCreate() para crear una ID única y protegerla para los valores predeterminados del usuario en el primer inicio (use CFUUIDCreateString() para convertir primero el UUID a una cadena). Perdurará las copias de seguridad y restauraciones e incluso se unirá al usuario original cuando cambien a un nuevo dispositivo. Es en muchos sentidos una mejor opción que el UDID.

Si realmente necesita un identificador de dispositivo único (no suena como lo hace), busque la dirección MAC como se señala en la respuesta de Suhail.

CFUUIDCreate() para crear un UUID:

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

Luego configure el UUID anterior en mi NSString:

 NSString *UUID = [nameofclasswhereGetUUIDclassmethodresides UUID]; 

Luego guardé ese UUID en el llavero usando SSKeyChain

Para configurar el UUID con SSKeyChain:

 [SSKeychain setPassword:UUID forService:@"com.yourapp.yourcompany" account:@"user"]; 

Para recuperarlo:

 NSString *retrieveuuid = [SSKeychain passwordForService:@"com.yourapp.yourcompany" account:@"user"]; 

Cuando configura el UUID en el llavero, persistirá incluso si el usuario desinstala completamente la aplicación y luego la instala de nuevo.

Para asegurarse de que TODOS los dispositivos tengan el mismo UUID en el llavero.

  1. Configura tu aplicación para usar iCloud.
  2. Guarde también el UUID que está en Keychain en NSUserDefaults.
  3. Pase el UUID en NSUserDefaults a la nube con el almacén de datos Key-Value.
  4. En la primera ejecución de la aplicación, compruebe si los datos de la nube están disponibles y configure el UUID en el llavero en el nuevo dispositivo.

Ahora tiene un identificador único que es persistente y compartido / sincronizado con todos los dispositivos.

Estaba actualizando mi aplicación que funcionaba solo en base al identificador único compatible con iOS 4.3 y superior. Asi que,

1) No pude usar [UIDevice currentDevice].uniqueIdentifier; como ya no estaba disponible

2) No pude usar [UIDevice currentDevice].identifierForVendor.UUIDString porque estaba Disponible solo en iOS 6.0 y más tarde y no pude usar para versiones inferiores de iOS.

3) La dirección MAC no era una opción, ya que no estaba permitida en iOS-7

4) OpenUDID fue desaprobado hace algún tiempo y también tuvo problemas con iOS-6.

5) Los identificadores de publicidad tampoco estaban disponibles para iOS-5 y abajo

Finalmente esto fue lo que hice

a) Se agregó SFHFKeychainUtils al proyecto

b) Cadena clave CFUUID generada

  CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault); udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid)); 

c) Lo guardó en Key Chain Utils o de lo contrario generará un nuevo Unique Each Time

Código final

 + (NSString *)GetDeviceID { NSString *udidString; udidString = [self objectForKey:@"deviceID"]; if(!udidString) { CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault); udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid)); CFRelease(cfuuid); [self setObject:udidString forKey:@"deviceID"]; } return udidString; } +(void) setObject:(NSString*) object forKey:(NSString*) key { NSString *objectString = object; NSError *error = nil; [SFHFKeychainUtils storeUsername:key andPassword:objectString forServiceName:@"LIB" updateExisting:YES error:&error]; if(error) NSLog(@"%@", [error localizedDescription]); } +(NSString*) objectForKey:(NSString*) key { NSError *error = nil; NSString *object = [SFHFKeychainUtils getPasswordForUsername:key andServiceName:@"LIB" error:&error]; if(error) NSLog(@"%@", [error localizedDescription]); return object; } 

enter image description here

Para mas detalles

Algunas personas quieren saber más sobre las diferentes opciones disponibles, y si lo hace, eche un vistazo a la respuesta de @ NSQuamber.java. Si quieres saber cómo usar el NSUUID y sincronizar con iCloud, sigue leyendo. Esta publicación terminó siendo más prolija de lo que originalmente quería, ¡pero espero que deje en claro a cualquiera que siga estos pasos!

Usando NSUUID

Yo uso la clase NSUUID para crear el UUID:

 NSUUID *uuid = [NSUUID UUID]; 

Luego, para crear la cadena, solo necesita llamar al método UUIDString :

 NSString *uuidString = [uuid UUIDString]; 

o hazlo en una línea:

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

En mi humilde opinión, esto es mucho más fácil que tratar de usar CFUUIDCreate y tener un método que tiene que mantener.


EDITAR: ahora uso UICKeyChainStore

Para configurar el UUID con UICKeyChainStore:

 UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"]; keychain[@"com.sample.MyApp.user"] = userID; 

Para recuperarlo:

 UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"]; NSString *userID = keychain[@"com.sample.MyApp.user"]; 

Luego guardé ese UUID en el llavero usando SSKeyChain

Para configurar el UUID con SSKeyChain:

 [SSKeychain setPassword:userID forService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"]; 

Para recuperarlo:

 NSString *userID = [SSKeychain passwordForService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"]; 

Cuando configura el UUID en el llavero, persistirá incluso si el usuario desinstala completamente la aplicación y luego la instala de nuevo.

Sincronizando con iCloud

Por lo tanto, es útil asegurarse de que todos los dispositivos del usuario usen el mismo UUID. Esto es para garantizar que los datos se sincronicen en todos los dispositivos, en lugar de que cada dispositivo crea que es un usuario único.

Hubo varias preguntas en los comentarios sobre mi respuesta sobre cómo funcionaría la sincronización, por lo que ahora que lo tengo todo funcionando, proporcionaré más detalles.

Configuración del uso de iCloud / NSUbiquitousKeyValueStore

  1. Haga clic en su proyecto en la parte superior del Project Navigator en Xcode.
  2. Seleccionar capacidades .
  3. Encienda iCloud.

Ahora debería verse algo como esto: Captura de pantalla de iCloud habilitada

Usando NSUbiquitousKeyValueStore

Usar iCloud es bastante simple. Escribir:

 // create the UUID NSUUID *userUUID = [[NSUUID UUID]; // convert to string NSString *userID = [userUUID UUIDString]; // create the key to store the ID NSString *userKey = @"com.sample.MyApp.user"; // Save to iCloud [[NSUbiquitousKeyValueStore defaultStore] setString:userID forKey:userKey]; 

Leer:

 // create the key to store the ID NSString *userKey = @"com.sample.MyApp.user"; // read from iCloud NSString *userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey]; 

Antes de poder escribir, la documentación de NSUbiquitousKeyValueStore indica que primero debe leer desde iCloud. Para forzar una lectura, llame al siguiente método:

 [[NSUbiquitousKeyValueStore defaultStore] synchronize]; 

Para que su aplicación reciba notificaciones de cambios en iCloud, agregue la siguiente notificación:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(iCloudStoreDidChange:) name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification object:[NSUbiquitousKeyValueStore defaultStore]]; 

Creando el UUID con iCloud

Combinando NSUUID, SSKeychain y NSUbiquityKeyValueStore, este es mi método para generar una ID de usuario:

 - (NSUUID *)createUserID { NSString *userKey = @"com.sample.MyApp.user"; NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; NSString *userID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; if (userID) { return [[NSUUID UUID] initWithUUIDString:userID]; } // check iCloud userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey]; if (!userID) { // none in iCloud, create one NSUUID *newUUID = [NSUUID UUID]; userID = [newUUID UUIDString]; // save to iCloud [[NSUbiquitousKeyValueStore defaultStore] setString:userID forKey:userKey]; } // store the user ID locally [SSKeychain setPassword:userID forService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; return [[NSUUID UUID] initWithUUIDString:userID]; } 

Cómo asegurarse de que su identificación de usuario esté sincronizada

Debido a que escribir en iCloud requiere una descarga de datos en iCloud primero, puse la llamada de sincronización en la parte superior de la (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions método (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions . También agregué el registro de notificación allí también. Eso me permite detectar cualquier cambio desde iCloud y manejarlos de manera apropiada.

Aquí hay una muestra:

 NSString *const USER_KEY = @"com.sample.MyApp.user"; NSString *const KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; - (void)iCloudStoreDidChange:(NSNotification *)notification { NSDictionary *userInfo = notification.userInfo; NSNumber *changeReason = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey]; NSArray *keysChanged = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey]; if (changeReason) { switch ([changeReason intValue]) { default: case NSUbiquitousKeyValueStoreServerChange: case NSUbiquitousKeyValueStoreInitialSyncChange: // check changed keys for (NSString *keyChanged in keysChanged) { NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:keyChanged]; if (![keyChanged isEqualToString:USER_KEY]) { NSLog(@"Unknown key changed [%@:%@]", keyChanged, iCloudID); continue; } // get the local key NSString *localID = [SSKeychain passwordForService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER]; if (!iCloudID) { // no value from iCloud continue; } // local ID not created yet if (!localID) { // save the iCloud value locally [SSKeychain setPassword:iCloudID forService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER]; continue; // continue because there is no user information on the server, so no migration } if ([iCloudID isEqualToString:localID]) { // IDs match, so continue continue; } [self handleMigration:keyChanged from:localID to:iCloudID]; } break; case NSUbiquitousKeyValueStoreAccountChange: // need to delete all data and download new data from server break; } } } 

Cuando se inicia la aplicación o cuando vuelve al primer plano, forzo una sincronización con iCloud y verifico la integridad de los UUID.

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [self configureSecKeyWrapper]; // synchronize data from iCloud first. If the User ID already exists, then we can initialize with it [[NSUbiquitousKeyValueStore defaultStore] synchronize]; [self checkUseriCloudSync]; } - (void)applicationWillEnterForeground:(UIApplication *)application { // synchronize changes from iCloud [[NSUbiquitousKeyValueStore defaultStore] synchronize]; [self checkUseriCloudSync]; } - (BOOL)checkUseriCloudSync { NSString *userKey = @"com.sample.MyApp.user"; NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp"; NSString *localID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER]; NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey]; if (!iCloudID) { // iCloud does not have the key saved, so we write the key to iCloud [[NSUbiquitousKeyValueStore defaultStore] setString:localID forKey:userKey]; return YES; } if (!localID || [iCloudID isEqualToString:localID]) { return YES; } // both IDs exist, so we keep the one from iCloud since the functionality requires synchronization // before setting, so that means that it was the earliest one [self handleMigration:userKey from:localID to:iCloudID]; return NO; } 

Si el UUID llegó primero importa

En mi caso de uso de mi ID de usuario, asumí que el valor en iCloud es el que debe conservarse, ya que sería el primer UUID enviado a iCloud, independientemente de qué dispositivo generara primero el UUID. La mayoría de ustedes probablemente tomaría la misma ruta, ya que realmente no le importará a qué UUID resuelve, siempre que se resuelva en uno solo. Para aquellos de ustedes que realmente les importa cuál fue el primero, sugiero que almacenen tanto el UUID como la generación de la marca de tiempo ( [[NSDate date] timeIntervalSince1970] ) para que pueda verificar cuál es más antiguo:

 // using dates NSDate *uuid1Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp1]; NSDate *uuid2Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp2]; NSTimeInterval timeDifference = [uuid1 timeIntervalSinceDate:uuid2Timestamp]; // or just subtract double timeDifference = timestamp1 - timestamp2; 

Hay una buena alternativa en Github que genera un identificador único basado en una combinación de dirección MAC y el identificador de paquete que funciona bastante bien: UIDevice-with-UniqueIdentifier-for-iOS-5

En iOS7, Apple ha introducido una propiedad de solo lectura llamada “identifierForVendor” en la clase UIDevice. Si decide usarlo, debe tomar nota de lo siguiente,

  • Este valor podría ser nulo si se accede antes de que el usuario desbloquee el dispositivo
  • El valor cambia cuando el usuario elimina todas las aplicaciones de ese proveedor del dispositivo y luego reinstala una o más de ellas.
  • El valor también puede cambiar al instalar comstackciones de prueba con Xcode o al instalar una aplicación en un dispositivo mediante distribución ad-hoc.

Si necesita un identificador para fines publicitarios, use la propiedad advertisingIdentifier de ASIdentifierManager. Sin embargo, tenga en cuenta que el punto uno discutido anteriormente sigue siendo cierto para esto también.

Fuente: https://developer.apple.com/library/ios/documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html#//apple_ref/occ/instp/UIDevice/identifierForVendor

Este es un tema candente de hecho. Tengo una aplicación que debo migrar porque usa el UDID para nombrar un archivo XML que se almacenará en un servidor. Luego, el dispositivo con la aplicación se conectará al servidor y descargará su udid.xml específico y lo analizará para que funcione.

He estado pensando que si el usuario se mueve a un nuevo dispositivo, la aplicación se romperá. Entonces realmente debería usar algo más. El caso es que no uso una base de datos para los datos. Los datos simplemente se almacenan en un formato xml, un archivo xml por dispositivo almacenado en la nube.

Creo que lo mejor sería que el usuario complete los datos en la web, haga que php cree un token sobre la marcha que no se almacene en una base de datos, sino que se lo envíe al usuario. El usuario puede ingresar el token en el dispositivo de destino y recuperar el xml en cuestión.

Esa sería mi solución al problema. Sin embargo, no estoy seguro de cómo implementar toda la creación de tokens únicos.