在一个公司中可能有多款产品。对于用户而言,一般使用一个帐号就可以登陆访问该公司的所有的产品。对于这种情况,如果一款手机中装了该公司的两款(或多款)产品,那么我们希望只在其中一款产品中登陆,那么另一款产品中就会获取到帐号密码,从而进行自动登陆。对于iOS端来说,我们可以借助Keychain来实现了。
1.首先是做到可以利用苹果提供的API将一些密码等敏感的数据保存到钥匙串中。
将一条或者多条信息保存到钥匙串:
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef _Nullable *result);
第一个参数是一个属性字典,这些字典包含一些特定的键和值等,例如:
[@{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock
} mutableCopy];
其中kSecClass是必须包含的,是指搜索的类型,后面的Value用于指定具体的搜索类型。共有5种可选的类型。分别是:
//1.普通的密码类型
kSecClassGenericPassword
//2.互联网密码类型
kSecClassInternetPassword
//3.证书类型
kSecClassCertificate
//4.加密的键类型
kSecClassKey
//5.身份类型
kSecClassIdentity
这5种类型我们可以根据应用的不同场景进行选择。
如果想同时添加多条数据,可以kSecUseItemList
作为键,以一个数组作为作为值。
如果需要多应用间共享Keychian中的数据,需要在这个属性字典中包含以kSecAttrAccessGroup
为键,值为应用程序间共享的钥匙串组名字。
2.添加和配置kSecAttrAccessGroup。
在程序中添加kSecAttrAccessGroup,其实就是配置SecItemAdd函数其中的字典参数。
代码如下:
//保存键值到钥匙串中
+ (BOOL)cacheValue:(id)value forKey:(NSString *)key {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];
[keychainQuery setObject:accessGroupItem forKey:(id)kSecAttrAccessGroup];
//删除之前的键值
[self deleteCacheValueForKey:key];
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:value] forKey:(__bridge id)kSecValueData];
OSStatus result = SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
return CHECK_OSSTATUS_ERROR(result);
}
//该函数是配置字典属性参数
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)key {
return [@{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService : key,
(__bridge id)kSecAttrAccount : key,
(__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleAfterFirstUnlock
} mutableCopy];
}
下面说一下配置。配置也非常简单。
首先新建一个plist文件。例如: keychain-access-groups.plist。该文件中的配置如下图:
其中item0中的值,需要注意以下,这里需要换成你的开发者Developer Team ID,后面可以加一些BundleID的公共部分。这个值在多个应用中名字应该是一样的,代表属于一个组。
然后,你需要在Build Settings的Code Siging Entitlements中引用这个文件。例如像下面这样。
到这里就配置好了。
完整代码可以参考下面的这个。
https://github.com/wenyc/YCKeyChainCacheTool