Uniquely identifying an iOS user

The correct solution is to use the iCloud Key-Value Store, where you can store a unique user ID without requiring any kind of authentication or user information such as an email address.

The end result is a random UUID (nothing that actually IDENTIFIES the user), that is different for each user, but will persist across multiple devices registered to the same iCloud account.

We define a field in our iCloud KV Store, let’s call it userID. When the app is launched, we first check the userID. If it’s there, then we’re all set with our user’s unique ID. If not, then this is the first time we’re running for this user. We generate a random UUID and store it in the KV Store under userID. That’s all there is to it.

Our experience shows that this UUID is unique per iTunes account. If your end-users are using family sharing, those accounts will be assigned different UUIDs (which may or may not be desirable but there’s nothing you can do about it). Any number of devices launching under the same iTunes account will see the same UUID.

This approach is totally legit and should be approved by Apple with no issues.

Obviously you must enable iCloud Key-Value store on Xcode under Capabilities, just turn on the iCloud Switch.

Here’s a simple class that implements this concept in Objective-C:

@implementation EEUserID

+ (NSUUID *) getUUID
{
    NSUUID *uuid = nil;
    NSString *uuidString = [[NSUbiquitousKeyValueStore defaultStore] stringForKey: @"EEUserID"];
    if (uuidString == nil)
    {
        // This is our first launch for this iTunes account, so we generate random UUID and store it in iCloud:
        uuid = [NSUUID UUID];
        [[NSUbiquitousKeyValueStore defaultStore] setString: uuid.UUIDString forKey: @"EEUserID"];
        [[NSUbiquitousKeyValueStore defaultStore] synchronize];
    }
    else
    {
        uuid = [[NSUUID alloc] initWithUUIDString: uuidString];
    }
    
    return uuid;
}

+ (NSString *) getUUIDString
{
    NSUUID *uuid = [self getUUID];
    if (uuid != nil)
        return uuid.UUIDString;
    else
        return nil;
}

+ (void) load
{
    // get changes that might have happened while this
    // instance of your app wasn't running
    [[NSUbiquitousKeyValueStore defaultStore] synchronize];
}

@end

And for the header file:

#import <Foundation/Foundation.h>

@interface EEUserID : NSObject

+ (NSUUID *) getUUID;
+ (NSString *) getUUIDString;

@end

To use, all you have to do is invoke:

NSString *uniqueIDForiTunesAccount = [EEUserID getUUIDString];

Enjoy.

Leave a Comment