iOS提供一種安全的存儲(chǔ)數(shù)據(jù)的方式,就是鑰匙串,想要在app中使用鑰匙串,首先要開(kāi)啟鑰匙串訪(fǎng)問(wèn)的功能,即在app server中勾選Data Protection功能,就像要通知一樣,需要開(kāi)啟改功能。如下圖:

同時(shí)使用精準(zhǔn)app ID如下圖:

打開(kāi)電腦鑰匙串,察看存儲(chǔ)在鑰匙串?dāng)?shù)據(jù),如圖,ios和mac是相似的。

對(duì)應(yīng)的屬性
kSecClass-- 上圖中的種類(lèi)
kSecAttrService--上圖中的位置
kSecAttrAccount--上圖中的賬戶(hù)
kSecValueData--上圖中的密碼
添加數(shù)據(jù):SecItemAdd
NSString *key = @"pwd";
NSString *value = @"password";
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
NSString *service = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *dict = @{
(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService:service,
(__bridge id)kSecAttrAccount:key,
(__bridge id)kSecValueData:valueData
};
CFTypeRef typeResult = NULL;
OSStatus state = SecItemAdd((__bridge CFDictionaryRef)dict, &typeResult);
if (state == errSecSuccess) {
NSLog(@"store secceed");
}
查詢(xún)屬性:SecItemCopyMatching
//查找
-(void)findAttr
{
NSString *key = @"pwd";
NSString *service = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *dict = @{
(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService:service,
(__bridge id)kSecAttrAccount:key,
(__bridge id)kSecReturnAttributes:(__bridge id)kCFBooleanTrue
};
CFDictionaryRef resultDict = NULL;
OSStatus state = SecItemCopyMatching((__bridge CFDictionaryRef)dict, (CFTypeRef*)&resultDict);
NSDictionary *result = (__bridge_transfer NSDictionary*)resultDict;
if (state == errSecSuccess)
{
NSLog(@"server:%@",result[(__bridge id)kSecAttrService]);
NSLog(@"account:%@",result[(__bridge id)kSecAttrAccount]);
NSLog(@"assessGroup:%@",result[(__bridge id)kSecAttrAccessGroup]);
NSLog(@"createDate:%@",result[(__bridge id)kSecAttrCreationDate]);
NSLog(@"modifyDate:%@",result[(__bridge id)kSecAttrModificationDate]);
}
}
當(dāng)在字典中添加kSecReturnAttributes并設(shè)置為yes時(shí),表示查詢(xún)鑰匙串?dāng)?shù)據(jù)的屬性,SecItemCopyMatching的第二個(gè)參數(shù)為字典。
查詢(xún)數(shù)據(jù):SecItemCopyMatching
//查找數(shù)據(jù)
-(void)findData
{
NSString *key = @"pwd";
NSString *server = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *queueDict = @{
(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService:server,
(__bridge id)kSecAttrAccount:key,
(__bridge id)kSecReturnData:(__bridge id)kCFBooleanTrue
/*(__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitAll
當(dāng)為kSecMatchLimit時(shí),SecItemCopyMatching第二個(gè)參數(shù)為CFArrayRef,元素為CFDataRef*/
};
CFDataRef dataRef = NULL;
OSStatus state = SecItemCopyMatching((__bridge CFDictionaryRef)queueDict, (CFTypeRef*)&dataRef);
if (state == errSecSuccess) {
NSString *value = [[NSString alloc] initWithData:(__bridge_transfer NSData*)dataRef encoding:NSUTF8StringEncoding];
NSLog(@"value:%@",value);
}
}
當(dāng)在字典中添加kSecReturnData并設(shè)置為yes時(shí),表示查詢(xún)鑰匙串?dāng)?shù)據(jù)的數(shù)據(jù),SecItemCopyMatching的第二個(gè)參數(shù)為CFDataRef。當(dāng)在字典中添加了kSecMatchLimit 時(shí)并設(shè)置為kSecMatchLimitAll會(huì)返回所有的,SecItemCopyMatching第二個(gè)參數(shù)為CFArrayRef,元素為CFDataRef。
更新數(shù)據(jù):SecItemUpdate
-(void)updateData
{
NSString *key = @"pwd";
NSString *server = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *queue = @{
(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService:server,
(__bridge id)kSecAttrAccount:key
};
OSStatus state = SecItemCopyMatching((__bridge CFDictionaryRef)queue, NULL);
//存在修改
if (state == errSecSuccess) {
NSString *newValue = @"new Value";
NSData *newData = [newValue dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *paramDict = @{
(__bridge id)kSecValueData:newData
};
OSStatus updateState = SecItemUpdate((__bridge CFDictionaryRef)queue, (__bridge CFDictionaryRef)paramDict);
if (updateState == errSecSuccess) {
NSLog(@"更新成功");
}
}
}
刪除鑰匙串:SecItemDelete
-(void)deleteData
{
NSString *key = @"pwd";
NSString *server = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *queue = @{
(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService:server,
(__bridge id)kSecAttrAccount:key
};
OSStatus state = SecItemCopyMatching((__bridge CFDictionaryRef)queue, NULL);
//存在
if (state == errSecSuccess) {
OSStatus deleteState = SecItemDelete((__bridge CFDictionaryRef)queue);
if (deleteState == errSecSuccess) {
NSLog(@"刪除成功!!!");
}
}
}
總結(jié):鑰匙串使用感覺(jué)還是挺有用的,今天特意研究了一下,還有兩個(gè)同一個(gè)開(kāi)發(fā)者發(fā)布的app之間可以共享鑰匙串?dāng)?shù)據(jù),Sharing Keychain Data Between Multiple Apps,下次有時(shí)間研究一下,下次再更新。
簡(jiǎn)單demo:https://github.com/jiangtaidi/KeyChainPro.git