对IOS设备中UDID的一些思考-程序员宅基地

技术标签: 操作系统  移动开发  

本文转载至 http://blog.csdn.net/happyrabbit456/article/details/11565209 

http://blog.csdn.net/xiaoguan2008一家之言,难免存在纰漏,欢迎指正,勿吐槽。

        UDID是什么?
        UDID的全称是Unique Device Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成。

        UDID有什么用?
        移动网络可利用UDID来识别移动设备,如iPhone和iPad。UDID对每台设备而言都是唯一的,从而成为了广告公司、市场分析机构和APP测试系统跟踪用户行为的实用工具。

        目前使用UDID主要原因分为:
                1)用于统计与分析,例如第三方统计工具Flurry、友盟等,广告商ADMOB等;
                2)将UDID作为用户ID来唯一识别用户,省去用户名,密码等注册过程。

        由此可见UDID对于IOS应用开发者说,是个很重要的信息(虽然越狱的设备通过某些工具可以改变设备的UDID)。但是,从IOS5.0开始,苹果宣布将不再支持用以下方法获取设备的UDID。

[cpp]  view plain copy
 
  1. [UIDevice currentDevice] uniqueIdentifier];  

        最近又爆出苹果App Store禁止访问UDID的应用上架,所以开发者应尽快弃用UDID,去寻找另外的替代方案。

        我为此也花了不少时间去寻找比较好的替代方案,下面一一道来:
        一、苹果公司建议的UUID替代方案
[cpp]  view plain copy
 
  1. -(NSString*) uuid {    
  2.     CFUUIDRef puuid = CFUUIDCreate( nil );    
  3.     CFStringRef uuidString = CFUUIDCreateString( nil, puuid );    
  4.     NSString * result = (NSString *)CFStringCreateCopy( NULL, uuidString);    
  5.     CFRelease(puuid);    
  6.     CFRelease(uuidString);    
  7.     return [result autorelease];    
  8. }  
        苹果公司建议采用上述代码为应用生成唯一标识字符串。开发者可以在应用第一次启动时调用一次,然后将该串存储起来,以便以后替代UDID来使用。显而易见,这种方法问题很多。如果用户删除该应用再次安装时,又会生成新的字符串,所以不能保证唯一识别该设备;如果你从一台旧设备中备份文件到新设备中,两台设备就拥有相同的CFUUID;如果你从临时文件中备份操作系统,就会出现一个设备里存在不同CFUUID的情况。

        二、开源方案 OpenUDID
        贡献者在readme文档中说:
        OpenUDID is a drop-in replacement for the deprecated [UIDevice uniqueIdentifier] a.k.a. UDID on iOS, and otherwise is an industry-friendly equivalent for iOS and Android.
        The agenda for this community driven project is to: - Provide a reliable proxy and replacement for a universal unique device identifier. That is, persistent and sufficiently unique, on a per device basis. - NOT use an obvious other sensitive unique identifier (like the MAC address) to avoid further deprecation and to protect device-level privacy concerns - Enable the same OpenUDID to be accessed by any app on the same device - Supply open-source code to generate and access the OpenUDID, for iOS and Android - Incorporate, from the beginning, a system that will enable user opt-out to match Apple’s initial intent.
        愿景很好,也确实没有用到MAC地址,同时能保证同一台设备上的不同应用使用同一个OpenUDID。但是仔细分析,还是能发现问题。

        OpenUDID生成唯一识别码的代码是:

