如何使用KeyChain保存和获取UDID

swift-UDID的代替UUIDKeychain UDID的代替UUID Keychain 立即下载
本文是iOS7系列文章第一篇文章,主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID的问题。并给出一个获取UDID的工具类,使用方便,只需要替换两个地方即可。

 

一、iOS不用版本获取UDID的方法比较

  

  1)iOS 5.0

  iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备的序列号,这个也是目前为止唯一可以确认唯一的标示符。好景不长,因为该唯一标识符与手机一一对应,苹果觉得可能会泄露用户隐私,所以在 iOS 5.0之后该方法就被废弃掉了。

  而且苹果做的更狠,今年5月份以后提交App Store的产品都不允许再用uniqueIdentifier接口,甚至有些朋友因为代码中有UDID还被打回来,看来这条路是被封死了。

 

  2)iOS 6.0

  iOS 6.0系统新增了两个用于替换uniqueIdentifier的接口,分别是:identifierForVendor,advertisingIdentifier。

  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.

The value of this property may be nil if the app is running in the background, before the user has unlocked the device the first time after the device has been restarted. If the value is nil, wait and get the value again later.

The value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them. Therefore, if your app stores the value of this property anywhere, you should gracefully handle situations where the identifier changes.
复制代码

  大概意思就是“同一开发商的APP在指定机器上都会获得同一个ID。当我们删除了某一个设备上某个开发商的所有APP之后,下次获取将会获取到不同的ID。” 也就是说我们通过该接口不能获取用来唯一标识设备的ID,问题总是难不倒聪明的程序员,于是大家想到了使用WiFi的mac地址来取代已经废弃了的uniqueIdentifier方法。具体的方法晚上有很多,大家感兴趣的可以自己找找,这儿提供一个网址: http://stackoverflow.com/questions/677530/how-can-i-programmatically-get-the-mac-address-of-an-iphone

 

  3)iOS 7.0  

  iOS 7中苹果再一次无情的封杀mac地址,使用之前的方法获取到的mac地址全部都变成了02:00:00:00:00:00。有问题总的解决啊,于是四处查资料,终于有了思路是否可以使用KeyChain来保存获取到的唯一标示符呢,这样以后即使APP删了再装回来,也可以从KeyChain中读取回来。有了方向以后就开始做,看关于KeyChain的官方文档,看官方使用KeyChain的Demo,大概花了一下午时间,问题终于解决了。 

 

二、KeyChain介绍

  

   我们搞iOS开发,一定都知道OS X里面的KeyChain(钥匙串),通常要乡镇及调试的话,都得安装证书之类的,这些证书就是保存在KeyChain中,还有我们平时浏览网页记录的账号密码也都是记录在KeyChain中。iOS中的KeyChain相比OS X比较简单,整个系统只有一个KeyChain,每个程序都可以往KeyChain中记录数据,而且只能读取到自己程序记录在KeyChain中的数据。iOS中Security.framework框架提供了四个主要的方法来操作KeyChain:

复制代码
// 查询
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result);

// 添加
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result);

// 更新KeyChain中的Item
OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);

// 删除KeyChain中的Item
OSStatus SecItemDelete(CFDictionaryRef query)
复制代码

  这四个方法参数比较复杂,一旦传错就会导致操作KeyChain失败,这块儿文档中介绍的比较详细,大家可以查查官方文档Keychain Services Reference。

  前面提到了每个APP只允许访问自己在KeyChain中记录的数据,那么是不是就没有别的办法访问其他APP存在KeyChain的数据了?

  苹果提供了一个方法允许同一个发商的多个APP访问各APP之间的途径,即在调SecItemAdd添加数据的时候指定AccessGroup,即访问组。一个APP可以属于同事属于多个分组,添加KeyChain数据访问组需要做一下两件事情:

  a、在APP target的bulibSetting里面设置Code Signing Entitlements,指向包含AceessGroup的分组信息的plist文件。该文件必须和工程文件在同一个目录下,我在添加访问分组的时候就因为plist文件位置问题,操作KeyChain失败,查找这个问题还花了好久的时间。

  b、在工程目录下新建一个KeychainAccessGroups.plist文件,该文件的结构中最顶层的节点必须是一个名为“keychain-access-groups”的Array,并且该Array中每一项都是一个描述分组的NSString。对于String的格式也有相应要求,格式为:"AppIdentifier.com.***",其中APPIdentifier就是你的开发者帐号对应的ID。

  c、在代码中往KeyChain中Add数据的时候,设置kSecAttrAccessGroup,代码如下:

复制代码
   NSString *accessGroup = [NSString stringWithUTF8String:"APPIdentifier.com.cnblogs.smileEvday"];
    if (accessGroup != nil)
    {
#if TARGET_IPHONE_SIMULATOR
        // Ignore the access group if running on the iPhone simulator.
        //
        // Apps that are built for the simulator aren't signed, so there's no keychain access group
        // for the simulator to check. This means that all apps can see all keychain items when run
        // on the simulator.
        //
        // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
        // simulator will return -25243 (errSecNoAccessForItem).
#else
        [dictForQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
    }
复制代码

  这段代码是从官方的Demo中直接拷贝过来的,根据注释我们可以看到,模拟器是不支持AccessGroup的,所以才行了预编译宏来选择性添加。

  注:appIdentifer就是开发者帐号的那一串标识,如下图所示:

   

  打开xcode的Organizer,选择Device选项卡,连接设备就可以看到设备上安装的开发者账号描述文件列表,其中第五列最开始的10个字符即为App Identifier,这块儿前面写的不是很清楚,好多朋友加我qq问我,今天特地补上。

 

三、使用KeyChain保存和获取UDID

  

  说了这么多终于进入正题了,如何在iOS 7上面获取到不变的UDID。我们将第二部分所讲的知识直接应用进来就可以了轻松达到我们要的效果了,下面我们先看看往如何将获取到的identifierForVendor添加到KeyChain中的代码。

复制代码
+ (BOOL)settUDIDToKeyChain:(NSString*)udid
{
    NSMutableDictionary *dictForAdd = [[NSMutableDictionary alloc] init];
    
    [dictForAdd setValue:(id)kSecClassGenericPassword forKey:(id)kSecClass];
    [dictForAdd setValue:[NSString stringWithUTF8String:kKeychainUDIDItemIdentifier] forKey:kSecAttrDescription];
    
    [dictForAdd setValue:@"UUID" forKey:(id)kSecAttrGeneric];
    
    // Default attributes for keychain item.
    [dictForAdd setObject:@"" forKey:(id)kSecAttrAccount];
    [dictForAdd setObject:@"" forKey:(id)kSecAttrLabel];
    
    // The keychain access group attribute determines if this item can be shared
    // amongst multiple apps whose code signing entitlements contain the same keychain access group.
    NSString *accessGroup = [NSString stringWithUTF8String:kKeyChainUDIDAccessGroup];
    if (accessGroup != nil)
    {
#if TARGET_IPHONE_SIMULATOR
        // Ignore the access group if running on the iPhone simulator.
        //
        // Apps that are built for the simulator aren't signed, so there's no keychain access group
        // for the simulator to check. This means that all apps can see all keychain items when run
        // on the simulator.
        //
        // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
        // simulator will return -25243 (errSecNoAccessForItem).
#else
        [dictForAdd setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
    }

    const char *udidStr = [udid UTF8String];
    NSData *keyChainItemValue = [NSData dataWithBytes:udidStr length:strlen(udidStr)];
    [dictForAdd setValue:keyChainItemValue forKey:(id)kSecValueData];
    
    OSStatus writeErr = noErr;
    if ([SvUDIDTools getUDIDFromKeyChain]) {        // there is item in keychain
        [SvUDIDTools updateUDIDInKeyChain:udid];
        [dictForAdd release];
        return YES;
    }
    else {          // add item to keychain
        writeErr = SecItemAdd((CFDictionaryRef)dictForAdd, NULL);
        if (writeErr != errSecSuccess) {
            NSLog(@"Add KeyChain Item Error!!! Error Code:%ld", writeErr);
            
            [dictForAdd release];
            return NO;
        }
        else {
            NSLog(@"Add KeyChain Item Success!!!");
            [dictForAdd release];
            return YES;
        }
    }
    
    [dictForAdd release];
    return NO;
}
复制代码

  上面代码中,首先构建一个要添加到KeyChain中数据的Dictionary,包含一些基本的KeyChain Item的数据类型,描述,访问分组以及最重要的数据等信息,最后通过调用SecItemAdd方法将我们需要保存的UUID保存到KeyChain中。

  获取KeyChain中相应数据的代码如下:

复制代码
+ (NSString*)getUDIDFromKeyChain
{
    NSMutableDictionary *dictForQuery = [[NSMutableDictionary alloc] init];
    [dictForQuery setValue:(id)kSecClassGenericPassword forKey:(id)kSecClass];
    
    // set Attr Description for query
    [dictForQuery setValue:[NSString stringWithUTF8String:kKeychainUDIDItemIdentifier]
                    forKey:kSecAttrDescription];
    
    // set Attr Identity for query
    NSData *keychainItemID = [NSData dataWithBytes:kKeychainUDIDItemIdentifier
                                            length:strlen(kKeychainUDIDItemIdentifier)];
    [dictForQuery setObject:keychainItemID forKey:(id)kSecAttrGeneric];
    
    // The keychain access group attribute determines if this item can be shared
    // amongst multiple apps whose code signing entitlements contain the same keychain access group.
    NSString *accessGroup = [NSString stringWithUTF8String:kKeyChainUDIDAccessGroup];
    if (accessGroup != nil)
    {
#if TARGET_IPHONE_SIMULATOR
        // Ignore the access group if running on the iPhone simulator.
        //
        // Apps that are built for the simulator aren't signed, so there's no keychain access group
        // for the simulator to check. This means that all apps can see all keychain items when run
        // on the simulator.
        //
        // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
        // simulator will return -25243 (errSecNoAccessForItem).
#else
        [dictForQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
    }
    
    [dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecMatchCaseInsensitive];
    [dictForQuery setValue:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    [dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    
    OSStatus queryErr   = noErr;
    NSData   *udidValue = nil;
    NSString *udid      = nil;
    queryErr = SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&udidValue);
    
    NSMutableDictionary *dict = nil;
    [dictForQuery setValue:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
    queryErr = SecItemCopyMatching((CFDictionaryRef)dictForQuery, (CFTypeRef*)&dict);
    
    if (queryErr == errSecItemNotFound) {
        NSLog(@"KeyChain Item: %@ not found!!!", [NSString stringWithUTF8String:kKeychainUDIDItemIdentifier]);
    }
    else if (queryErr != errSecSuccess) {
        NSLog(@"KeyChain Item query Error!!! Error code:%ld", queryErr);
    }
    if (queryErr == errSecSuccess) {
        NSLog(@"KeyChain Item: %@", udidValue);
        
        if (udidValue) {
            udid = [NSString stringWithUTF8String:udidValue.bytes];
        }
    }
    
    [dictForQuery release];
    return udid;
}
复制代码

  上面代码的流程也差不多一样,首先创建一个Dictionary,其中设置一下查找条件,然后通过SecItemCopyMatching方法获取到我们之前保存到KeyChain中的数据。

  

四、总结

  本文介绍了使用KeyChain实现APP删除后依然可以获取到相同的UDID信息的解决方法。

  你可能有疑问,如果系统升级以后,是否仍然可以获取到之前记录的UDID数据?

  答案是肯定的,这一点我专门做了测试。就算我们程序删除掉,系统经过升级以后再安装回来,依旧可以获取到与之前一致的UDID。但是当我们把整个系统还原以后是否还能获取到之前记录的UDID,这一点我觉得应该不行,不过手机里面数据太多,没有测试,如果大家有兴趣可以测试一下,验证一下我的猜想。

  

  完整代码地址: https://github.com/smileEvday/SvUDID

  大家如果要在真机运行时,需要替换两个地方:

  第一个地方是plist文件中的accessGroup中的APPIdentifier。

  第二个地方是SvUDIDTools.m中的kKeyChainUDIDAccessGroup的APPIdentity为你所使用的profile的APPIdentifier。

  文章和代码中如果有什么不对的地方,欢迎指正,在这儿先谢过了。

 

YOLO26训练教程,训练自己的数据集教学,从源码下载,配置虚拟环境,准备数据集、训练、验证、推理测试 。实现0到1的完整教学过程。快速入门必看 本文详细介绍了YOLO26目标检测模型的配置与使用流程:1)下载YOLOv11源码并创建Python3.10虚拟环境;2)安装PyTorch2.5.1及相关依赖库;3)准备数据集并修改配置文件;4)编写训练脚本设置参数(640x640分辨率、500轮次);5)验证模型效果;6)使用训练好的模型进行推理测试;7)生成可视化热力图。整个过程涵盖了从环境搭建到模型应用的全流程,并提供了清华镜像源加速下载。 阅读详情

