IOS体系ID知多少?【技术类】

IOS体系ID知多少?【技术类】

吴俊吴俊
摘要:移动IOS设备体系ID您知道多少?

本系列第一篇《移动设备ID烦恼知多少?》已将ID的各种烦恼问题说了那么多,下面我体系化地从IOS、Android两大体系来详解一下两大体系中的各种设备ID吧:

先说IOS吧:2013年IOS6是一个巨大的分水岭:

一、IMEI

在iOS5之后该方法就被废弃掉了,因此iOS5以后不能获取手机IMEI,但是也是可以通过私有API获取手机的IMEI号的,但是通过苹果私有API获取IMEI号,上架苹果商店会被拒掉的。

电信运营商因为通讯网络协议中都是传递用户手机的IMEI及SIM卡的IMSI,所以运营商是有这些用户的IMEI及IMSI的;

二、UDID

UDID的全称是UniqueDevice Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成。在很多需要限制一台设备一个账号的应用中经常会用到。在iOS5中可以获取到设备的UDID,iOS7中已经完全的禁用了它。iOS7之前的使用了的app如果在iOS7上运行,它不会返回设备的UDID,而是会返回一串字符串,以FFFFFFFF开头,跟着identifierForVendor的十六进制值。

废弃版本:iOS6

获取代码:[[UIDevice currentDevice] uniqueIdentifier]

AppleAccount(非法私有方法):虽然苹果在iOS6中禁用了获取UDID的方式,但是只要你研究下就知道这个API只是私有化了,使用私有API还是可以获取设备的UDID。但是这个方法也面临着风险:比如API变更以及AppStore审核问题,但是在越狱设备上你还是可以尽情享用的。

类:AADeviceInfo(dump出头文件)

@classNSObject<OS_dispatch_semaphore>, APSConnection, NSData;

@interfaceAADeviceInfo : 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一样在项目中使用)

三、无线网卡MAC地址

1、在App中编程获取使用:

IOS7以后不能通过获得MAC地址来标示手机唯一,App应用在iOS6及以下时,可以正确取道Mac地址,在iOS7上,会返回固定值。这样带来的问题是无法区分具体的iOS设备,有些产品就非常难搞了,目前没有找到可以区分不同iOS设备的方法。测试过mac地址,确实会返回固定值02:00:00:00:00:00。

MAC地址在网络上用来区分设备的唯一性,接入网络的设备都有一个MAC地址,他们肯定都是不同的,是唯一的。一部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一个WIFI的,因此只需获取WIFI的MAC地址就好了,也就是en0的地址。MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。但在iOS7之后,如果请求Mac地址都会返回一个固定值。

废弃版本:iOS7.0+(当然App有一些特殊的方法,例如主动提示用户选择WIFI网络的方式可以获取MAC地址。)

获取代码:

- (NSString *)macAddress

{

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_nametoindexerror/n");

return NULL;

}

if (sysctl(mib, 6, NULL, &len, NULL, 0)< 0) {

printf("Error: sysctl, take1/n");

return NULL;

}

if ((buf = malloc(len)) == NULL) {

printf("Could not allocate memory.error!/n");

return NULL;

}

if (sysctl(mib, 6, buf, &len, NULL, 0)< 0) {

printf("Error: sysctl, take2");

return NULL;

}

ifm = (struct if_msghdr *)buf;

sdl = (struct sockaddr_dl *)(ifm + 1);

ptr = (unsigned char *)LLADDR(sdl);

NSString *outstring = [NSStringstringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1),*(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];

NSLog(@"outString:%@",outstring);

free(buf);

return [outstring uppercaseString];

}

2、WIFI上网成功后时WIFI AP可以获取这个设备的MAC地址;

3、WIFI AP探针SSID广播扫描已获取不到IOS8以上手机的MAC地址;

IOS8在同WIFI AP探针SSID广播扫描包通讯的时候,因为是非主动申请上网,所以IOS8都会随机生成一个MAC地址来回应WIFI AP探针。导致WIFI AP探针获取到假的MAC地址,以保护用户隐私。

当然有一些特别的做法:例如将AP伪装为用户常用的”SSID”,例如:“CMCC”等等,IOS会主动尝试连接,这个时候WIFI AP探针就获取到了用户真实的MAC地址。

四、IDFV

IDFV是App隔离的,某一App内部获取到给用户的IDFV是稳定不变的,但是不同App之间获取的IDFV是不同的,意味着App内部要追踪和分析用户及个性化可以直接使用IDFV。而要跨App来追踪这个用户的设备IDFV就无能为力了。

iOS 6.0系统新增用于替换uniqueIdentifier的接口。是给Vendor标识用户用的,每个设备在所属同一个Vender的应用里,都有相同的值。其中的Vender是指应用提供商,但准确点说,是通过BundleID的DNS反转的前两部分进行匹配,如果相同就是同一个Vender,例如对于com.somecompany.appone,com.somecompany.apptwo这两个BundleID来说,就属于同一个Vender,共享同一个idfv的值。和idfa不同的是,idfv的值是一定能取到的,所以非常适合于作为内部用户行为分析的主id,来标识用户,替代OpenUDID。如果用户将属于此Vender的所有App卸载,则idfv的值会被重置,即再重装此Vender的App,idfv的值和之前不同。

适用:iOS6.0+