[cpp]  view plain copy
 
  1. unsigned char result[16];  
  2. const char *cStr = [[[NSProcessInfo processInfo] globallyUniqueString] UTF8String];  
  3. CC_MD5( cStr, strlen(cStr), result );  
  4. _openUDID = [NSStringstringWithFormat:  
  5.             @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08x",  
  6.             result[0], result[1], result[2], result[3],   
  7.             result[4], result[5], result[6], result[7],  
  8.             result[8], result[9], result[10], result[11],  
  9.             result[12], result[13], result[14], result[15],  
  10.             arc4random() % 4294967295];  
        这里使用了NSProcessInfo类。
        当设备上第一个使用OpenUDID解决方案的应用第一次调用时,确实会生成一个唯一的识别码。同时,为了与官方的UDID位数相同,还在MD5值后面追加了8位随机码。然后,该方案使用到了NSUserDefaults类(应用设置)。应用将获取到的唯一识别码保存到应用的UserDefaults中,如果程序以后需要使用唯一识别码,就从UserDefaults中获取,这样就保证可以拿到同一个识别码。但是,如果用户删除了应用,UserDefaults同样会被清空,为了避免重新生成唯一识别码,该方案还使用到了UIPasteboard类(设备剪切板)。应用在将唯一识别码保存到UserDefaults的同时,也会将其保存到以特殊的key标识的UIPasteboard中。代码如:
[cpp]  view plain copy
 
  1. UIPasteboard* slotPB = [UIPasteboardpasteboardWithName:availableSlotPBid create:YES];      
  2. [slotPB setData:[NSKeyedArchiver archivedDataWithRootObject:dict] forPasteboardType:kOpenUDIDDomain];  
        其中availableSlotPBid是一个字符串key,前缀是“org.OpenUDID.slot.”,点后面加上数字。这个数字默认是从0到99(当然你可以修改源代码使它更大或者更小)。
如果设备上安装了第二个使用OpenUDID解决方案的应用,当应用调用生成OpenUDID的方法时,将会从UIPasteboard中获取唯一识别码(遍历key从0到99的UIPasteboard),这里取到的就是之前第一个应用保存到UIPasteboard中的。也就是说,只要用户设备上有一个使用了OpenUDID的应用存在时,其他后续安装的应用如果获取OpenUDID,都将会获得第一个应用生成的那个。
        看起来似乎很好,很复杂。但是仔细想想,还是有问题,如果把使用了OpenUDID方案的应用全部都删除,再重新获取OpenUDID,此时的OpenUDID就跟以前的不一样了(本人测了一下,确实如此)。可见,这种方法还是不保险。
     

        三、开源方案SecureUDID

        稍微看了下SecureUDID源码,发现其与OpenUDID其实差不多,只是初始获取的唯一识别码稍有不同。同时,从作者的Readme文档中可见,这个方案同样存在很多问题。如原文:
        Is this a true UDID replacement?
        SecureUDID has two properties that you should know about before you use it. First, as indicated above, the identifier is not derived from hardware attributes. Second, the persistence of an identifier cannot be guaranteed in all situations. This means that, while unlikely, it is technically possible for two distinct devices to report the same identifier, and for the same device to report different identifiers. Consider this carefully in your application. Here is a list of situations where this identifier will not exhibit the uniqueness/persistence of a traditional UDID.
        * The user has opted-out of the SecureUDID system, in which case you will receive a well-formed string of zeroes.
        * Device A is backed up and then restored to Device B, which is an identical model. This is common when someone breaks their phone, for example, and is likely desirable: you will receive Device A's SecureUDID.
        * The SecureUDID data is removed, via user intervention, UIPasteboard data purge, or by a malicious application.
        * The SecureUDID backing store becomes corrupt.
        * All SecureUDID applications are uninstalled from a device, followed by a UIPasteboard data purge.
        我发现,其实前面的OpenUDID也基本存在以上问题,只是作者没写出来。看来还是SecureUDID的贡献者比较厚道。

        四、与WIFI MAC地址相关
        网上同样有一些与WIFI MAC地址相关的替代方案,主要分三种:第一种直接使用“MAC Address”;第二种,使用“MD5(MAC Address)”;第三种,“MD5(MAC Address+CFBundleIdentifier)”。github上有个开源项目(UIDevice-with-UniqueIdentifier-for-iOS-5)实现了这几种方法。
        使用这种方法也存在问题:1、市面上有部分机器(虽然数量极少,但是本人在使用过程中确实发现过这种情况)无法获得MAC地址,有人说这部分机器是联通阉割无WIFI版的,具体不得而知了。2、MAC地址跟UDID一样,存在隐私问题。苹果现在禁用UDID,不能保证以后不会禁用MAC地址。

        五、部分大公司私有的解决方案,但是他们怎么会告诉你呢?

        所以,如果你想以一种万无一失的方法追踪某台设备,现在还没有比UDID更合适的选择。但是,苹果现在不让用了,苦逼的开发者们,该怎么办呢?

 

