Id UUID 在会话中是静态的吗?

Posted

技术标签:

【中文标题】Id UUID 在会话中是静态的吗?【英文标题】:Id UUID static over sessions? 【发布时间】:2013-05-23 10:30:57 【问题描述】:

我想使用 UDID 的替代方法并找到了这个:

+ (NSString *)GetUUID

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

但在模拟器中,该方法每次都会给我不同的结果?

这仅在模拟器中吗?

我需要确保在实际设备上该方法总是返回相同的字符串 识别用户。

是真是假?

米尔扎

【问题讨论】:

它只适用于设备.. 【参考方案1】:

CFUUIDRef 将在每个会话中创建不同的值。

解决方案 1:

将值保存在NSUserDefaults 中,下次使用NSUserDefaults 中的值。

解决方案 2:

您可以使用identifierForVendor 来执行此操作。

NSString *udidVendor = [[[UIDevice currentDevice] identifierForVendor] UUIDString];

根据UIDevice Class Reference:

对于来自 同一供应商在同一设备上运行。返回不同的值 对于来自不同供应商的同一设备上的应用程序,以及 不同设备上的应用程序,无论供应商如何。

请查看Unique Identifier In ios 6

【讨论】:

谢谢大家,你建议 openudid 但每次会议给我不同的结果 @LejlaHatipovic:我认为您对我的回答发表了错误的评论。可能你想对 Mar0ux 这么说。 :)【参考方案2】:

每次调用该函数时,CFUUIDCreate 都会为您提供一个通用唯一标识符,因此每次您都会得到不同的结果(根据定义)。

您可以做的是在会话之间使用 NSUserDefaults 等方式将其持久化,以唯一标识特定用户(或一组用户设置)。

【讨论】:

【参考方案3】:

CFUUID 根本不持久。

每次您调用 CFUUIDCreate 时,系统都会向您返回一个全新的唯一标识符。

如果您想保留此标识符,您需要自己使用 NSUserDefaults、Keychain、Pasteboard 或其他方式来完成。

【讨论】:

【参考方案4】:

一次读一行代码,试着理解它的作用。 CFUUIDCreate 函数在您每次调用它时都会创建一个 new UUID。这可以解释你的发现。您需要在第一次保存 NSUserDefaults* 中的值,并在下次启动应用程序时使用该值:

+ (NSString *)GetUUID

    NSString *string = [[NSUserDefaults standardUserDefaults] objectForKey: @"UUID"];
    if (!string)
    
        CFUUIDRef theUUID = CFUUIDCreate(NULL);
        string = (NSString*)[CFUUIDCreateString(NULL, theUUID) autorelease];
        CFRelease(theUUID);
        [[NSUserDefaults standardUserDefaults] setObject: string forKey: @"UUID"];
    
    return string;

*使用NSUserDefaults 有一个小警告 - 如果用户再次卸载并重新安装应用程序,将再次创建 UUID。如果您不能忍受这个,请考虑将其保存在钥匙串中。或者,您可能想查看OpenUDID。

【讨论】:

【参考方案5】:

该方法将始终返回一个唯一的字符串。如果应用程序只有一个用户,请在用户 first 启动应用程序时运行一次此方法,并将该字符串保存在 plist 或 NSUserDefaults 或核心数据中(如果您已经使用它) .

以下链接可能有助于此 UUID 持久性逻辑: UUID for app on iOS5

但是,如果用户随后卸载并重新安装应用程序,这个持久化的 UUID 仍然会丢失,并且会再次生成需求。

Apple 也不再允许使用设备 ID。

假设由于应用程序连接到服务器而需要 UUID,据我所知,您需要用户使用用户名和密码登录服务器。

【讨论】:

【参考方案6】:

它总是不同的。 UUID 包含时间戳,因此每次调用此函数时,都会得到一个不同的(随机)。 我在IDManager 类中采用了这种方法, 这是来自不同解决方案的集合。 KeyChainUtil 是一个从钥匙串中读取的包装器。在github 中可以找到类似的钥匙串工具。

