iOS唯一用户标识符

Dra*_*una 90 iphone objective-c ios

我正在写一个iphone应用程序,它使用REST与我的服务器通信.主要问题是,我需要以某种方式识别用户.不久前,我们被允许使用UDID,但现在不再允许了.那我应该用什么呢?我需要在iphone上使用某种标识符,因此用户将删除应用程序,再次安装它,并且他将获得相同的ID.

小智 186

我曾经CFUUIDCreate()创建过一个UUID:

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

然后将上面的UUID设置为我的NSString:

NSString *UUID = [nameofclasswhereGetUUIDclassmethodresides UUID];
Run Code Online (Sandbox Code Playgroud)

然后我使用SSKeyChain将UUID存储到Keychain

使用SSKeyChain设置UUID:

[SSKeychain setPassword:UUID forService:@"com.yourapp.yourcompany" account:@"user"];
Run Code Online (Sandbox Code Playgroud)

要检索它:

NSString *retrieveuuid = [SSKeychain passwordForService:@"com.yourapp.yourcompany" account:@"user"];
Run Code Online (Sandbox Code Playgroud)

当您将UUID设置为Keychain时,即使用户完全卸载App然后再次安装它,它仍会保留.

确保所有设备在Keychain中具有相同的UUID.

  1. 设置您的应用程序以使用iCloud.
  2. 将Keychain中的UUID也保存到NSUserDefaults.
  3. 将NSUserDefaults中的UUID传递给具有键值数据存储的云.
  4. 在应用程序首次运行时,检查云数据是否可用,并在新设备的Keychain中设置UUID.

您现在拥有一个持久性的唯一标识符,并与所有设备共享/同步.

  • 嗨,提交给appstore时有什么问题吗?用户也可以清除钥匙串吗? (4认同)

Ole*_*ann 69

首先,UDID 在iOS 5中被弃用.这并不意味着它已经消失了.

其次,你应该问自己是否真的需要这样的东西.如果用户获得新设备并在其上安装您的应用程序该怎么办?相同的用户,但UDID已更改.同时,原始用户可能已经售出了他的旧设备,所以现在一个全新的用户安装你的应用程序,你认为它是基于UDID的不同的人.

如果你不需要的UDID,使用CFUUIDCreate()创造一个独特的ID,安全是用户默认第一次启动(使用CFUUIDCreateString()的UUID先转换为字符串).它将在备份和恢复后继续存在,甚至在原始用户切换到新设备时也会出现.它在很多方面都是UDID的更好选择.

如果你真的需要一个唯一的设备标识符(听起来不像你那样),请按照Suhail的回答中的指示寻找MAC地址.

  • @Drabuna:不,`CFUUIDCreate()`每次调用都会创建一个新的UUID。 (2认同)

Qua*_*Ali 39

我正在更新我的应用程序,该应用程序仅基于支持iOS 4.3及更高版本的 Unique Identifier工作.所以,

1)我无法使用,[UIDevice currentDevice].uniqueIdentifier;因为它已不再可用

2)我无法使用,[UIDevice currentDevice].identifierForVendor.UUIDString因为它仅在iOS 6.0及更高版本中可用,并且无法用于较低的iOS版本.

3)mac地址不是一个选项,因为它在iOS-7中是不允许的

4)OpenUDID不久前已被弃用,并且还存在iOS-6问题.

5)iOS-5及以下版本也没有广告标识符

最后这就是我所做的

a)将SFHFKeychainUtils添加到项目中

b)生成的CFUUID密钥字符串

 CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
    udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
Run Code Online (Sandbox Code Playgroud)

c)将其保存到Key Chain Utils ,否则它将生成一个新的Unique Every Time

最终守则

