keychain的特點(diǎn)就是不比其他存儲(chǔ)在沙盒中,即使刪除了App,數(shù)據(jù)依然保存在keychain中,如果重新安裝了App,還可以從keychain獲取數(shù)據(jù)。
keychain的數(shù)據(jù)可以用過group方式,讓程序可以在App間共享,不過得要相同TeamID。
- keychain在secutity.framework中,需導(dǎo)入
GQKeychain.m文件中
根據(jù)特定的Service創(chuàng)建一個(gè)用于操作KeyChain的Dictionary
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassGenericPassword,(__bridge id)kSecClass,
service, (__bridge id)kSecAttrService,
service, (__bridge id)kSecAttrAccount,
(__bridge id)kSecAttrAccessibleAfterFirstUnlock,(__bridge id)kSecAttrAccessible,
nil];
}
extern const CFStringRef kSecClassGenericPassword 一般密碼
extern const CFStringRef kSecClassInternetPassword 互聯(lián)網(wǎng)密碼
extern const CFStringRef kSecClassCertificate 證書
extern const CFStringRef kSecClassKey 秘鑰
extern const CFStringRef kSecClassIdentity 身份對象,包含kSecClassKey和kSecClassCertificate
keychain同樣與sql,存在增刪改查
SecItemAdd 添加一個(gè)item
SecItemUpdate 更新已存在的item
SecItemCopyMatching 搜索一個(gè)已存在的item
SecItemDelete 刪除一個(gè)keychain item
增
+ (void)saveKeychain:(NSString *)service data:(id)data
{
NSMutableDictionary *keychainQuery = [GQKeyChain getKeychainQuery:service];
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}
查
+ (id)getKeychain:(NSString *)service
{
id ret = nil;
NSMutableDictionary *keychainQuery = [GQKeyChain getKeychainQuery:service];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", service, e);
} @finally {
}
}
if (keyData)
CFRelease(keyData);
return ret;
}
改
+ (BOOL)updateKeychain:(id)data forService:(NSString *)service{
NSMutableDictionary *keychainQuery = [GQKeyChain getKeychainQuery:service];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
[updateDictionary setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
OSStatus status = SecItemUpdate((CFDictionaryRef)keychainQuery,
(CFDictionaryRef)updateDictionary);
if (status == errSecSuccess) {
return YES;
}
return NO;
}
刪
+ (void)deleteKeychain:(NSString *)service {
NSMutableDictionary *keychainQuery = [GQKeyChain getKeychainQuery:service];
SecItemDelete((CFDictionaryRef)keychainQuery);
}
- 如果需要通過group,讓程序可以在App間共享數(shù)據(jù)
打開項(xiàng)目配置

會(huì)多出這么一個(gè)文件:

然后在info.plist增加一對鍵值對Key: AppIdentifierPrefix Value: $(AppIdentifierPrefix),為了方便代碼獲取到發(fā)布者的App標(biāo)識(shí)
最后創(chuàng)建Keychain Item的時(shí)候,需要指定的相應(yīng)的group
NSMutableDictionary *keychainQuery = [GQKeyChain getKeychainQuery:service];
NSString *perfix = [[[NSBundle mainBundle]infoDictionary]objectForKey:@"AppIdentifierPrefix"];
NSString *groupString = [NSString stringWithFormat:@"%@com.jinyinghui.bill",perfix];
[keychainQuery setObject:groupString forKey:(id)kSecAttrAccessGroup];