#import
@interfaceFFKeyChain : NSObject+ (void)save:(NSString *)serve data:(id)Data;+ (id)read:(NSString *)serve;@end
#import "FFKeyChain.h"
@implementationFFKeyChain/*
https://blog.csdn.net/zhoushuangjian511/article/details/78583429
https://www.cnblogs.com/whyandinside/p/3303108.htmlkSecAttrAccessible: 属性控制keychain中的Item什么时候可以被访问。可选值有 kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAlways, kSecAttrAcessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, kSecAttrAccessibleAlwaysThisDeviceOnly
带有ThisDeviceOnly的意思是如果手机使用其他device的备份restore了之后这些Item就不存在了。
kSecAttrAccessGroup: 如果希望,keychain的item可以被多个应用share, 可以给Item设置这个属性, 类型是CFStringRef, 应用程序在被编译时,可以在entitlement中指定自己的accessgroup,如果应用中的accessgroup和keyChain item中的Accessgroup名字一直,那么这个应用就可以访问这个item,缺点是:accessgroup是由开发者指定的,他可以故意跟其他应用的accessgroup一样,已达到访问其他应用item的目的。同事还支持 wild card ,如keychain-dumper将自己的accessgroup指定为*,从而可以把keychain中所有的Item都dump出来。
kSecAttrAccount 必须 指定一个字典键,其值为物品的描述属性, 使用此键设置或获得,CFStringRef, 包含账户名
kSecAttrService 必须 指定一个字典键,其值为物品的描述属性, 使用此键设置或获得,CFStringRef与该项目相关的服务*/
+ (NSMutableDictionary *)getKeyChainQuery:(NSString *)serve {return [@{(id)kSecClass:(id)kSecClassGenericPassword,
(id)kSecAttrAccount:serve,
(id)kSecAttrService:serve,
(__bridge NSString*)kSecAttrAccessible:(__bridge NSString *)kSecAttrAccessibleAfterFirstUnlock,
} mutableCopy];
}+(NSMutableDictionary*)keyChainIdentifier:(NSString*)identifier {
NSMutableDictionary* keyChainMutableDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword,kSecClass,identifier,kSecAttrService,identifier,kSecAttrAccount,kSecAttrAccessibleAfterFirstUnlock,kSecAttrAccessible, nil];returnkeyChainMutableDictionary;
}+ (void)save:(NSString *)serve data:(id)Data {
NSMutableDictionary*mDic = [self keyChainIdentifier:serve];//[self getKeyChainQuery:serve];//;
SecItemDelete((CFDictionaryRef)mDic);
[mDic setObject:[NSKeyedArchiver archivedDataWithRootObject:Data] forKey:(id)kSecValueData];
OSStatus sta=SecItemAdd((__bridge CFDictionaryRef)mDic, NULL);if (sta ==noErr) {
NSLog(@"成功。。");
};
}+ (void)delete:(NSString *)serve {
NSMutableDictionary*mdic =[self getKeyChainQuery:serve];
SecItemDelete((__bridge CFDictionaryRef)mdic);
}
+ (void)neeUpdateServe:(NSString *)server updateValue:(NSString *)value {
NSMutableDictionary *mdic = [self getKeyChainQuery:server];
OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)mdic, (__bridge CFDictionaryRef)@{(id)kSecValueData:[NSKeyedArchiver archivedDataWithRootObject:value]});
if (status == errSecSuccess) {
NSLog(@"更新成功");
}else {
NSLog(@"更新失败");
}
}+ (id)read:(NSString *)serve {id let =nil;
NSMutableDictionary*mdic =[self getKeyChainQuery:serve];
[mdic setValue:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[mdic setValue:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
CFDataRef keyData=nil;if (SecItemCopyMatching((__bridge CFDictionaryRef)mdic, (CFTypeRef *)&keyData) ==noErr) {@try{
let= [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
}@catch (NSException *e) {
NSLog(@"Unarchiver of %@ failed %@", serve, e);
}@finally{
}
}if(keyData) {
CFRelease(keyData);
}returnlet;
}@end