参考:

http://www.cnblogs.com/zhulin/archive/2012/03/26/2417860.html

http://www.iteye.com/news/24661

转载于:https://www.cnblogs.com/Camier-myNiuer/p/3472497.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30911451/article/details/98713253

智能推荐

基于51单片机的简易计算器,用LCD1602显示_c51让1602显示数字的代码-程序员宅基地

文章浏览阅读7.3k次,点赞27次,收藏121次。基于51单片机的简易计算器经历了一番学习,成功做出了一个简易的计算器,并且在程序开头加了一个小密码。我用的单片机是STC89C52,单片机类型不同,电路图也是不一样的。一.设计思路1.1LCD1602的电路图该芯片引脚,sbit RS = P3^5; //液晶引脚定义sbit RW = P3^6;sbit EN = P3^4;#1.2主函数思路主函数的思路图:1.3主函数..._c51让1602显示数字的代码

python生成随机imei_imei码 python-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏4次。原理:代码import randomdef get_random_imei(): # 定义一个长度为14字符类的数字 num = str(random.randint(10000000000000, 99999999999999)) # 计算最后一位校验值 num_list = list(num) # 数字和 math_sum = 0 for i in range(1, len(num_list)+1): # ..._imei码 python

Pepper机器人的背后,孙正义的情怀和梦想-程序员宅基地

文章浏览阅读103次。奥尔德巴伦机器人研究公司潜心两年终于秘密研发成功类人型机器人 Pepper,现如今日本电信巨头软银公司准备在明年将 Pepper 卖给日本消费者!Pepper 机器人似乎想博得大家一乐,它问「你是发自内心的微笑吗?」对面的人忍不住乐出声来。Pepper 吊高嗓门又放出一句妙语,「你看看,果不其然吧9Pepper 认为自己不太礼貌,于是乎弯下它的塑料脑袋道歉说,「我是不是对我们的首席执行官做的太过了..._pepper孙正义

libnet使用举例(8)_libnet_dns_type_a-程序员宅基地

文章浏览阅读1.1k次。作者:小四 主页:http://www.nsfocus.com日期:2000-08-02 11:33呼呼,又到了领略C语言编程魅力的时刻,看如下函数原型:int libnet_build_dns ( u_short id, u_short flags, u_short num_q, u_short num_anws_rr, u_short num_aut_libnet_dns_type_a

python虚拟环境安装和使用_在虚拟环境中安装完库该怎么用-程序员宅基地

文章浏览阅读1k次。python虚拟环境的搭建虚拟环境的使用_在虚拟环境中安装完库该怎么用

Qt——鼠标拖动调整窗口大小_qt 拖动窗口,控件可字体可自由调整-程序员宅基地

文章浏览阅读7.6k次。要求:鼠标移到界面边角时,鼠标样式相应地发生改变。实现方法一:重写mouseMoveEvent,如果鼠标没有按下,则根据鼠标在界面上的位置设置鼠标样式,如果鼠标按下,则根据位置判断该怎样调整界面大小,或者是拖动界面。思路如上,实现起来很简单。但是存在一个问题,如果界面中放了一些其它控件,比如listWidget,此时鼠标在界面边缘移动速度稍微快一些,mouseMoveEvent就会_qt 拖动窗口,控件可字体可自由调整

