iOS获取设备唯一标示符UDIDUUIDIDFAIDFVIMEIIMSIMAC地址OpenUUID

iOS获取设备唯⼀标⽰符UDIDUUIDIDFAIDFVIMEIIMSIMAC
地址OpenUUID
各种获取设备唯⼀标识的⽅法介绍
幸福双响炮
⼀.UDID(Unique Device Identifier)
UDID的全称是Unique Device Identifier,它就是苹果iOS设备的唯⼀识别码,它由40位16进制数的字母和数字组成(越狱的设备通过某些⼯具可以改变设备的UDID)。移动⽹络可利⽤UDID来识别移动设备,但是,从IOS5.0(2011年8⽉份)开始,苹果宣布将不再⽀持⽤uniqueIdentifier⽅法获取设备的UDID,iOS5以下是可以⽤的。苹果从iOS5开始就移除了通过代码访问UDID的权限。从2013年5⽉1⽇起,试图访问UIDIDs的程序将不再被审核通过,替代的⽅案是开发者应该使⽤“在iOS 6中介绍的Vendor或Advertising标⽰符”。所以UDID是绝对是不能再使⽤了。
//UDID , 已废除
NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];
为什么苹果反对开发⼈员使⽤UDID?
iOS 2.0版本以后UIDevice提供⼀个获取设备唯⼀标识符的⽅法uniqueIdentifier,通过该⽅法我们可以获取设备的序列号,这个也是⽬前为⽌唯⼀可以确认唯⼀的标⽰符。 许多开发者把UDID跟⽤户的真实姓名、密码、住址、其它数据关联起来;⽹络窥探者会从多个应⽤收集这些数据,然后顺藤摸⽠得到这个⼈的许多隐私数据。同时⼤部分应⽤确实在频繁传输UDID和私⼈信息。 为了避免集体诉讼,苹果最终决定在iOS 5 的时候,将这⼀惯例废除,开发者被引导⽣成⼀个唯⼀的标识符,只能检测应⽤程序,其他的信息不提供。现在应⽤试图获取UDID已被禁⽌且不允许上架。
⽰例:bb4d786633053a0b9c0da20d54ea7e38e8776da4
⼆.UUID(Universally Unique Identifier)
UUID是Universally Unique Identifier的缩写,中⽂意思是通⽤唯⼀识别码。它是让分布式系统中的所有元素,都能有唯⼀的辨识资讯,⽽不需要透过中央控制端来做辨识资讯的指定。这样,每个⼈都可以建⽴不与其它⼈冲突的 UUID。在此情况下,就不需考虑数据库建⽴时的名称重复问题。苹果公司建议使⽤UUID为应⽤⽣成唯⼀标识字符串。
获得的UUID值系统没有存储, ⽽且每次调⽤得到UUID,系统都会返回⼀个新的唯⼀标⽰符。如果你希望存储这个标⽰符,那么需要⾃⼰将其存储到NSUserDefaults, Keychain, Pasteboard或其它地⽅。⽬前⼤部分应⽤存的是UUID,它是苹果再iOS6后提供的⼀个获取⼤随机数的⽅法。UUID, 全球独⽴标
识(Globally Unique Identifier),据wiki说UUID随机数算法得到的数重复概率为170亿分之⼀,170亿分之⼀什么概念?可以告诉你买⼀注双⾊球的中奖概率是1700万分之⼀。
1.CFUUID
从iOS2.0开始,CFUUID就已经出现了。它是CoreFoundatio包的⼀部分,因此API属于C语⾔风格。CFUUIDCreate ⽅法⽤来创建CFUUIDRef,并且可以获得⼀个相应的NSString,如下代码
CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
NSString *cfuuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
获得的这个CFUUID值系统并没有存储。每次调⽤CFUUIDCreate,系统都会返回⼀个新的唯⼀标⽰符。如果你希望存储这个标⽰符,那么需要⾃⼰将其存储到NSUserDefaults, Keychain, Pasteboard或其它地⽅。
⽰例:68753A44-4D6F-1226-9C60-0050E4C00067
2.NSUUID
的性质
NSUUID在iOS 6中才出现,这跟CFUUID⼏乎完全⼀样,只不过它是Objective-C接⼝。+ (id)UUID 是⼀个类⽅法,调⽤该⽅法可以获得⼀个UUID。通过下⾯的代码可以获得⼀个UUID字符串:
NSString *uuid = [[NSUUID UUID] UUIDString];
跟CFUUID⼀样,这个值系统也不会存储,每次调⽤的时候都会获得⼀个新的唯⼀标⽰符。如果要存储的话,你需要⾃⼰存储。在我读取NSUUID时,注意到获取到的这个值跟CFUUID完全⼀样(不过也可能不⼀样)
⽰例:68753A44-4D6F-1226-9C60-0050E4C00067
三.⼴告标⽰符(IDFA-identifierForIdentifier)
⼴告标⽰符,在同⼀个设备上的所有App都会取到相同的值,是苹果专门给各⼴告提供商⽤来追踪⽤户⽽设的。但好在Apple默认是允许追踪的,⽽且⼀般⽤户都不知道有这么个设置,所以基本上⽤来监测推⼴效果,是戳戳有余了。
它是iOS 6中另外⼀个新的⽅法,提供了⼀个⽅法advertisingIdentifier,通过调⽤该⽅法会返回⼀个NSUUID实例,最后可以获得⼀个UUID,由系统存储着的。
#import <AdSupport/AdSupport.h>
NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
不过即使这是由系统存储的,但是有⼏种情况下,会重新⽣成⼴告标⽰符。如果⽤户完全重置系统((设置程序 -> 通⽤ -> 还原 -> 还原位置与隐私) ,这个⼴告标⽰符会重新⽣成。另外如果⽤户明确的还原⼴告(设置程序-> 通⽤ -> 关于本机 -> ⼴告 -> 还原⼴告标⽰符) ,那么⼴告标⽰符也会重新⽣成。
关于⼴告标⽰符的还原,有⼀点需要注意:如果程序在后台运⾏,此时⽤户“还原⼴告标⽰符”,然后再回到程序中,此时获取⼴ 告标⽰符并不会⽴即获得还原后的标⽰符。必须要终⽌程序,然后再重新启动程序,才能获得还原后的⼴告标⽰符。
所以IDFA也不可以作为获取唯⼀标识的⽅法,来识别⽤户。
注意:Appstore禁⽌不使⽤⼴告⽽采集IDFA的app上架。
四.Vendor标⽰符 (IDFV-identifierForVendor)
Vendor标⽰符,是给Vendor标识⽤户⽤的,每个设备在所属同⼀个Vender的应⽤⾥,都有相同的值。其中的Vender是指应⽤提供商,但准确点说,是通过BundleID的反转的前两部分进⾏匹配,如果相同就是同⼀个Vender,例如对于com.taobao.app1,
com.taobao.app2 这两个BundleID来说,就属于同⼀个Vender,共享同⼀个IDFV的值。和IDFA不同的是,IDFV的值是⼀定能取到的,所以⾮常适合于作为内部⽤户⾏为分析的主id,来标识⽤户,替代OpenUDID。
钻头尺寸规格它是iOS 6中新增的,跟advertisingIdentifier⼀样,该⽅法返回的是⼀个 NSUUID对象,可以获得⼀个UUID。如果满⾜条件“相同的⼀个程序⾥⾯-相同的vendor-相同的设备”,那么获取到的这个属性值就不会变。如果是“相同的程序-相同的设备-不同的vendor,或者是相同的程序-不同的设备-⽆论是否相同的vendor”这样的情况,那么这个值是不会相同的。
NSString *strIDFV = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
但是如果⽤户将属于此Vender的所有App卸载,则IDFV的值会被重置,即再重装此Vender的App,IDFV的值和之前不同。
五.IMEI,IMSI
IMEI(International Mobile Equipment Identity)是国际移动设备⾝份码的缩写,国际移动装备辨识码,是由15位数字组成的”电⼦串号”,它与每台⼿机⼀⼀对应,⽽且该码是全世界唯⼀的。每⼀部⼿机在组装完成后都将被赋予⼀个全球唯⼀的⼀组号码,这个号码从⽣产到交付使⽤都将被制造⽣产的⼚商
所记录。⼿机⽤户可以在⼿机中查到⾃⼰⼿机的IMEI码。重点来了!iOS5以后不能再获取了,但通过私有Api能获取,这是在⽹上能查到的。Git上的erica的UIDevice扩展⽂件,以前可⽤但由于IOKit framework没有公开,所以也⽆法使⽤。就算⼿动导⼊,依旧⽆法使⽤,看来获取IMEI要失败了,同时失败的还有IMSI。不过还存在另外⼀种可能,Stack Overflow上有⼈提供采⽤ entitlement⽅法,but device must be jailbroken;在此附上链接,供⼤家参考:如果实现了,⾃⼰拿来玩就⾏,别上架,这是会被拒掉的。
六.MAC Address
1.这个MAC地址是指什么?有什么⽤?
MAC(Medium/Media Access Control)地址,⽤来表⽰互联⽹上每⼀个站点的标识符,采⽤⼗六进制数表⽰,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构 RA负责给不同⼚家分配的代码(⾼位24位),也称为“编制上唯⼀的标识符” (Organizationally Unique Identifier),后三个字节(低位24位)由各⼚家⾃⾏指派给⽣产的适配器接⼝,称为扩展标识符(唯⼀性)。
MAC地址在⽹络上⽤来区分设备的唯⼀性,接⼊⽹络的设备都有⼀个MAC地址,他们肯定都是不同的,是唯⼀的。⼀部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有⼀个WIFI的,因此只需获取WIFI的MAC地址就好了,也就是en0的地址。
形象的说,MAC地址就如同我们⾝份证上的⾝份证号码,具有全球唯⼀性。这样就可以⾮常好的标识设备唯⼀性,类似与苹果设备的UDID 号,通常的⽤途有:
1)⽤于⼀些统计与分析⽬的,利⽤⽤户的操作习惯和数据更好的规划产品;
2)作为⽤户ID来唯⼀识别⽤户,可以⽤游客⾝份使⽤app⼜能在服务器端保存相应的信息,省去⽤户名、密码等注册过程。
2.如何使⽤Mac地址⽣成设备的唯⼀标识呢?
主要分三种:
1、直接使⽤“MAC Address”
2、使⽤“MD5(MAC Address)”
3、使⽤“MD5(Mac Address+bundle_id)”获得“机器+应⽤”的唯⼀标识(bundle_id 是应⽤的唯⼀标识)
iOS7之前,因为Mac地址是唯⼀的, ⼀般app开发者会采取第3种⽅式来识别安装对应app的设备。为
什么会使⽤它?在iOS5之前,都是使⽤UDID的,后来被禁⽤。苹果推荐使⽤UUID 但是也有诸多问题,从⽽使⽤MAC地址。⽽MAC地址跟UDID⼀样,存在隐私问题,现在苹果新发布的iOS7上,如果请求Mac地址都会返回⼀个固定值,那么Mac Address+bundle_id这个值⼤家的设备都变成⼀致的啦,跟UDID⼀样相当于被禁⽤, 所以Mac Address 是不能够被使⽤为获取设备唯⼀标识的。
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
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("Could not allocate memory. error!\n");
return NULL;
}
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
printf("Error: sysctl, take 2");
free(buf);
return NULL;
}
玩命关头3东京甩尾ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl);
NSString *macStr = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",*ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
技术创新管理free(buf);
七.open UDID
在iOS 5发布时,uniqueIdentifier被弃⽤了,这引起了⼴⼤开发者需要寻⼀个可以替代UDID,并且不受苹果控制的⽅案。由此成为了当时使⽤最⼴泛的开源UDID替代⽅案。OpenUDID在⼯程中实现起来⾮常简单,并且还⽀持⼀系列的⼴告提供商。
OpenUDID利⽤了⼀个⾮常巧妙的⽅法在不同程序间存储标⽰符 — 在粘贴板中⽤了⼀个特殊的名称来存储标⽰符。通过这种⽅法,别的程序(同样使⽤了OpenUDID)知道去什么地⽅获取已经⽣成的标⽰符(⽽不⽤再⽣成⼀个新的)。⽽且根据贡献者的代码和⽅法,和⼀些开发者的经验,如果把使⽤了OpenUDID⽅案的应⽤全部都删除,再重新获取OpenUDID,此时的OpenUDID就跟以前的不⼀样。可见,这种⽅法还是不保险。
但是OpenUDID库早已经弃⽤了, 在其中也指明了, 停⽌维护OpenUDID的原因是为了更好的向苹果的举措靠拢, 还指明了MAC Address不是⼀个好的选择。
总结
说了这么多, 才发现原来没有⼀种⽅法是可⾏的。没错, 其实⾃从苹果废除UDID后, 就不能达到获取设备真正的唯⼀标识了。因为这些⽅法中导致获取的唯⼀标⽰产⽣改变的原因, 或是重新调⽤⽅法, 或是重启设备, 或是卸载应⽤, 或是还原某些标识, 或者刷新系统…
所以, 不能达到从根本上获取唯⼀标识, 我们只能做到尽可能接近。下⾯是我⽤过的⽅法。
如何正确的获取设备的唯⼀标识
我⽤的⽅法是将获取的UUID永久存储在设备的KeyChain中, 这个⽅法在应⽤第⼀次启动时, 将获取的
UUID存储进KeyChain中, 每次取的时候, 检查本地钥匙串中有没有, 如果没有则需要将获取的UUID存储进去。当你重启设备, 卸载应⽤再次安装,都不影响, 只是当设备刷机时, KeyChain会清空, 才会消失, 才会失效。
不只是这⼀种⽅法, 你也可以保存除UUID之外,其他合适的标识, 但利⽤KeyChain去存储标识的⽅式应该是最接近的。
利⽤keyChain和UUID永久获得设备的唯⼀标识
开发者可以在应⽤第⼀次启动时调⽤⼀次,然后将该串存储起来,以便以后替代UDID来使⽤。但是,如果⽤户删除该应⽤再次安装时,⼜会⽣成新的字符串,所以不能保证唯⼀识别该设备。这就需要各路⾼⼿想出各种解决⽅案。所以,之前很多应⽤就采⽤MAC Address。但是现在如果⽤户升级到iOS7(及其以后的苹果系统)后,他们机⼦的MAC Address就是⼀样的,没办法做区分,只能弃⽤此⽅法,重新使⽤UUID来标识。如果使⽤UUID,就要考虑应⽤被删除后再重新安装时的处理。
什么是钥匙串?
⼀、在应⽤间利⽤KeyChain共享数据
我们可以把KeyChain理解为⼀个Dictionary,所有数据都以key-value的形式存储,可以对这个Diction
ary进⾏add、update、get、delete这四个操作。对于每⼀个应⽤来说,KeyChain都有两个访问区,私有区和公共区。私有区是⼀个sandbox,本程序存储的任何数据都对其他程序不可见。⽽要想在将存储的内容放在公共区,需要先声明公共区的名称,官⽅⽂档管这个名称叫“keychain access group”,声明的⽅法是新建⼀个plist⽂件,名字随便起,内容如下
“urCompany.whatever”就是你要起的公共区名称,除了whatever字段可以随便定之外,其他的都必须如实填写。这个⽂件的路径要配置在 Project->build setting->Code Signing Entitlements⾥,否则公共区⽆效,配置好后,须⽤你正式的证书签名编译才可通过,否则xcode会弹框告诉你code signing有问题。所以,苹果限制了你只能同公司的产品共享KeyChain数据,别的公司访问不了你公司产品的KeyChain。
⼆、保存私密信息
iOS的keychain服务提供了⼀种安全的保存私密信息(密码,序列号,证书等)的⽅式,每个ios程序都有⼀个独⽴的keychain存储。相对于NSUserDefaults、⽂件保存等⼀般⽅式,keychain保存更为安全,⽽且keychain⾥保存的信息不会因App被删除⽽丢失,所以在重装App后,keychain⾥的数据还能使⽤。
实现代码
⾸先, 我先推荐两篇⽂章,⾥⾯介绍了如利⽤keyChain和UUID永久获得设备的唯⼀标识, 和  。
然后, 再介绍下我使⽤的⽅法以及封装的⼯具类, 在应⽤⾥使⽤使⽤keyChain,我们需要导⼊Security.framework。下⾯介绍下, 我在其他库基础上封装的⼀个获取唯⼀标识的⼯具类:

本文发布于:2024-09-22 14:34:00,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/15226.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:设备   获取   苹果   程序   标识   数据
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议