keychain储存

作者: 马戏团小丑 | 来源:发表于2017-11-01 10:04 被阅读13次

    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];
    

    相关文章

      网友评论

        本文标题:keychain储存

        本文链接:https://www.haomeiwen.com/subject/ptlppxtx.html