随便推点

java程序员基础面试的56个面试题_java方法可以同时即是static又是synchronized的吗?-程序员宅基地

文章浏览阅读327次。01-101.问题:如果main方法被声明为private会怎样?答案:能正常编译,但运行的时候会提示”main方法不是public的”。2.问题:Java里的传引用和传值的区别是什么?答案:传引用是指传递的是地址而不是值本身,传值则是传递值的一份拷贝。3.问题:如果要重写一个对象的equals方法,还要考虑什么?答案:hashCode。4.问题:Java的”一次编写,..._java方法可以同时即是static又是synchronized的吗?

# MyBatis(技术NeiMu):核心处理层(ResultSetHandler)_mybatis resultsethandler-程序员宅基地

文章浏览阅读1k次。回顾ResultSetHandlerDefaultResultSetHandlerhandlerResultSets方法ResultSet的迭代过程ResultSetWrapper构造方法映射回顾前面我们已经了解了MyBatis的整个初始化过程,与SQL节点的解析与SQL节点的SQL是如何与实参进行绑定起来、如何根据实参进行动态拼接,下面来看一下MyBatis是如何处理结果集的ResultSetHandlerMyBatis会根据SQL映射配置文件中定义的映射规则,比如resultMap标签、res._mybatis resultsethandler

二叉树的前序遍历--非递归解法(简单难度)_二叉树栈非递归遍历思想算法难吗-程序员宅基地

文章浏览阅读198次。目录题目概述(简单难度)思路与代码思路展现代码示例总结题目概述(简单难度)给你二叉树的根节点 root ,返回它节点值的 前序 遍历。示例 1:输入:root = [1,null,2,3]输出:[1,2,3]示例 2:输入:root = []输出:[]示例 3:输入:root = [1]输出:[1]示例 4:输入:root = [1,2]输出:[1,2]示例 5:输入:root = [1,null,2]输出:[1,2]题目链接:点我进入leetcode_二叉树栈非递归遍历思想算法难吗

嵌入式实时操作系统μC/OS-II在STM32处理器移植_stm上可以运行μc/os-ii-程序员宅基地

文章浏览阅读5k次。http://blog.sina.com.cn/s/blog_a79574c6010168rm.html下载代码stm32标准外设库是stm32全系列芯片的外设驱动,有了它可以大大加速我们开发stm32。首先从st公司的网站下载最新的stm32标准外设库,写本文时最新的版本是V3.5.0。解压该zip文件,得到如下文件夹和文件STM32F10x__stm上可以运行μc/os-ii

13.1-全栈Java笔记:打飞机游戏实战项目|AWT|MyGameFrame-程序员宅基地

文章浏览阅读1.2k次。重点内容简介和项目目标 通过游戏项目学习整个Java基础知识体系,我们做了精心的设计,让每一章知识都能获得应用。 比如:多线程用来实现动画效果、容器实现对于多发炮弹的存取和处理、常用类等等的应用。 寓教于乐,让大家迅速入门,更希望通过喜闻乐见的小游戏,让大家爱上编程,爱上“程序员”。老鸟建议 很多朋友会疑惑:“游戏项目,又不能拿到企业面试中,为什么要讲?” 这是一种太过于功利的想法。就像,

magic-api 框架使用-程序员宅基地

文章浏览阅读3k次。概述先说一下为什么选择这个框架,在搬砖过程中百分之八十的代码是增删改查操作,复杂的逻辑只是占了不多部分,这个框架能够使简单增删改查的时间大大减少.magic-api 是一个基于Java的接口快速开发框架,编写接口将通过magic-api提供的UI界面完成,自动映射为HTTP接口,无需定义Controller、Service、Dao、Mapper、XML、VO等Java对象即可完成常见的HTTP API接口开发简单使用引用<dependency> <groupId>org._magic-api

推荐文章

热门文章

相关标签