iOS获取设备唯一标识:UDID、IDFA、IDFV、OpenIDFA、SimulateIDFA等.

15,589 阅读5分钟

1. UDID

UDID全称是Unique Device Identifier,顾名思义,它就是苹果iOS设备的唯一标识码,它由40个字符的字母和数字组成。在很多需要限制一台设备一个张红的应用中经常会用到。哎iOS5中可以获取到设备的UDID,iOS7中已经完全禁用了它。iOS7之前的使用app如果在iOS7以上的设备运行,它不会反悔设备的UDID,而是会返回一串字符串,以FFFFF开头,跟着一串十六进制值。 获取:[[UIDevice currenDevice] uniqueIdentifier]
废弃:iOS6

2.IDFV

IDFV是通过BundleID的DNS反串的前两部分进行匹配,如果相同,返回的值就相同。
例如:com.company.hello和com.company.word这两个bundleID就是同一个Vender生成的IDFV就是相同的,如果用户把所有此Vender的app都卸载,再次获取IDFV就会和之前的不同,会被重置。
获取方式:[[[UIDevice currentDevice] identifierForVendor] UUIDString]
试用:iOS6+
注意:无法保证唯一标识

3.IDFA

该标识是用来进行广告标记,进行推送广告。
用户可以在设置->隐私->广告,进行重置此ID的值,获取直接关闭,关闭之后获取的值是000000000xxxxx
获取:[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]
试用:iOS6+
注意:该值在用户没有对系统设置进行修改的时候是惟一的,但是用户可以进行手动操作关闭或者重置

4.MAC

在iOS7之后,无法获取到值(是一个固定值) 废弃:iOS7+

5.KeyChain

简介:iOS整个系统中有一个KeyChain,每个程序都可以往KeyChain中记录数据,而且只能读取到自己程序记录在KeyChain中的数据。而且就算我们程序删除掉,系统经过在升级,重新安装应用,获取到的值还是不改变,(系统还原、刷机除外)。因此我们可以将UUID的字符串存储在KeyChain中,然后下次直接从KeyChain获取唯一标识例如:

+ (NSString *)UUID {
    KeychainItemWrapper *keyChainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MYAppID" accessGroup:@"com.test.app"];
    NSString *UUID = [keyChainWrapper objectForKey:(__bridge id)kSecValueData];

    if (UUID == nil || UUID.length == 0) {
        UUID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
        [keyChainWrapper setObject:UUID forKey:(__bridge id)kSecValueData];
    }

    return UUID;
}

6.AppleAccount

简介:虽然Apple在iOS6之后禁用了UUID的获取,但是可以通过私有API的方式获取UUID,但是这种方式有存在风险,比如私有API会有变更的风险,导致无法获取,获取私有API会影响AppStore审核,只有在越狱设备上可以使用
可以通过dump的方式获取私有头文件

@class NSObject<OS_dispatch_semaphore>, APSConnection, NSData;

@interface AADeviceInfo : NSObject {

APSConnection *_apsConnection;

BOOL _tokenDone;

NSData *_token;

NSObject<OS_dispatch_semaphore> *_tokenSema;

}

+ (id)userAgentHeader;

+ (id)signatureWithDictionary:(id)arg1;

+ (id)apnsToken;

+ (id)serialNumber;

+ (id)clientInfoHeader;

+ (id)appleIDClientIdentifier;

+ (id)productVersion;

+ (id)osVersion;

+ (id)udid;

+ (id)infoDictionary;

- (id)wifiMacAddress;

- (id)regionCode;

- (id)deviceClass;

- (id)osName;

- (id)productType;

- (id)apnsToken;

- (id)serialNumber;

- (id)deviceInfoDictionary;

- (id)appleIDClientIdentifier;

- (id)productVersion;

- (id)osVersion;

- (id)udid;

- (id)init;

- (void).cxx_destruct;

- (id)buildVersion;

@end

获取:[AADeviceInfo udid]
使用方法:在项目中将真机上的AppleAccount.framework框架导出,引入Xcode工程中,利用runtime或者直接使用该类就行。 (细节补充:导出AppleAccount.framework后,进入AppleAccount.framework的根目录,新建Headers文件夹,然后将dump出的头文件放在Headers目录,就可以像引用第三方framework一样在项目中使用,导出framework需要通过越狱设备)

二、通过算法计算得出唯一标识

1.SimulateIDFA

简介:SimulatorIDFA是通过设备的各种信息计算整合成的一串MD5值,用于标记不同设备
使用:

CoreTelephony.framework
https://github.com/youmi/SimulateIDFA (下载代码)

注意:SimulatorIDFA设备信息包括了系统版本,如果升级了就会出现唯一标识出现改变。

2.OpenIDFA

简介:OpenIDFA 是 Yann Lechelle的一个开源库。同是IDFA的替换方案
也是通过算法计算设备的一些信息,整合的一个字符串.

时效性对比:

  1. OpenIDFA
    每天获取的值都不一样
  2. SimulateIDFA
    SimulateIDFA分两部分,前16位是在系统升级的时候才会变化,后16位用户的某些行为可能会导致值变化(例如:重启手机、修改设备名称、修改手机本地语言)

总结:

OpenIDFA 有一些限制,生成的IDFA会每天变化,在一些极端条件下重复率比较高。 SimulateIDFA在这方面有更好的表现

检查是否有应用IDFA

检查我们项目中是否使用广告标示符,其实就是查看我们-

  1. framework中是否有个叫做AdSupport.framework的框架;
  2. 如果检查framework没有,可能是我们接入的第三方里面有,用以下方法检查第三方中是否包含有IDFA版本;
(1)打开终端cd到要检查的文件的目录;
(2)执行命令:grep -r advertisingIdentifier .(注意别少了点);

对比各个设备ID稳定性:

情况IDFA(广告标识符)存于Keychain的IDFAOpenUDID存于Keychain的OpenUDID
删除应用不会改变不会改变,也不会被删除不会改变不会改变,也不会被删除
手机还原所有设置不会改变不会改变,也不会被删除不会改变不会改变,也不会被删除
手机抹掉所有数据改变被删除改变被删除
还原广告标识符改变原存于Keychain的数据没变化,除非重新写入不会改变不会改变,也不会被删除
同一设备,不同开发者的应用(签名不一样)不会改变不会改变,也不会被删除改变如果没有重新写入keychain,则为NULL

后续有变化再更新内容,先总结结论

参考地址:
iOS获取设备UUID和IDFA
OpenUDID 和 IDFA 比较
开源框架OpenUDID源码和伪源码分析