UIDevice的uniqueIdentifier已经被弃用 - 现在该怎么做?

511
刚刚得知,在iOS 5中已将UIDevice唯一标识符属性(uniqueIdentifier property)作废,在iOS 7及以上版本中也不再提供该属性的支持。目前似乎没有可用或即将推出的替代方法或属性。

我们许多现有的应用程序都高度依赖此属性来唯一标识特定设备。那么我们该如何解决这个问题呢?

2011-2012年的文档建议:

特别注意事项

不要使用uniqueIdentifier属性。要创建与您的应用程序特定的唯一标识符,您可以调用CFUUIDCreate函数创建UUID,并使用NSUserDefaults类将其写入默认数据库。

但是如果用户卸载并重新安装该应用程序,该值将不同。


1
对于仍在使用uniqueIdentifier的应用程序,iOS7现在返回FFFFFFFF + identifierForVendor,这破坏了许多编写不良的非续订订阅应用程序。 - Rhythmic Fistman
如果你的应用程序幸运地使用了推送通知,你可以使用从苹果推送服务返回的令牌,它对于每个设备都是唯一的。 - Calin Chitu
如果用户不接受推送通知,您是否仍会为该用户获取推送ID? - Chase Roberts
32个回答

1
请使用以下代码来适配Swift 3.0。
let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)

1
iOS 11引入了DeviceCheck框架。它提供了一种完美的解决方案,可以唯一地识别设备。 - Santosh Botre

1
你可以使用

标签


NSString *sID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

设备在所有应用程序中都是独一无二的。

1

但是它需要一个互联网连接,不是吗? - Nike Kov
是的,它需要互联网连接。 - Santosh Botre

0

一个不完美但是最好和最接近UDID的替代方案(在使用iOS 8.1和Xcode 6.1的Swift中):

生成一个随机UUID

let strUUID: String = NSUUID().UUIDString

并使用KeychainWrapper库:

将字符串值添加到钥匙串中:

let saveSuccessful: Bool = KeychainWrapper.setString("Some String", forKey: "myKey")

从钥匙串中检索字符串值:

let retrievedString: String? = KeychainWrapper.stringForKey("myKey")

从钥匙串中删除字符串值:

let removeSuccessful: Bool = KeychainWrapper.removeObjectForKey("myKey")

该解决方案使用钥匙串,因此存储在钥匙串中的记录将被持久化,即使应用程序被卸载并重新安装后也是如此。删除此记录的唯一方法是重置设备的所有内容和设置。这就是为什么我提到,虽然这种替代方案并不完美,但在使用Swift的iOS 8.1上,仍然是最好的UDID替代方案之一。


0
如果有人在寻找替代方案时偶然遇到了这个问题,我已经在IDManager类中采用了这种方法。这是从不同解决方案中收集的。KeyChainUtil是一个包装器,用于从钥匙串中读取。您还可以使用散列MAC地址作为一种唯一ID。
/*  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"

+ (NSString *) getUniqueID {
    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 {
        return [IDManager getUniqueUUID];
    }
}


+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService 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 = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

/* NSUUID is after iOS 6. */
+ (NSString *)GetUUID
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

#pragma mark - MAC address
// Return the local MAC addy
// 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 [Util md5String:mac];
}

+ (NSString *)md5String:(NSString *)plainText
{
    if(plainText == nil || [plainText length] == 0)
        return nil;

    const char *value = [plainText UTF8String];
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);

    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    NSString * retString = [NSString stringWithString:outputString];
    [outputString release];
    return retString;
}

0

我们可以在iOS7中使用identifierForVendor

-(NSString*)uniqueIDForDevice
{
    NSString* uniqueIdentifier = nil;
    if( [UIDevice instancesRespondToSelector:@selector(identifierForVendor)] ) { // >=iOS 7
        uniqueIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    } else { //<=iOS6, Use UDID of Device       
            CFUUIDRef uuid = CFUUIDCreate(NULL);
            //uniqueIdentifier = ( NSString*)CFUUIDCreateString(NULL, uuid);- for non- ARC
            uniqueIdentifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));// for ARC
            CFRelease(uuid);
         }
    }
return uniqueIdentifier;
}

--重要提示--

UDID和identifierForVendor是不同的:---

1.) On uninstalling  and reinstalling the app identifierForVendor will change.

2.) The value of identifierForVendor remains the same for all the apps installed from the same vendor on the device.

3.) The value of identifierForVendor also changes for all the apps if any of the app (from same vendor) is reinstalled.

你确定吗?我们可以在iOS7中使用identifierForVendor吗? - Avis

0
+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService 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 = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

0

我也遇到了一些问题,解决方案很简单:

    // Get Bundle Info for Remote Registration (handy if you have more than one app)
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];


    // Get the users Device Model, Display Name, Unique ID, Token & Version Number
    UIDevice *dev = [UIDevice currentDevice];
    NSString *deviceUuid=[dev.identifierForVendor  UUIDString];

    NSString *deviceName = dev.name;

0

NSLog(@"%@",[[UIDevice currentDevice]identifierForVendor]);

NSLog(@“%@”,[[UIDevice currentDevice] identifierForVendor]);


0

自iOS 7开始,苹果已经从所有公共API中隐藏了UDID。任何以FFFF开头的UDID都是伪造的ID。之前可以使用的“发送UDID”应用程序现在不能再用于收集测试设备的UDID。(叹气!)

当设备连接到XCode(在组织者中)时,会显示UDID;当设备连接到iTunes时也会显示UDID(尽管您必须单击“序列号”才能显示标识符)。

如果您需要获取设备的UDID以添加到配置文件中,而无法在XCode中自行完成,则必须引导他们按照步骤从iTunes中复制/粘贴它。

自iOS 7发布以来,是否有一种不使用PC / Mac上的iTunes获取UDID的方法?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接