一、钥匙串存储相比其他存储的优点
APP删掉下次下载能记住存在钥匙串中的信息,多用于账号密码、设备唯一标识符的存储等GitHub:XKeyChain
二、Demo效果
Demo有两个界面,分别有一个输入框,一个存入钥匙串按钮一个删除钥匙串信息按钮。
1、输入框输入内容,点击存入钥匙串的按钮,删除App。重新下载(编译)可以看到之前输入的内容还显示在输入框
2、点击删除那个按钮,重新下载(编译),输入框内容不存在了
三、主要代码如下
1、h文件
#import Foundation/Foundation.h
#import Security/security.h
@interface XKeyChain : NSObject
/**
保持数据到钥匙串的方法
@param data 对应字典的值(保存的文本信息)
@param key 对应字典的键(一条信息一个键)
这对键值保存在单例的字典里
*/
+ (void)saveData:(id)data key:(NSString *)key;
/**
加载存在钥匙串中键对应的信息
@param key 对应的键
@return 键对应的值
*/
+ (id)loadDataKey:(NSString *)key;
/**
删除该APP存在钥匙串中的所有信息(一般用不上)
*/
+ (void)deleteData;
2、m文件
#import "XKeyChain.h"
#import "InfoManager.h"
static NSString *const KEY_BUILD_ID = @"demo.xzr.KeyChain"; //区分app的键(每个app不一样)
static NSString *const KEY_BUILD_ID_SUB = @"demo.xzr.passWord"; //与keyBuildId唯一对应生成的键,该键对应的值就是具体存在钥匙串中的信息(包括多条信息)
@implementation XKeyChain
/**
把信息存放到钥匙串当中
@param data 存放的信息(可以是字典、数组、字符串)
@param key 键值(传入不同键值实现多次信息存储)
*/
+ (void)saveData:(id)data key:(NSString *)key{
NSMutableDictionary *informationDic = [NSMutableDictionary dictionary];
InfoManager *manager = [InfoManager share];
[manager.singleDic setObject:data forKey:key];
[informationDic setObject:manager.singleDic forKey:KEY_BUILD_ID_SUB];
[self saveInformationDic:informationDic];
}
+ (void)saveInformationDic:(NSMutableDictionary *)informationDic {
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychainQuery:KEY_BUILD_ID];
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:informationDic] forKey:(id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}
/**
获取存在钥匙串中的信息
@param key 对应的键值
@return 钥匙串中对应键的值
*/
+ (id)loadDataKey:(NSString *)key {
NSMutableDictionary *keyBuildIdSubDic = [self load:KEY_BUILD_ID];
NSMutableDictionary *informationDic = keyBuildIdSubDic[KEY_BUILD_ID_SUB];
return informationDic[key];
}
+ (NSMutableDictionary *)load:(NSString *)keyBuildId {
NSMutableDictionary *ret = [[NSMutableDictionary alloc] init];
NSMutableDictionary *keychainQuery = [self getKeychainQuery:keyBuildId];
//Configure the search setting
//Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", keyBuildId, e);
} @finally {
}
}
if (keyData)
CFRelease(keyData);
return ret;
}
/**
删除存在钥匙串中该APP的所有信息
*/
+ (void)deleteData {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:KEY_BUILD_ID];
SecItemDelete((CFDictionaryRef)keychainQuery);
}
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)keyBuildId {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassGenericPassword,(id)kSecClass,
keyBuildId, (id)kSecAttrService,
keyBuildId, (id)kSecAttrAccount,
(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
nil];
}
其中manager是个单例对象 里头有一个可变字典singleDic。用于存储钥匙串中的信息
四、可以参考我画的思维导图
五、还有不清楚的可以下载该文章对应的GitHub代码:XKeyChain 。如果有疑问或者批判请不要吝啬,喜欢就点个赞呗,谢谢大家!
六、参考文献
1、iOS简单使用keychain存储密码
2、百度百科
3、iOS中Keychain保存用户名和密码