首先,我承认我骗人了,目前iOS已经无法再获取UDID了,没有办法做到唯一标识一个设备了。目前有一些替代的方案,我在这里将一个我认为最优的写在这里,欢迎大家指正。

首先介绍几个知识点:

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或其它地方。

2、NSUUID

NSUUID在iOS 6中才出现,这跟CFUUID几乎完全一样,只不过它是Objective-C接口。+ (id)UUID 是一个类方法,调用该方法可以获得一个UUID。通过下面的代码可以获得一个UUID字符串:

NSString *uuid = [[NSUUID UUID] UUIDString];

跟CFUUID一样,这个值系统也不会存储,每次调用的时候都会获得一个新的唯一标示符。如果要存储的话,你需要自己存储。

3、IDFA(广告标示符)

这是iOS 6中另外一个新的方法,advertisingIdentifier是新框架AdSupport.framework的一部分。ASIdentifierManager单例提供了一个方法advertisingIdentifier,通过调用该方法会返回一个上面提到的NSUUID实例。

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

广告标示符是由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。之所以会这样,我猜测是由于ASIdentifierManager是一个单例。

4、IDFV(Vindor标示符)

这种叫法也是在iOS 6中新增的,不过获取这个IDFV的新方法被添加在已有的UIDevice类中。跟advertisingIdentifier一样,该方法返回的是一个NSUUID对象。

NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];

苹果官方的文档中对identifierForVendor有如下这样的一段描述 :

The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.

如果满足这样的条件,那么获取到的这个属性值就不会变:相同的一个程序里面-相同的vindor-相同的设备。如果是这样的情况,那么这个值是不会相同的:相同的程序-相同的设备-不同的vindor,或者是相同的程序-不同的设备-无论是否相同的vindor。

看完上面的内容,我有这样的一个疑问“vendor是什么”。我首先想到的是苹果开发者账号。但事实证明这是错误的。接着我想可能是有一个AppIdentifierPrefix东西,跟钥匙串访问一样,可以在多个程序间共享。同样,这个想法也是的。最后证明,vendor非常简单:一个Vendor是CFBundleIdentifier(反转DNS格式)的前两部分。例如,com.doubleencore.app1 和 com.doubleencore.app2 得到的identifierForVendor是相同的,因为它们的CFBundleIdentifier 前两部分是相同的。不过这样获得的identifierForVendor则完全不同:com.massivelyoverrated 或 net.doubleencore。

在这里,还需要注意的一点就是:如果用户卸载了同一个vendor对应的所有程序,然后在重新安装同一个vendor提供的程序,此时identifierForVendor会被重置。

5、UDID 设备唯一标识(已被禁)

在之前的版本中是可用的,但是在iOS5以及之后的版本中,以及被弃用了。虽然,这个UDID用得很广泛,但是,不得不说的是,它在慢慢的远离开发者,不能在考虑使用UDID了。至于这个标示符是转为私有方法,或者完全从以后的iOS版本中移除,还有待观察。不过,这个UDID在部署企业级签名程序时,非常方便。获取UDID的方法如下:

NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];


6、OpenUDID

在iOS 5发布时,uniqueIdentifier被弃用了,这引起了广大开发者需要寻找一个可以替代UDID,并且不受苹果控制的方案。由此 OpenUDID成为了当时使用最广泛的开源UDID替代方案。OpenUDID在工程中实现起来非常简单,并且还支持一系列的广告提供商。

NSString *openUDID = [OpenUDID value];

OpenUDID利用了一个非常巧妙的方法在不同程序间存储标示符 — 在粘贴板中用了一个特殊的名称来存储标示符。通过这种方法,别的程序(同样使用了OpenUDID)知道去什么地方获取已经生成的标示符(而不用再生成一个新的)。是不是感觉这个就是你想要的,但是,UIPasteboard由共享变为沙盒化了,只对相同的app group可见。所以现在OpenUDID基本只能保证同一个APP的openUDID一样了

7、UIPasteboard 剪切板

可以自定义APP的剪切板

8、Keychain 钥匙串

我们可以把KeyChain理解为一个Dictionary,所有数据都以key-value的形式存储,可以对这个Dictionary进行add、update、get、delete这四个操作。对于每一个应用来说,KeyChain都有两个访问区,私有区和公共区。私有区是一个sandbox,本程序存储的任何数据都对其他程序不可见。而要想在将存储的内容放在公共区,需要先声明公共区的名称,官方文档管这个名称叫“keychain access group”。现在用Xcode很方便可以配置。但是公共区也是相同的app group才可以共享。操作keychain,推荐使用SSKeychain:https://github.com/soffes/sskeychain。keychain默认是不同步到iCloud上的,除非该item设置了key:kSecAttrSynchronizable。

下面正餐来了:

获取流程:

1、其中主要是使用钥匙串中的UUID,剪切板和userDefaults都是为了备份UUID,以防止钥匙串中信息失效。