相关推荐

SAP交货单增强字段更新实战:手把手教你用BAPI_OUTB_DELIVERY_CHANGE和EXTENSION2参数

本文详细解析了如何使用BAPI_OUTB_DELIVERY_CHANGE和EXTENSION2参数实现SAP交货单增强字段的更新。从增强点SMOD_V50B0001的定位到字段落表的全流程,提供了ABAP代码示例和常见问题排查方法,帮助开发者高效完成交货单自定义字段的集成开发。

weixin_42525637的博客 450

iOS7: 如何获取不变的UDID

如何使用KeyChain保存和获取UDID     本文是iOS7系列文章第一篇文章,主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID的问题。并给出一个获取UDID的工具类,使用方便,只需要替换两个地方即可。   一、iOS不用版本获取UDID的方法比较      1)iOS 5.0   iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符...

weixin_34255793的博客 287

宇树GO2-YOLOv5在Jetson Orin上的部署避坑实践

本文详细记录了在宇树GO2四足机器人搭载的Jetson Orin平台上部署YOLOv5目标检测模型的完整实践过程。文章重点分享了从ARM架构认知、网络连接解决方案、Archiconda环境搭建、PyTorch版本精准匹配到依赖安装与性能验证的核心步骤与避坑指南,旨在帮助开发者高效完成边缘计算环境下的算法部署。

