xcode identifierForVendor 和 iOS6

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12506893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 01:32:12  来源:igfitidea点击:

identifierForVendor and iOS6

objective-ciosxcodeitunes

提问by Ryan

The identifierForVendorrequire iOS6, so if my app currently supporting iOS4 and therefore I can't use it since my updates should always meet my app's previous min. requirement?

identifierForVendor要求iOS6的,所以如果我的应用程序目前支持iOS4的,所以我不能使用它,因为我的更新应该总能满足我的应用程序以前分钟。要求?

回答by Naka

You can use this:

你可以使用这个:

NSString *udid;

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0"))
    udid = [UIDevice currentDevice].identifierForVendor.UUIDString;
else
    udid = [UIDevice currentDevice].uniqueIdentifier;

with pre processor code:

带有预处理器代码:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

回答by Laszlo

You don't need preprocessor macros for this, you should check if it response, like this:

您不需要为此使用预处理器宏,您应该检查它是否响应,如下所示:

if ([[UIDevice currentDevice]respondsToSelector:@selector(identifierForVendor)]) {
    return [UIDevice currentDevice].identifierForVendor.UUIDString;
}else{
    // return [UIDevice currentDevice]. uniqueIdentifier
    return [[UIDevice currentDevice] performSelector:@selector(uniqueIdentifier)];
}

回答by karim

It is always different. UUID includes timestamps, so every time you call this function, you will get a different (random) one. I have followed this approach in IDManagerclass, This is a collection from different solutions. KeyChainUtil is a wrapper to read from keychain. A similar keychain util is found in github.

它总是不同的。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

回答by J. Costa

You can use the following code

您可以使用以下代码

if (NSClassFromString(@"ASIdentifierManager")) {
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];           
} else {
    // return other identifier generated with OpenUDID or some custom method
}

You can get OpenUDID documentation here

您可以在此处获取 OpenUDID 文档

回答by miho

Have a look at NSSelectorFromStringand [NSObject performSelector:SEL]. NSSelectorFromStringallows you to select a selector by runtime with a string. Use it in combination with a OS version check at runtime.

看看NSSelectorFromString和 [NSObject performSelector:SEL]。NSSelectorFromString允许您通过运行时使用字符串选择选择器。将它与运行时的操作系统版本检查结合使用。