//  IDManager.m


/*
 A replacement for deprecated uniqueIdentifier API. Apple restrict using this from 1st May, 2013.

 We have to consider,
    * iOS <6 have not the ASIIdentifer API
    * When the user upgrade from iOS < 6 to >6
        - Check if there is a UUID already stored in keychain. Then use that. 
            - In that case, this UUID is constant for whole device lifetime. Keychain item is not deleted with application deletion.
 */

#import "IDManager.h"
#import "KeychainUtils.h"
#import "CommonUtil.h"

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
    #import <AdSupport/AdSupport.h>
#endif

#include <sys/socket.h> 
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>



/*  Apple confirmed this bug in their system in response to a Technical Support Incident request. They said that identifierForVendor and advertisingIdentifier sometimes returning all zeros can be seen both in development builds and apps downloaded over the air from the App Store. They have no work around and can't say when the problem will be fixed. */
#define kBuggyASIID             @"00000000-0000-0000-0000-000000000000"


#pragma mark 


#pragma mark 

@implementation IDManager

+ (NSString *) getUniqueID 

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000

    if (NSClassFromString(@"ASIdentifierManager")) 
        NSString * asiID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
        if ([asiID compare:kBuggyASIID] == NSOrderedSame) 
            NSLog(@"Error: This device return buggy advertisingIdentifier.");
            return [IDManager getUniqueUUID];
         else 
            return asiID;
        

     else 

#endif

        return [IDManager getUniqueUUID];

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 60000
    
#endif



+ (NSString *) getUniqueUUID 

    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:@"UserName" andServiceName:@"YourServiceName" error:&error];
    if (error) 
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    
    if (!uuid) 
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager getUUID];
        uuid = [CommonUtil md5String:uuid]; // create md5 hash for security reason
        [KeychainUtils storeUsername:@"UserName" andPassword:uuid forServiceName:@"YourServiceName" updateExisting:YES error:&error];
        if (error) 
            NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        
    
    return uuid;


+ (NSString *) readUUIDFromKeyChain 
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:@"UserName" andServiceName:@"YourServiceName" error:&error];
    if (error) 
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    
    return uuid;


/* NSUUID is after iOS 6. So we are using CFUUID for compatibility with iOS 4.3 */
+ (NSString *)getUUID

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


#pragma mark - MAC address

/* THIS WILL NOT WORK IN iOS 7. IT WILL RETURN A CONSTANT MAC ADDRESS ALL THE TIME.
 SEE - https://developer.apple.com/news/?id=8222013a
 */

// Return the local MAC address
// Courtesy of FreeBSD hackers email list
// Last fallback for unique identifier
+ (NSString *) getMACAddress

    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;

    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;

    if ((mib[5] = if_nametoindex("en0")) == 0) 
        printf("Error: if_nametoindex error\n");
        return NULL;
    

    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) 
        printf("Error: sysctl, take 1\n");
        return NULL;
    

    if ((buf = malloc(len)) == NULL) 
        printf("Error: Memory allocation error\n");
        return NULL;
    

    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) 
        printf("Error: sysctl, take 2\n");
        free(buf); // Thanks, Remy "Psy" Demerest
        return NULL;
    

    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];

    free(buf);
    return outstring;


+ (NSString *) getHashedMACAddress

    NSString * mac = [IDManager getMACAddress];
    return [CommonUtil md5String:mac];


@end

【讨论】:

如何获取 IDManager 类? IDManager 类代码在这里给出。将代码包装在类名 IDManager 中。

以上是关于Id UUID 在会话中是静态的吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用 UUID v4 生成会话 ID 是不是安全?

query_id 在所有 Snowflake 帐户中是唯一的吗?

使用中间件将 UUID 存储在会话中

我对 PHP 会话的理解正确吗?

Ruby on Rails 中的会话如何工作?

为啥php每次在测试环境(WAMP)中生成相同的会话ID?