app77的博客 668

ios设备唯一标识获取策略

英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor property of

为你超神 852

STC8G1K08A的10位PWM避坑指南:为什么你的占空比调节总失效?(附寄存器操作时序图)

本文深入剖析了STC8G1K08A单片机10位PWM功能中占空比调节失效的核心原因,揭示了数据手册未明确指出的寄存器操作时序陷阱。通过对比错误与正确配置的波形,文章指出关键在于更新占空比高2位前需临时关闭PWM输出,并提供了经过验证的安全操作宏与函数库,帮助开发者彻底解决此问题,实现0%-100%的平滑控制。

yyy34的博客 747

Western blot (WB) 灰度分析进阶指南:ImageJ 高效定量技巧与实战优化

本文详细介绍了使用ImageJ进行Western blot灰度分析的进阶技巧,包括批量处理、背景校正和疑难条带处理等实战优化方法。通过自动化宏脚本和动态背景校正,显著提升分析效率和准确性,特别适合科研人员处理复杂WB数据。

weixin_42557830的博客 896

macOS 更新后找不到钥匙串访问工具的解决方案

随着macOS的不断更新,一些系统工具的位置可能会发生变化,给用户带来不便。钥匙串访问(Keychain Access)是macOS中一个非常重要的工具,用于管理密码、证书等敏感信息。最近,一些用户在更新到最新版本的macOS后发现,在“实用工具”文件夹中找不到钥匙串访问APP。本文将提供详细的解决方案,帮助您找回钥匙串访问工具。

smileKH的博客 1万+

手把手教你学Simulink--基于Simulink的微电网用DC-DC变换器仿真建模

微电网概述微电网:包括可再生能源发电设备、储能系统和负载,可以独立于大电网运行,也可以并网运行。重要性提高能源可靠性:通过本地化供电减少对外部电网的依赖。促进可再生能源利用:支持高效整合多种可再生能源。挑战多源管理:不同类型的能源产生方式各异,需设计灵活的电源管理系统。能量转换效率:需要高效的能量转换装置来确保能源的有效利用。通过上述步骤,我们简要介绍了如何基于Simulink进行微电网中DC-DC变换器的仿真建模。

MHD0815的博客 161

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

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

weixin_36429702的博客 2460

C 语言多文件编程 : 大型程序的组织与管理