+ (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;
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

详情请联系我们

  • 这个答案值得更多的赞成 (3认同)
  • 很好地解释.当然这应该是公认的答案 (2认同)

mik*_*eho 15

有些人想了解更多关于可用的不同选项,如果你这样做,请看看@ NSQuamber.java的答案.如果您想知道如何使用NSUUID并与iCloud同步,请继续阅读.这篇文章最终比我原本想要的更加冗长,但我希望它能让任何采取这些步骤的人明白!

使用NSUUID

我使用NSUUID类来创建UUID:

NSUUID *uuid = [NSUUID UUID];
Run Code Online (Sandbox Code Playgroud)

然后要创建字符串,您只需要调用该UUIDString方法:

NSString *uuidString = [uuid UUIDString];
Run Code Online (Sandbox Code Playgroud)

或者在一行中完成:

NSString *uuidString = [[NSUUID UUID] UUIDString];
Run Code Online (Sandbox Code Playgroud)

恕我直言,这比尝试使用CFUUIDCreate要容易得多,并且有一个必须维护的方法.


编辑:我现在使用UICKeyChainStore

使用UICKeyChainStore设置UUID:

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"];
keychain[@"com.sample.MyApp.user"] = userID;
Run Code Online (Sandbox Code Playgroud)

要检索它:

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"];
NSString *userID = keychain[@"com.sample.MyApp.user"];
Run Code Online (Sandbox Code Playgroud)

然后我使用SSKeyChain将UUID存储到Keychain

使用SSKeyChain设置UUID:

[SSKeychain setPassword:userID forService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"];
Run Code Online (Sandbox Code Playgroud)

要检索它:

NSString *userID = [SSKeychain passwordForService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"];
Run Code Online (Sandbox Code Playgroud)

当您将UUID设置为Keychain时,即使用户完全卸载App然后再次安装它,它仍会保留.

与iCloud同步

因此,确保所有用户的设备使用相同的UUID非常有用.这是为了确保数据在所有设备之间同步,而不是每个设备都认为它是一个独特的用户.

关于同步如何工作的答案中有几个问题,所以现在我已经完成了所有工作,我将提供更多细节.

配置iCloud/NSUbiquitousKeyValueStore使用

  1. 单击Xcode中Project Navigator顶部的项目.
  2. 选择功能.
  3. 打开iCloud.

现在应该看起来像这样: 启用iCloud的屏幕截图

使用NSUbiquitousKeyValueStore

使用iCloud非常简单.来写:

// 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];
Run Code Online (Sandbox Code Playgroud)

阅读:

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

// read from iCloud
NSString *userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey];
Run Code Online (Sandbox Code Playgroud)

在您编写NSUbiquitousKeyValueStore文档之前,请先说明您需要从iCloud中读取.要强制读取,请调用以下方法:

[[NSUbiquitousKeyValueStore defaultStore] synchronize];
Run Code Online (Sandbox Code Playgroud)

要让您的应用收到iCloud中的更改通知,请添加以下通知:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(iCloudStoreDidChange:)
                                             name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
                                           object:[NSUbiquitousKeyValueStore defaultStore]];
Run Code Online (Sandbox Code Playgroud)

使用iCloud创建UUID

结合NSUUID,SSKeychain和NSUbiquityKeyValueStore,这是我生成用户ID的方法:

- (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];
}
Run Code Online (Sandbox Code Playgroud)

如何确保您的用户ID同步

因为写入iCloud需要先在iCloud中下载任何数据,所以我将同步调用放在(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法的顶部.我还在那里添加了通知注册.这允许我检测iCloud的任何变化并适当地处理它们.

这是一个示例:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当应用程序启动或返回到前台时,我强制与iCloud同步并验证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;
}
Run Code Online (Sandbox Code Playgroud)

如果首先出现哪个UUID

在我的UserID的用例中,我假设iCloud中的值是要保留的值,因为它将是第一个推送到iCloud的UUID,无论哪个设备首先生成UUID.大多数人可能会采取相同的路径,因为你不会真正关心它解析的UUID,只要它解析为一个.对于那些真正关心哪个是第一个的人,我建议您存储UUID和时间戳生成([[NSDate date] timeIntervalSince1970]),以便您可以检查哪个更老:

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

// or just subtract
double timeDifference = timestamp1 - timestamp2;
Run Code Online (Sandbox Code Playgroud)


Suh*_*tel 10

在Github上有一个不错的选择,它基于Mac地址和捆绑标识符的组合生成唯一标识符,该标识符运行良好:UIDevice-with-UniqueIdentifier-for-iOS-5

  • iOS 7中现在无法使用MAC地址. (8认同)