2、生成UUID的顺序是IDFA -> IDFV -> 获取UUID。原因是IDFA如果有的话是设备唯一(除非还原),IDFV是同一个vendor一样,尽量使用作用域比较大的值作为唯一标示。

下面不说废话,直接上代码:

代码实现

//
//  DLUDID.m
//  DLUDID
//
//  Created by zhangdali on 16/5/5.
//  Copyright © 2016年 zhangdali. All rights reserved.
//#import "DLUDID.h"
#import <UIKit/UIDevice.h>
#import <UIKit/UIPasteboard.h>
#import "SSKeychain.h"#define kUDIDService @"com.dali.udid"
#define kUDIDKey @"com.dali.udid"#define DL_IS_STR_NIL(objStr) (![objStr isKindOfClass:[NSString class]] || objStr == nil || [objStr length] <= 0)static NSString *_udid;@implementation DLUDID#pragma mark - generate UUID
/***  get IDFA**  @return IDFA*/
+ (NSString *)appleIDFA {NSString *idfa = nil;Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager");if (ASIdentifierManagerClass) { // a dynamic way of checking if AdSupport.framework is availableSEL sharedManagerSelector = NSSelectorFromString(@"sharedManager");id sharedManager = ((id (*)(id, SEL))[ASIdentifierManagerClass methodForSelector:sharedManagerSelector])(ASIdentifierManagerClass, sharedManagerSelector);SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier");NSUUID *advertisingIdentifier = ((NSUUID* (*)(id, SEL))[sharedManager methodForSelector:advertisingIdentifierSelector])(sharedManager, advertisingIdentifierSelector);idfa = [advertisingIdentifier UUIDString];}return idfa;
}/***  get IDFV**  @return IDFV*/
+ (NSString *)appleIDFV {if(NSClassFromString(@"UIDevice") && [UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) {// only available in iOS >= 6.0return [[UIDevice currentDevice].identifierForVendor UUIDString];}return nil;
}/***  get UDID**  @return UDID*/
+ (NSString *)randomUDID {if(NSClassFromString(@"NSUUID")) { // only available in iOS >= 6.0return [[NSUUID UUID] UUIDString];}CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);CFStringRef cfuuid = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);CFRelease(uuidRef);NSString *uuid = [((__bridge NSString *) cfuuid) copy];CFRelease(cfuuid);return uuid;
}#pragma mark - keychain/***  get UDID in keychain**  @return UDID*/
+ (NSString *)UDIDInKeychain {return [SSKeychain passwordForService:kUDIDService account:kUDIDKey];
}/***  save UDID to keychain**  @param udid*/
+ (void)saveUDIDToKeychain:(NSString *)udid {[SSKeychain setPassword:udid forService:kUDIDService account:kUDIDKey];
}#pragma mark - UIPasteboard
/***  get UDID in pasteboard**  @return UDID*/
+ (NSString *)UDIDInPasteboard {UIPasteboard *pb = [UIPasteboard pasteboardWithName:kUDIDService create:NO];if (!pb) {return nil;}id data = [pb dataForPasteboardType:kUDIDKey];NSString *udid = nil;if (data) {udid = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];}return udid;
}/***  save UDID to pasteboard**  @param udid*/
+ (void)saveUDIDToPasteboard:(NSString *)udid {UIPasteboard *pb = [UIPasteboard pasteboardWithName:kUDIDService create:YES];[pb setPersistent:YES];NSData *data = [udid dataUsingEncoding:NSUTF8StringEncoding];[pb setData:data forPasteboardType:kUDIDKey];
}#pragma mark - NSUserDefaults
/***  get UDID in NSUserDefaults**  @return UDID*/
+ (NSString *)UDIDInUserDefaults {return [[NSUserDefaults standardUserDefaults] objectForKey:kUDIDKey];
}/***  save UDID to NSUserDefaults**  @param udid*/
+ (void)saveUDIDToUserDefaults:(NSString *)udid {[[NSUserDefaults standardUserDefaults] setObject:udid forKey:kUDIDKey];[[NSUserDefaults standardUserDefaults] synchronize];
}/***  save UDID to cache: keychain, pasteboard, userDefaults*/
+ (void)save:(NSString *)udid {if (DL_IS_STR_NIL(udid)){return;}[[self class] saveUDIDToKeychain:udid];[[self class] saveUDIDToPasteboard:udid];[[self class] saveUDIDToUserDefaults:udid];
}/***  get UDID**  @return UDID*/
+ (NSString *)value {// get exists valueif (DL_IS_STR_NIL(_udid)) _udid = [[self class] UDIDInKeychain];if (DL_IS_STR_NIL(_udid)) _udid = [[self class] UDIDInPasteboard];if (DL_IS_STR_NIL(_udid)) _udid = [[self class] UDIDInUserDefaults];// generate new valueif (DL_IS_STR_NIL(_udid)) _udid = [[self class] appleIDFA];if (DL_IS_STR_NIL(_udid)) _udid = [[self class] appleIDFV];if (DL_IS_STR_NIL(_udid)) _udid = [[self class] randomUDID];// 去掉字符中的'-'_udid = [_udid stringByReplacingOccurrencesOfString:@"-" withString:@""];[[self class] save:_udid];return _udid;
}@end

完整demo地址:

https://github.com/DaliZh/DLUDID

参考了两个比较好的网站:

https://blog.onliquid.com/persistent-device-unique-identifier-ios-keychain/

http://www.cocoachina.com/industry/20130422/6040.html

iOS获取UDID问题相关推荐

  1. iOS获取UDID的方法

    办公远程添加设备,每次被问怎么获取UDID,就写了篇文章: 方法一: 1.打开"音乐App",如下图 2. 点击红色框内 3.出现UDID,就是他 方法二: 1.打开xcode,如 ...

  2. IOS获取UDID添加到开发者账号用来安装测试包

    1.查询设备的UDID 先展示出来的是序列号,点击序列号切换到UDID,右击复制 或者去蒲公英查看 ​​​​​​蒲公英 | 一步快速获取 iOS 设备的UDID 然后登陆开发者账号 选择[Certif ...

  3. 通过Safari浏览器获取iOS设备UDID(设备唯一标识符)

    通过Safari与mobileconfig获取iOS设备UDID(设备唯一标识符) 科普:U D I D (Unique Device Identifier),唯一标示符,是iOS设备的一个唯一识别码 ...

  4. iOS系统 查看设备序列号 获取UDID

    iOS系统的设备标识即UDID,长度为40位,如:85f3c1bcb9ca8ad8b2931219072cf05382a6da09 获取UDID,可以使用手机端访问UDID查询网站在线查询,也可以通过 ...

  5. iOS - 获取设备标识符UUID/UDID/IMEI等

    关于获取设备各种标识符,最近整理了一下.基本上有IDFA.IDFV.IMEI.IMSI.UUID.UDID.MAC地址; 想要获取系统唯一标识符的话,比如说不管用户卸载还是重新安装都可以唯一标识的可以 ...

  6. 通过Safari与mobileconfig获取iOS设备UDID(设备唯一标识符)

    本文基于在线安装Profile来实现获取UDID. 先看下效果,真机打开 获取设备UDID 科普 UDID UDID (Unique Device Identifier),唯一标示符,是iOS设备的一 ...

  7. iOS获取设备UDID/IMEI信息

    标题iOS获取设备UDID/IMEI信息 通过Safari与mobileconfig获取iOS设备UDID UDID (Unique Device Identifier),唯一标示符,是iOS设备的一 ...

  8. Mac机获取IOS手机udid

    mac获取ios手机的udid 命令:idevice_id -l mac获取Android手机的udid 命令:adb deivces 查看 iOS 模拟器 udid命令: xcrun simctl ...

  9. iOS获取设备唯一标识的各种方法?IDFA、IDFV、UDID分别是什么含义?

    http://www.ithao123.cn/content-8688001.html iOS获取设备唯一标识的各种方法?IDFA.IDFV.UDID分别是什么含义? [摘要:1.UDID (Uniq ...

最新文章

  1. [matlab]Monte Carlo模拟学习笔记
  2. 80 年代以来的操作系统 GUI 设计进化史
  3. windows7 删除hiberfil.sys文件的方法
  4. RDMBorderedButton
  5. flex 实现图片播放 方案二 把临时3张图片预加载放入内存
  6. idea增强for循环
  7. matlab函数grid,Matlab基本函数-grid、box函数
  8. 游戏运营的工作中是做什么
  9. P2339 [USACO04OPEN]Turning in Homework G 笔记/题解
  10. 2013年,移动互联网行业技术趋势前瞻
  11. vue实现websoket即时通讯
  12. 双目视觉三维重建框架
  13. matlab 群延迟,实现最小相位群延迟的音节切分算法的一些问题
  14. 前端安全系列(一):如何防止XSS攻击?
  15. Android 程序锁
  16. Python卸载时提示发生严重错误!
  17. springboot基础框架搭建
  18. VHDL实现与门,或门,非门。
  19. Android V1及V2签名原理简析
  20. IOS 集成讯飞语音唤醒+语音识别,实现语音控制效果

热门文章

  1. 如何使用Axure快速制作有趣好看的数据可
  2. 【状态估计】无迹卡尔曼滤波(UKF)应用于FitzHugh-Nagumo神经元动力学研究(Matlab代码实现)
  3. Java——九九乘法表
  4. java 段子_那些关于程序员的段子
  5. Linux菜鸟笔记【基本命令汇总】
  6. 这道题该怎么做,指点指点,教教代码
  7. 如何在blender粒子系统随机散布树
  8. 【微信小程序】预览视频
  9. 【学习笔记】Visual Cortex of Human‘s Brain
  10. leetcode554、砖墙