本文介绍了C语言多文件编程的核心概念与实践方法。主要内容包括:1. 多文件编程的必要性:解决单文件编程在大型项目中的维护和协作问题;2. 文件组织方式:头文件(.h)负责声明接口,源文件(.c)实现具体功能;3. 编译链接过程:分阶段编译和链接多个源文件;4. 头文件设计原则:包含接口声明、使用保护机制、保持自包含性;5. 模块化实践:通过示例展示学生信息管理系统的模块划分;6. 构建工具:介绍Makefile的编写和使用方法。文章还提供了创建静态库和动态库的指导,并强调了模块化设计、信息隐藏等软件工程原则

2503_91057718的博客 1945

ROCm rocr-libhsakmt分析系列1-2:多GPU跨卡VRAM访问机制分析

本文基于ROCr-Runtime的libhsakmt库源码,深入分析了多GPU系统中跨设备内存访问的实现机制。主要内容包括: 实现流程概述:通过P2P拓扑发现、统一虚拟地址空间、页表映射和硬件转发四个步骤,实现零拷贝的跨GPU内存访问。

图形/计算GPU的驱动与虚拟化技术分享园地 2498

KeyChain保存和获取应用的UDID

KeyChain保存和获取应用的UDIDTODO手机网络游戏,希望玩家不用输入账号就能自动登录到游戏中,这样就需要生成设备的唯一UDID作为账号,需求在删除游戏重新安装、升级游戏等情况下UDID账号不会更改。思路1.生成一个UDID 2.iOS手机上把UDID保存到keychain(钥匙链)中1.1在iOS系统中,获取设备唯一标识的方法有很多:一.UDID(Unique Device Identi

Teng's world 3456

消息平台接入实战:Hermes Agent 实现微信/钉钉日常任务自动化的 4 步配置

揭示 Hermes Agent 接入微信/钉钉时高频失效的根本原因——非 API 调用问题,而是上下文边界缺失;详解通过 soul.md 锁定人格基线、skills/ 目录原子化封装技能、CLAUDE.md 控制记忆节奏、Docker 环境适配四步构建可信赖自动化信任链,并给出身份证号过滤、中文标点

weixin_42520239的博客 162

如何使用KeyChain保存和获取UDID。iOS7获取唯一标示符的方法

转自:http://www.haodaima.net/art/2388057 本文主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID的问题。并给出一个获取UDID的工具类,使用方便,只需要替换两个地方即可。 一、iOS不用版本获取UDID的方法比较   1)iOS 5.0   iOS 2.0版本以后UIDevice提供一个获取设备唯

随缘,随心 9634

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

转载:如何使用KeyChain保存和获取UDID

一、关于为什么在iOS中使用UDIDTools...在 iOS6之前开发一般都是使用设备的mac地址来唯一标示每一台设备,可是,在iOS7之后由于系统的原因,每次获得mac地址,所有、获得的值都是:02:00:00:00:00:00如此,在iOS7之后的使用中在通过获得设备的mac地址来表示设备便不再管用了。作为替代,iOS 中有个方法也是可以获得设备的id的,即可以通过 [[UIDev...

dicuolu4266的博客 135

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

如何使用KeyChain保存和获取不变的UDID

转自:http://www.cnblogs.com/smileEvday/p/UDID.html  如何获取不变的UDID  本文是iOS7系列文章第一篇文章,主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID的问题。并给出一个获取UDID的工具类,使用方便,只需要替换两个地方即可。   一、iOS不用版本获取UDID的方法比较

Welcome to tikeyc's column 905

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

使用KeyChain保存和获取UDID

本文主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID的问题。并给出一个获取UDID的工具类,使用方便,只需要替换两个地方即可。   一、iOS不用版本获取UDID的方法比较      1)iOS 5.0   iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备

bluewindaa的专栏 718

如何使用KeyChain保存和获取UDID - Flex/AS Programmer

原文 http://www.cnblogs.com/yssgyw/p/3364370.html 本文是iOS7系列文章第一篇文章,主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID的问题。并给出一个获取UDID的工具类,使用方便,只需要替换两个地方即可。 一、iOS不用版本获取UDID的方法比较 1)iOS 5.0 iOS 2.0版本以...

143
上一篇: iOS7 UUID唯一标识
下一篇: wireshark使用
focusjava
博客等级 码龄14年 127粉丝 528原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值