Certaines personnes veulent en savoir plus sur les différentes options disponibles. Si c'est votre cas, jetez un coup d'œil à la réponse de @NSQuamber.java. Si vous voulez savoir comment utiliser le NSUUID et synchroniser avec iCloud, continuez à lire. Ce billet a fini par être plus long que je ne le souhaitais à l'origine, mais j'espère qu'il est clair pour tous ceux qui suivent ces étapes !
Utilisation de 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 fonction UUIDString
méthode :
NSString *uuidString = [uuid UUIDString];
ou le faire en une seule ligne :
NSString *uuidString = [[NSUUID UUID] UUIDString];
IMHO, c'est beaucoup plus facile que d'essayer d'utiliser CFUUIDCreate et d'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 dans le trousseau de clés 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 dans le trousseau, il persistera même si l'utilisateur désinstalle complètement l'application, puis 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 laisser chaque appareil penser qu'il est un utilisateur unique.
Il y a eu plusieurs questions dans les commentaires pour ma réponse sur la façon dont la synchronisation fonctionnerait, donc maintenant que j'ai tout fait fonctionner, je vais fournir plus de détails.
Configuration de l'utilisation de iCloud/NSUbiquitousKeyValueStore
- Cliquez sur votre projet en haut de la page Navigateur de projet dans Xcode.
- Sélectionnez Capacités .
- Activez iCloud.
Il devrait maintenant ressembler à quelque chose comme ceci :
Utilisation de NSUbiquitousKeyValueStore
L'utilisation d'iCloud est assez simple. Pour é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];
A 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 le Documentation sur le NSUbiquitousKeyValueStore indique que vous devez d'abord lire à partir d'iCloud. Pour forcer une lecture, appelez la méthode suivante :
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
Pour que votre application reçoive des notifications de changements 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 s'assurer que votre ID utilisateur est synchronisé
Étant donné que l'écriture dans iCloud nécessite d'abord le téléchargement de toutes les données présentes dans iCloud, j'ai placé l'appel de synchronisation en haut de la page d'accueil de l'application. (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
méthode. J'y ai également ajouté l'enregistrement de la notification. Cela me permet de détecter tout changement provenant d'iCloud et de le traiter de manière appropriée.
En 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 l'UUID qui est venu en premier est important
Dans mon cas d'utilisation de mon UserID, j'ai supposé que la valeur dans iCloud est celle à conserver, puisqu'il s'agit du premier UUID envoyé à iCloud, quel que soit l'appareil qui a généré l'UUID en premier. La plupart d'entre vous suivront probablement le même chemin, puisque vous ne vous soucierez pas vraiment de l'UUID auquel il se résout, tant qu'il se résout à un seul. Pour ceux d'entre vous qui se soucient réellement de savoir lequel a été généré en premier, je vous suggère de stocker à la fois l'UUID et la génération de l'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;
0 votes
Il s'agit d'un sujet très actuel et brûlant. Avez-vous d'abord cherché ici des questions similaires ? Et sur Google ? Sujet très actuel...
0 votes
Certains disent que nous devrions utiliser mac-address pour cette situation, mais je ne suis pas sûr que les règles d'Apple le permettent.
0 votes
Apple ne le permettra pas car il est aussi spécifique par appareil que l'est l'udid.
0 votes
Pour votre information, une recherche sur Google sur ce sujet mène à ce fil de discussion.