一、鑰匙串存儲相比其他存儲的優點
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保存用戶名和密碼