keychain的特點就是不比其他存儲在沙盒中,即使刪除了App,數據依然保存在keychain中,如果重新安裝了App,還可以從keychain獲取數據。
keychain的數據可以用過group方式,讓程序可以在App間共享,不過得要相同TeamID。
- keychain在secutity.framework中,需導入
GQKeychain.m文件中
根據特定的Service創建一個用于操作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 互聯網密碼
extern const CFStringRef kSecClassCertificate 證書
extern const CFStringRef kSecClassKey 秘鑰
extern const CFStringRef kSecClassIdentity 身份對象,包含kSecClassKey和kSecClassCertificate
keychain同樣與sql,存在增刪改查
SecItemAdd 添加一個item
SecItemUpdate 更新已存在的item
SecItemCopyMatching 搜索一個已存在的item
SecItemDelete 刪除一個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間共享數據
打開項目配置
會多出這么一個文件:
然后在info.plist增加一對鍵值對Key: AppIdentifierPrefix Value: $(AppIdentifierPrefix)
,為了方便代碼獲取到發布者的App標識
最后創建Keychain Item的時候,需要指定的相應的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];