我有一个应用程序(app1),它位于appstore中,包ID为com.x. y 现在我正在开发另一个应用程序(app2),在相同的开发者帐户下使用包ID com.x. z
我想让app1中存储的keychain值可用于app2。
钥匙串的可用性由钥匙串访问组决定。 所以,如果我将两个前缀(当前团队ID)添加到捆绑ID我能够获取值。示例 teamid .com.x.y teamid .com.x.z
问题当我向appstore中的app1添加前缀时,它会再次请求登录凭据,因为应用程序拥有大量用户,所以我不希望这样做。 我之前没有使用前缀我只是添加了它们。 有没有办法让我可以获得两个应用程序的钥匙串访问权限而无需用户再次登录。
答案 0 :(得分:1)
首先,重要的是要意识到Xcode已经将AppIdentifierPrefix添加到您的标识符中。遗憾的是,它隐藏在GUI中,但是如果你打开权利plist,你会看到它。这是用于对应用程序进行签名的标识符,它是用于强制执行访问控制的部分。我不相信你添加的teamid
前缀确实做了什么。我通常会建议访问组com.x.shared
或com.x.appgroup.shared
而不使用com.x.z
(我假设com.x.y
已经存在,因此您无法更改)。
我在这里假设你不想强迫用户升级App1,对吗?我正在继续这个假设。
如果您可以升级App1(不需要升级,但确保所有新客户都有升级版本),则仅存储在com.x.y
(如果存在)。否则,请存储在com.x.shared
:
如果你现在不想升级App1(必需与否),那么只需在App2中读写com.x.y
即可。
当您准备好临终com.x.y
组(如果您最终能够升级所有App1支持的用户),那么您可以切换到:
com.x.y
读取。如果已找到,请将其删除,然后将其重新创建为com.x.shared
。您可以在应用程序启动时执行此操作一次(只需编写一个表示您已完成此操作的NSUserDefaults
。com.x.shared
。这里的关键工具是当你要求一个显式访问组时,你必须提供整个东西,包括你的AppId(它没有显示在Xcode GUI中)。您当然可以对其进行硬编码,但更好的解决方案是动态查询它。我使用David H's code的更新版本:
- (NSString *)bundleSeedID {
NSDictionary *query = @{ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrAccount : @"bundleSeedIDQuery",
(__bridge id)kSecAttrService : @"",
(__bridge id)kSecReturnAttributes : (id)kCFBooleanTrue
};
CFDictionaryRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFTypeRef)query,
(CFTypeRef *)&result);
if (status == errSecItemNotFound)
status = SecItemAdd((__bridge CFTypeRef)query, (CFTypeRef *)&result);
if (status != errSecSuccess)
return nil;
NSString *accessGroup = [(__bridge NSDictionary *)result
objectForKey:(__bridge id)kSecAttrAccessGroup];
NSArray *components = [accessGroup componentsSeparatedByString:@"."];
NSString *bundleSeedID = components[0];
CFRelease(result);
return bundleSeedID;
}
这将在运行时告诉您前缀。它会创建一个伪造的钥匙串条目,然后查询它并查看附加了哪个访问组。
您可能对2014年Renaissance.io的Getting Security and Privacy Right的第一部分感兴趣。您可以跳到“使用钥匙扣保护秘密。”