(绝对有用)iOS获取UUID,并使用keychain存储
原文链接 http://blog.sina.com.cn/s/blog_5971cdd00102vqgy.html
UDID被弃用,使用UUID来作为设备的唯一标识。获取到UUID后,如果用NSUserDefaults存储,当程序被卸载后重装时,再获得的UUID和之前就不同了。使用keychain存储可以保证程序卸载重装时,UUID不变。但当刷机或者升级系统后,UUID还是会改变的。但这仍是目前为止最佳的解决办法了,如果有更好的解决办法,欢迎留言。
#import
尖括号(Foundation/Foundation.h)
@interface UUID : NSObject
+(NSString *)getUUID;
@end
UUID.m中的代码:
#import "UUID.h"
#import 尖括号(Foundation/Foundation.h)
#import
"KeychainItemWrapper.h"
@implementation UUID
+(NSString *)getUUID
{
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper
alloc]
initWithIdentifier:@"UUID"
accessGroup:@"YOUR_BUNDLE_SEED.com.yourcompany.userinfo"];
NSString *strUUID = [keychainItem
objectForKey:(id)CFBridgingRelease(kSecValueData)];
//首次执行该方法时,uuid为空
if ([strUUID isEqualToString:@""])
{
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
strUUID = (NSString *)CFBridgingRelease(CFUUIDCreateString (kCFAllocatorDefault,uuidRef));
[keychainItem setObject:strUUID forKey:(id)CFBridgingRelease(kSecValueData)];
}
return strUUID;
}
@end
第二个类是苹果官方的一个Demo里封装的,Demo的下载地址:http://developer.apple.com/library/ios/#samplecode/GenericKeychain/Listings/Classes_KeychainItemWrapper_h.html#//apple_ref/doc/uid/DTS40007797-Classes_KeychainItemWrapper_h-DontLinkElementID_9
KeychainItemWrapper.h中的代码:
#import 尖括号(UIKit/UIKit.h)
@interface KeychainItemWrapper
: NSObject
{
NSMutableDictionary *keychainItemData;
NSMutableDictionary *genericPasswordQuery;
}
@property (nonatomic, retain) NSMutableDictionary *keychainItemData;
@property (nonatomic, retain) NSMutableDictionary
*genericPasswordQuery;
- (id)initWithIdentifier:
(NSString *)identifier
accessGroup:(NSString *)
accessGroup;
- (void)setObject:(id)inObject forKey:(id)key;
- (id)objectForKey:(id)key;
- (void)resetKeychainItem;
@end
KeychainItemWrapper.m中的代码:
#import
"KeychainItemWrapper.h"
#import
尖括号(Security/Security.h)
@interface KeychainItemWrapper
(PrivateMethods)
- (NSMutableDictionary
*)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert;
- (NSMutableDictionary
*)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert;
-
(void)writeToKeychain;
@end
@implementation
KeychainItemWrapper
@synthesize keychainItemData,
genericPasswordQuery;
- (id)initWithIdentifier:
(NSString *)identifier
accessGroup:(NSString *)
accessGroup;
{
if (self = [super init])
{
genericPasswordQuery = [[NSMutableDictionary alloc]
init];
[genericPasswordQuery setObject:(id)CFBridgingRelease(kSecClassGenericPassword) forKey:(id)kSecClass];
[genericPasswordQuery setObject:identifier forKey:(id)CFBridgingRelease(kSecAttrGeneric)];
if (accessGroup != nil)
{
#if TARGET_IPHONE_SIMULATOR
#else
[genericPasswordQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
}
[genericPasswordQuery setObject:(id)CFBridgingRelease(kSecMatchLimitOne) forKey:(id)kSecMatchLimit];
[genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
NSDictionary
*tempQuery = [NSDictionary
dictionaryWithDictionary:genericPasswordQuery];
NSMutableDictionary *outDictionary =
nil;
if (!
SecItemCopyMatching((CFDictionaryRef)tempQuery, (CFTypeRef *)&outDictionary) ==
noErr)
{
[self
resetKeychainItem];
[keychainItemData setObject:identifier forKey:(id)kSecAttrGeneric];
if (accessGroup != nil)
{
#if TARGET_IPHONE_SIMULATOR
#else
[keychainItemData setObject:accessGroup forKey:(id)kSecAttrAccessGroup];
#endif
}
}
else
{
self.keychainItemData = [self secItemFormatToDictionary:outDictionary];
}
[outDictionary release];
}
return self;
}
- (void)dealloc
{
[keychainItemData release];
[genericPasswordQuery release];
[super dealloc];
}
- (void)setObject:(id)inObject forKey:(id)key
{
if (inObject == nil) return;
id currentObject = [keychainItemData objectForKey:key];
if (![currentObject isEqual:inObject])
{
[keychainItemData setObject:inObject forKey:key];
[self writeToKeychain];
}
}
- (id)objectForKey:(id)key
{
return [keychainItemData objectForKey:key];
}
- (void)resetKeychainItem
{
OSStatus junk = noErr;
if
(!keychainItemData)
{
self.keychainItemData = [[NSMutableDictionary alloc] init];
}
else
if (keychainItemData)
{
NSMutableDictionary *tempDictionary =
[self dictionaryToSecItemFormat:keychainItemData];
junk = SecItemDelete((CFDictionaryRef)tempDictionary);
NSAssert( junk
== noErr || junk == errSecItemNotFound, @"Problem deleting current dictionary."
);
}
[keychainItemData
setObject:@"" forKey:(id)kSecAttrAccount];
[keychainItemData setObject:@""
forKey:(id)kSecAttrLabel];
[keychainItemData
setObject:@""
forKey:(id)kSecAttrDescription];
[keychainItemData
setObject:@""
forKey:(id)kSecValueData];
}
- (NSMutableDictionary
*)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert
{
NSMutableDictionary *returnDictionary =
[NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];
[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
NSString *passwordString =
[dictionaryToConvert objectForKey:(id)kSecValueData];
[returnDictionary setObject:[passwordString
dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];
return returnDictionary;
}
- (NSMutableDictionary
*)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert
{
NSMutableDictionary *returnDictionary =
[NSMutableDictionary
dictionaryWithDictionary:dictionaryToConvert];
[returnDictionary
setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
NSData *passwordData =
NULL;
if (SecItemCopyMatching((CFDictionaryRef)returnDictionary,
(CFTypeRef *)&passwordData)
== noErr)
{
[returnDictionary
removeObjectForKey:(id)kSecReturnData];
NSString *password =
[[[NSString
alloc] initWithBytes:[passwordData
bytes] length:[passwordData
length]
encoding:NSUTF8StringEncoding] autorelease];
[returnDictionary setObject:password forKey:(id)kSecValueData];
}
else
{
NSAssert(NO,
@"Serious error, no matching item found in the
keychain.\n");
}
[passwordData release];
return returnDictionary;
}
- (void)writeToKeychain
{
NSDictionary *attributes = NULL;
NSMutableDictionary *updateItem =
NULL;
OSStatus result;
if (SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes) ==
noErr)
{
updateItem
= [NSMutableDictionary dictionaryWithDictionary:attributes];
[updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass];
NSMutableDictionary *tempCheck =
[self dictionaryToSecItemFormat:keychainItemData];
[tempCheck removeObjectForKey:(id)kSecClass];
#if TARGET_IPHONE_SIMULATOR
[tempCheck removeObjectForKey:(id)kSecAttrAccessGroup];
#endif
result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);
NSAssert( result == noErr,
@"Couldn't update the Keychain Item." );
}
else
{
result
= SecItemAdd((CFDictionaryRef)[self
dictionaryToSecItemFormat:keychainItemData],
NULL);
NSAssert( result == noErr,
@"Couldn't add the Keychain Item." );
}
}
@end
1. KeychainItemWrapper类在官方Demo里面也有,如果我复制出错了,大家可以在上面的链接上下载官方Demo.
2.使用时要添加Security.framework
3. 尤为注意的是,UUID类下面这句代码中group的设置方法。
*keychainItem =
[[KeychainItemWrapper
alloc]
initWithIdentifier:@"UUID"
accessGroup:@"YOUR_BUNDLE_SEED.com.yourcompany.userinfo"];
(1)在项目相同的目录下创建KeychainAccessGroups.plist文件。
(2)在项目相同的目录下创建KeychainAccessGroups.plist文件。在Target-Build
Settings-Code Signing栏下的Code
Signing Entitlements右侧添加KeychainAccessGroups.plist,如下图。
首次安装程序时,打印出一个uuid,当把程序卸载后,再用getUUID获得
NSString * uuid= [UUID getUUID];
NSLog(@"uuid=%@",uuid);
测试结果:
(绝对有用)iOS获取UUID,并使用keychain存储的更多相关文章
- iOS获取UUID
转自:<iOS获取设备的唯一标识的方法总结以及最好的方法> 参考:<获取iOS设备唯一标识> 总结一下: 1.代码采用CFUUID+KeyChain的实现方式. 2.CFUUI ...
- iOS获取UUID,并使用keychain存储
http://blog.sina.com.cn/s/blog_5971cdd00102vqgy.html
- iOS 获取UUID
-(NSString*)GetUUID { CFUUIDRef puuid = CFUUIDCreate( nil ); CFStringRef uuidString = CFUUIDCreateSt ...
- iOS获取设备卸载后不变的UUID
1.首先导入系统库Security.framework 2.创建文件SFHFKeychainUtils.h如下(复制即可): @interface SFHFKeychainUtils : NSObje ...
- iOS获取设备唯一标识的8种方法
8种iOS获取设备唯一标识的方法,希望对大家有用. UDID UDID(Unique Device Identifier),iOS 设备的唯一识别码,是一个40位十六进制序列(越狱的设备通过某些工具可 ...
- iOS获取设备型号、装置类型等信息
iOS获取设备型号.设备类型等信息 设备标识 关于设备标识,历史上盛行过很多英雄,比如UDID.Mac地址.OpenUDID等,然而他们都陆陆续续倒在了苹果的门下.苹果目前提供了2个方法供App获取设 ...
- iOS 获取一个不变的UDID
原文:iOS7: 如何获取不变的UDID 如何使用KeyChain保存和获取UDID 本文是iOS7系列文章第一篇文章,主要介绍使用KeyChain保存和获取APP数据,解决iOS7上获取不变UDID ...
- IOS - UDID IDFA IDFV MAC keychain
在开发过程中,我们经常会被要求获取每个设备的唯一标示,以便后台做相应的处理.我们来看看有哪些方法来获取设备的唯一标示,然后再分析下这些方法的利弊. 具体可以分为如下几种: UDID IDFA IDFV ...
- iOS获取设备唯一标识的各种方法?IDFA、IDFV、UDID分别是什么含义?
一.UDID (Unique Device Identifier) UDID的全称是Unique Device Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和 ...
随机推荐
- Sunday算法模板
Sunday是一个线性字符串模式匹配算法.算法的概念如下: Sunday算法是Daniel M.Sunday于1990年提出的一种字符串模式匹配算法.其核心思想是:在匹配过程中,模式串并不被要求一定要 ...
- linux_base-f10-10_7 linuxulator is not (kld)loaded
# cd linux_base-f10/# make install clean===> linux_base-f10-10_7 linuxulator is not (kld)loaded. ...
- sysbench0.5安装和使用介绍
sysbench是一个模块化的.跨平台.多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况,sysbench支持MySQL.PostgreSQL.Oracle数据库OLTP测试.它 ...
- EF+linq的增删改查
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...
- Android(java)学习笔记146:网页源码查看器(Handler消息机制)
1.项目框架图: 2.首先是布局文件activity_main.xml: <LinearLayout xmlns:android="http://schemas.android.com ...
- 洛谷 P2668 斗地主
毒瘤题目,搞了三天-- 也没什么好讲的,就是纯搜索,先搜顺子,再搜其他的,最后单张牌和对子的时候,就不要搜索了,直接枚举,不然会T飞掉多么痛的领悟-- 主要还是靠码力 #include<iost ...
- 【curl】【php】curl报错,错误代码77,CURLE_SSL_CACERT_BADFILE (77)解决方法
CURLE_SSL_CACERT_BADFILE (77) - 读取 SSL CA 证书时遇到问题(可能是路径错误或访问权限问题) 在微信接口相关开发时容易出现此问题 这一般是因为服务更新了相关的软件 ...
- LeetCode(91) Decode Ways
题目 A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A ...
- CodeForces:847D-Dog Show
D. Dog Show time limit per test2 seconds memory limit per test256 megabytes Problem Description A ne ...
- ACM训练联盟周赛 K. Teemo's reunited
Teemo likes to drink raspberry juice. He even spent some of his spare time tomake the raspberry jui ...