以编程方式访问应用程序标识符前缀

如何以编程方式访问Bundle Seed ID / Team ID / App Identifier Prefixstring? (据我所知,这些都是一样的东西)。

我正在使用UICKeychainStore钥匙串包装器将数据保存在多个应用程序中。 这些应用程序中的每个应用程序在其授权plists中都有一个共享的钥匙串访问组,并共享相同的设置configuration文件。 默认情况下,钥匙串服务使用plist中的第一个访问组作为存储数据的访问组。 当我debuggingUICKeychainStore时,这看起来像“AS234SDG.com.myCompany.SpecificApp”。 我想设置访问组为“AS234SDG.com.myCompany.SharedStuff”,但我似乎无法find如何获得编程的访问组的“AS234SDG”string,并希望避免硬编码它如果可能的话。

您可以通过查看现有KeyChain项的访问组属性(即kSecAttrAccessGroup )以编程方式检索Bundle Seed ID。 在下面的代码中,我查找现有的KeyChain条目并创build一个,如果它不存在。 一旦我有一个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; } 

Info.plist可以有你自己的信息,如果你用$(AppIdentifierPrefix)写一个值,它会在构build阶段被replace成真正的应用程序标识符前缀。

所以,试试这个:

在Info.plist中,添加有关应用程序标识符前缀的信息。

 <key>AppIdentifierPrefix</key> <string>$(AppIdentifierPrefix)</string> 

然后您可以通过编程方式检索它。

 NSString *appIdentifierPrefix = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"AppIdentifierPrefix"]; 

请注意, appIdentifierPrefixappIdentifierPrefix结尾; 如AS234SDG.

这是一个很好的问题,但要实现你打算做的事情,可能有一个解决scheme,不需要检索捆绑种子ID。

从这篇文章 ,你正在使用相同的钥匙串包装:

默认情况下,它将在写入时挑选Entitlements.plist中指定的第一个访问组,并在没有指定任何访问组时search所有访问组。

然后,密钥将在所有授予访问权限的组中进行search。 因此,要解决您的问题,您可以将所有捆绑包应用程序的访问组添加到您的entitlements.plist中,而不是使用“共享东西”组,将$(CFBundleIdentifier)作为您的第一个钥匙串组(您的钥匙串包装器将写入此小组),你们都准备好了

在swift3中:(基于@Hiron解决scheme)

只需一行:

 var appIdentifierPrefix = Bundle.main.infoDictionary!["AppIdentifierPrefix"] as! String 

鉴于在Info.plist中,添加以下键值属性:

键:AppIdentifierPrefix

string值:$(AppIdentifierPrefix)

这里是@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? Dictionary<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 } }