例子:95955F33-BFBD-48BA-A630-866D2DAE482D

获取代码:[[[UIDevice currentDevice]identifierForVendor] UUIDString]

五、IDFA

广告标示符,适用于对外:例如广告推广,换量等跨应用的用户追踪等。

适用:iOS6.0+

例子:9C287922-EE26-4501-94B5-DDE6F83E1475

获取代码:[[[ASIdentifierManager sharedManager] advertisingIdentifier]UUIDString];

详细代码如下:

a.添加框架

AdSupport.framework

b.添加头文件

#import<AdSupport/ASIdentifierManager.h>

c.使用语句

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

NSLog(@"identifierForAdvertising ==%@",identifierForAdvertising)

广告标示符是由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序 ->通用 -> 还原 ->还原位置与隐私),这个广告标示符会重新生成。

另外如果用户明确的还原广告(设置程序->通用 -> 关于本机 ->广告 ->还原广告标示符),那么广告标示符也会重新生成。


关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。之所以会这样,因为ASIdentifierManager是一个单例。


作为媒体方的App开启IDFA注意:在App提交AppStore审核时,对于IDFA的用途请按下图勾选,且在AppStore的审核人员审核操作时能看到Ad,否则App审核将被拒(无Ad不可使用IDFA)。


作为广告主方App开启IDFA注意:在App提交AppStore审核时,对于IDFA的用途请按下图勾选,说明使用IDFA是为了作为广告主要跟踪广告效果的需要(若被拒,可按此理由作为广告主身份进行申诉。):

作为既具备媒体方及广告主方特性的App开启IDFA注意:在App提交AppStore审核时,对于IDFA的用途请按下图勾选,且在AppStore的审核人员审核操作时能看到Ad,否则App审核将被拒(无Ad不可使用IDFA)


若按上述操作后App审核仍被拒,可开启一个临时的Ad(无Ad不可使用IDFA),审核通过后关闭该Ad(在AppStore的审核人员审核操作时能看到Ad即可),且可发送一个带有Ad的截图进行申诉。

附被拒提示:

提交App审核时若未勾上“使用了IDFA”被拒的提示如下: Improper Advertising Identifier [IDFA] Usage. Your app contains theAdvertising Identifier [IDFA] API but you have not indicated its usage on thePrepare for Upload page in iTunes Connect.

提交App审核是若未勾上“Limit Ad Tracking setting in iOS”被拒的提示如下: Improper Advertising Identifier [IDFA] Usage. Your app contains theAdvertising Identifier [IDFA] API but your app is not respecting the Limit AdTracking setting in iOS.


最近大家恐慌的IOS10 关闭广告追踪后 IDFA为一串“0000……”不必惊慌,因为早在IOS6的时候就已经有这个功能了也没看到多大影响。一般IDFA是专门给“广告用的”,而Iphone手机只要在出厂的时候没有关闭“广告追踪”,很少有用户会主动去设置关闭。(据不完全统计也就10%左右的专业用户能找到那个藏的很深入的设置界面)。


同时IDFA由于是App获取后需要通过业务程序发送给服务器端的,所以电信运营商只有通过寻找业务数据包特征码的方式拆解业务数据包才能获取IDFA。所以不能100%拥有IDFA。

六、KeyChain

iOS整个系统有一个KeyChain,每个程序都可以往KeyChain中记录数据,而且只能读取到自己程序记录在KeyChain中的数据。而且就算我们程序删除掉,系统经过升级以后再安装回来,依旧可以获取到与之前一致的UDID(系统还原、刷机除外)。因此我们可以将UUID的字符串存储到KeyChain中,然后下次直接从KeyChain获取UUID字符串。(本示例中使用KeychainItemWrapper工具类)。

获取代码:

+(NSString *)UUID {

KeychainItemWrapper *keyChainWrapper =[[KeychainItemWrapper alloc] initWithIdentifier:@"MYAppID"accessGroup:@"com.test.app"];

NSString *UUID = [keyChainWrapper objectForKey:(__bridgeid)kSecValueData];

if (UUID == nil || UUID.length == 0) {

UUID = [[[UIDevice currentDevice]identifierForVendor] UUIDString];

[keyChainWrapper setObject:UUIDforKey:(__bridge id)kSecValueData];

}

return UUID;

}

七、OpenUDID:(IOS7+已无法使用)

非Apple官方提供的Api,原理是由第一个使用openudid的app生成,并存放到系统粘贴版(具体也不理解什么原理),之后安装的其他app去粘贴版取。但ios7发布后,OpenUDID不能用了. OpenUDID是用系统粘贴板作为中间存储供所有app调用. 新的系统把粘贴板的访问权限限制在了同一个开发者的范围内,既同一个开发者的多个app在同个设备上共享粘贴板。

目前市场上IOS主要以IDFA作为广告流量标识为主。


大家是不是已经彻底晕菜了?那我们休息一下,下篇再来看看“Android体系的各种ID”吧。

(转载请注明出处:微信订阅号:ad_automation)


文字的表现力毕竟有限,若大家还比较迷糊的话,欢迎参加“1.7号的线下大课堂专门增加了针对移动ID的专题,可面对面为您答疑解惑讲透这些问题。

「真诚赞赏,手留余香」
还没有人赞赏,快来当第一个赞赏的人吧!
文章被以下专栏收录
7 条评论
推荐阅读