如何以编程方式访问Bundle Seed ID / Team ID / App Identifier Prefix字符串? (就我所知,这些都是一样的。)
我正在使用UICKeychainStore钥匙串包装器来跨多个应用程序保存数据。这些应用程序中的每一个都在其权利清单中具有共享密钥链访问组,并共享相同的配置文件。默认情况下,钥匙串服务使用plist中的第一个访问组作为保存数据的访问组。当我调试UICKeychainStore时,这看起来像“AS234SDG.com.myCompany.SpecificApp”。我想将访问组设置为“AS234SDG.com.myCompany.SharedStuff”,但我似乎无法找到如何以编程方式获取访问组的“AS234SDG”字符串,并希望避免对其进行硬编码如果可能的话。
答案 0 :(得分:77)
Info.plist可以拥有您自己的信息,如果您使用$(AppIdentifierPrefix)
编写值,则会在构建阶段将其替换为实际的应用程序标识符前缀。
所以,试试这个:
在Info.plist中,添加有关应用标识符前缀的信息。
<key>AppIdentifierPrefix</key>
<string>$(AppIdentifierPrefix)</string>
然后,您可以使用Objective-C以编程方式检索它:
NSString *appIdentifierPrefix =
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppIdentifierPrefix"];
和Swift:
let appIdentifierPrefix =
Bundle.main.infoDictionary!["AppIdentifierPrefix"] as! String
请注意,appIdentifierPrefix
以句点结尾;例如AS234SDG.
答案 1 :(得分:55)
您可以通过查看现有KeyChain项的访问组属性(即kSecAttrAccessGroup
)以编程方式检索Bundle Seed ID。在下面的代码中,我查找现有的KeyChain条目,如果它不存在则创建一个。一旦我有KeyChain条目,我从中提取访问组信息并返回访问组的第一个组件,以“。”分隔。 (期间)作为捆绑种子ID。
+ (NSString *)bundleSeedID {
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge NSString *)kSecClassGenericPassword, (__bridge NSString *)kSecClass,
@"bundleSeedID", kSecAttrAccount,
@"", kSecAttrService,
(id)kCFBooleanTrue, kSecReturnAttributes,
nil];
CFDictionaryRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
if (status == errSecItemNotFound)
status = SecItemAdd((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
if (status != errSecSuccess)
return nil;
NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:(__bridge NSString *)kSecAttrAccessGroup];
NSArray *components = [accessGroup componentsSeparatedByString:@"."];
NSString *bundleSeedID = [[components objectEnumerator] nextObject];
CFRelease(result);
return bundleSeedID;
}
答案 2 :(得分:6)
在swift3中(基于@Hiron解决方案)
只需一行:
var appIdentifierPrefix = Bundle.main.infoDictionary!["AppIdentifierPrefix"] as! String
鉴于在Info.plist中,添加以下键值属性:
key:AppIdentifierPrefix
string-value:$(AppIdentifierPrefix)
答案 3 :(得分:4)
这是一个很好的问题,但要实现您的目标,可能会有一个解决方案 这不需要检索Bundle Seed ID。
从这个article开始,您使用的是相同的钥匙串包装器:
默认情况下,它会选择您指定的第一个访问组 写作时将获得Entitlements.plist,并将搜索所有内容 没有指定时访问组。
然后,密钥将在授予访问权限的所有组中进行搜索。 因此,要解决您的问题,您可以将所有捆绑应用的访问组添加到您的entitlements.plist中,而不是使用“共享内容”组,将$(CFBundleIdentifier)作为您的第一个钥匙串组(您的密钥链包装器将在此处写入)小组)你已经完成了
答案 4 :(得分:4)
以下是@David H答案的Swift版本:
static func bundleSeedID() -> String? {
let queryLoad: [String: AnyObject] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "bundleSeedID" as AnyObject,
kSecAttrService as String: "" as AnyObject,
kSecReturnAttributes as String: kCFBooleanTrue
]
var result : AnyObject?
var status = withUnsafeMutablePointer(to: &result) {
SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
}
if status == errSecItemNotFound {
status = withUnsafeMutablePointer(to: &result) {
SecItemAdd(queryLoad as CFDictionary, UnsafeMutablePointer($0))
}
}
if status == noErr {
if let resultDict = result as? [String: Any], let accessGroup = resultDict[kSecAttrAccessGroup as String] as? String {
let components = accessGroup.components(separatedBy: ".")
return components.first
}else {
return nil
}
} else {
print("Error getting bundleSeedID to Keychain")
return nil
}
}