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

问题描述 投票:42回答:5

如何以编程方式访问Bundle Seed ID / Team ID / App Identifier Prefix字符串? (就我所知,这些都是一样的)。

我正在使用UICKeychainStore keychain包装器来跨多个应用程序保存数据。这些应用程序中的每一个都在其权利清单中具有共享密钥链访问组,并共享相同的配置文件。默认情况下,钥匙串服务使用plist中的第一个访问组作为保存数据的访问组。当我调试UICKeychainStore时,这看起来像“AS234SDG.com.myCompany.SpecificApp”。我想将访问组设置为“AS234SDG.com.myCompany.SharedStuff”,但我似乎无法找到如何以编程方式获取访问组的“AS234SDG”字符串,并希望避免对其进行硬编码如果可能的话。

iphone objective-c ios cocoa-touch ipad
5个回答
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;
}

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.


6
投票

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

只需一行:

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

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

key:AppIdentifierPrefix

string-value:$(AppIdentifierPrefix)


4
投票

这是一个很好的问题,但要实现您的目标,可能会有一个解决方案,不需要检索Bundle Seed ID。

从这个article,关于你正在使用的相同的钥匙串包装:

默认情况下,它会在编写时选择Entitlements.plist中指定的第一个访问组,并在未指定任何访问组时搜索。

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


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
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.