[iphone] Identifiant utilisateur unique iOS


2 Answers

J'ai utilisé CFUUIDCreate() pour créer un UUID:

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

Ensuite, définissez l'UUID ci-dessus sur mon NSString:

NSString *UUID = [nameofclasswhereGetUUIDclassmethodresides UUID];

J'ai ensuite stocké cet UUID à la Keychain en utilisant SSKeyChain

Pour définir l'UUID avec SSKeyChain:

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

Pour le récupérer:

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

Lorsque vous définissez l'UUID sur le trousseau, il persistera même si l'utilisateur désinstalle complètement l'application et l'installe à nouveau.

Pour vous assurer que TOUS les périphériques ont le même UUID dans le Keychain.

  1. Configurez votre application pour utiliser iCloud.
  2. Enregistrez également l'UUID qui se trouve dans le trousseau vers NSUserDefaults.
  3. Transmettez l'UUID dans NSUserDefaults au nuage avec le magasin de données de valeur-clé.
  4. Lors de la première exécution de l'application, vérifiez si les données de cloud sont disponibles et définissez l'UUID dans le trousseau sur le nouveau périphérique.

Vous avez maintenant un identifiant unique qui est persistant et partagé / synchronisé avec tous les appareils.

Question

Cette question a déjà une réponse ici:

J'écris une application pour iphone, qui communique avec mon serveur en utilisant REST. Le problème principal est, je dois identifier l'utilisateur d'une manière ou d'une autre. Il n'y a pas si longtemps, nous étions autorisés à utiliser UDID, mais maintenant ce n'est plus autorisé. Alors que dois-je utiliser à la place? J'ai besoin d'une sorte d'identifiant sur iphone, donc l'utilisateur va supprimer l'application, l'installer à nouveau, et il aura le même identifiant.




Dans iOS7, Apple a introduit une propriété en lecture seule appelée "identifierForVendor" dans la classe UIDevice. Si vous décidez de l'utiliser, vous devez prendre note de ce qui suit,

  • Cette valeur peut être nulle si elle est accessible avant que l'utilisateur déverrouille l'appareil
  • La valeur change lorsque l'utilisateur supprime toutes les applications de ce fournisseur de l'appareil et réinstalle ensuite un ou plusieurs d'entre eux.
  • La valeur peut également changer lors de l'installation de versions de test à l'aide de Xcode ou lors de l'installation d'une application sur un périphérique à l'aide d'une distribution ad-hoc.

Si vous avez besoin d'un identifiant à des fins publicitaires, utilisez la propriété advertisingIdentifier de ASIdentifierManager. Cependant, notez que le point un discuté ci-dessus est toujours vrai pour cela aussi.

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




Certaines personnes veulent en savoir plus sur les différentes options disponibles, et si vous le faites, jetez un oeil à la réponse de @ NSQuamber.java. Si vous voulez savoir comment utiliser le NSUUID et synchroniser avec iCloud, continuez à lire. Ce message a fini par être plus long que ce que je voulais au départ, mais j'espère que cela sera clair pour tous ceux qui prendront ces mesures!

Utiliser NSUUID

J'utilise la classe NSUUID pour créer l'UUID:

NSUUID *uuid = [NSUUID UUID];

Ensuite, pour créer la chaîne, il suffit d'appeler la méthode UUIDString :

NSString *uuidString = [uuid UUIDString];

ou faites-le en une ligne:

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

À mon humble avis, c'est beaucoup plus facile que d'essayer d'utiliser CFUUIDCreate et avoir une méthode que vous devez maintenir.

EDIT: J'utilise maintenant UICKeyChainStore

Pour définir l'UUID avec UICKeyChainStore:

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

Pour le récupérer:

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

J'ai ensuite stocké cet UUID à la Keychain en utilisant SSKeyChain

Pour définir l'UUID avec SSKeyChain:

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

Pour le récupérer:

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

Lorsque vous définissez l'UUID sur le trousseau, il persistera même si l'utilisateur désinstalle complètement l'application et l'installe à nouveau.

Synchronisation avec iCloud

Il est donc utile de s'assurer que tous les appareils de l'utilisateur utilisent le même UUID. Cela permet de s'assurer que les données sont synchronisées sur tous les appareils, plutôt que de croire que chaque appareil est un utilisateur unique.

Il y avait plusieurs questions dans les commentaires pour ma réponse sur la façon dont la synchronisation fonctionnerait, alors maintenant que tout fonctionne, je vais fournir plus de détails.

Configuration de l'utilisation de iCloud / NSUbiquitousKeyValueStore

  1. Cliquez sur votre projet en haut du Project Navigator dans Xcode.
  2. Sélectionnez Capabilities .
  3. Activez iCloud.

Il devrait maintenant ressembler à ceci:

Utiliser NSUbiquitousKeyValueStore

Utiliser iCloud est assez simple. Écrire:

// 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];

Lire:

// create the key to store the ID
NSString *userKey = @"com.sample.MyApp.user";

// read from iCloud
NSString *userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey];

Avant de pouvoir écrire les états de la documentation NSUbiquitousKeyValueStore que vous devez lire d'abord dans iCloud. Pour forcer la lecture, appelez la méthode suivante:

[[NSUbiquitousKeyValueStore defaultStore] synchronize];

Pour que votre application reçoive des notifications de modifications dans iCloud, ajoutez la notification suivante:

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

Création de l'UUID avec iCloud

En combinant NSUUID, SSKeychain et NSUbiquityKeyValueStore, voici ma méthode pour générer un ID utilisateur:

- (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];
}

Comment vous assurer que votre ID utilisateur est synchronisé

Comme l'écriture sur iCloud nécessite d'abord le téléchargement de toutes les données dans iCloud, je mets l'appel de synchronisation en haut de l' (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions méthode (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions . J'ai également ajouté l'enregistrement de notification là aussi. Cela me permet de détecter les changements d'iCloud et de les gérer de manière appropriée.

Voici un exemple:

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

Lorsque l'application est lancée ou lorsqu'elle revient au premier plan, je force une synchronisation avec iCloud et vérifie l'intégrité des 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 quel UUID est venu en premier lieu

Dans mon cas d'utilisation de mon ID utilisateur, j'ai supposé que la valeur dans iCloud est celle à conserver, car il s'agirait du premier UUID transmis à iCloud, quel que soit le périphérique qui a généré l'UUID en premier. La plupart d'entre vous prendront probablement le même chemin, puisque vous ne vous soucierez pas vraiment de l'UUID auquel il résout, tant qu'il se résout en un seul. Pour ceux d'entre vous qui se soucient de savoir qui est le premier, je vous suggère de stocker à la fois l'UUID et la génération d'horodatage ( [[NSDate date] timeIntervalSince1970] ) afin que vous puissiez vérifier lequel est le plus ancien:

// using dates
NSDate *uuid1Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp1];
NSDate *uuid2Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp2];
NSTimeInterval timeDifference = [uuid1 timeIntervalSinceDate:uuid2Timestamp];

// or just subtract
double timeDifference = timestamp1 - timestamp2;





Related