Search code examples
iphoneobjective-cioscocoa-touchipad

Access App Identifier Prefix programmatically


How can I access the Bundle Seed ID/Team ID/App Identifier Prefix string programmatically? (These are all the same thing as far as I can tell).

I am using the UICKeychainStore keychain wrapper to persist data across several applications. Each of these applications has a shared keychain access group in their entitlement plists, and share the same provisioning profile. By default, the keychain services use the first access group in the plist as the access group to save data to. This looks like "AS234SDG.com.myCompany.SpecificApp" when I debug UICKeychainStore. I would like to set the access group to "AS234SDG.com.myCompany.SharedStuff", but I can't seem to locate how to get the "AS234SDG" string of the access group programmatically, and would like to avoid hard-coding it if possible.


Solution

  • You can programmatically retrieve the Bundle Seed ID by looking at the access group attribute (i.e. kSecAttrAccessGroup) of an existing KeyChain item. In the code below, I look up for an existing KeyChain entry and create one if it doesn't not exist. Once I have a KeyChain entry, I extract the access group information from it and return the access group's first component separated by "." (period) as the Bundle Seed ID.

    + (NSString *)bundleSeedID {
        NSString *tempAccountName = @"bundleSeedID";
        NSDictionary *query = @{
            (__bridge NSString *)kSecClass : (__bridge NSString *)kSecClassGenericPassword,
            (__bridge NSString *)kSecAttrAccount : tempAccountName,
            (__bridge NSString *)kSecAttrService : @"",
            (__bridge NSString *)kSecReturnAttributes: (__bridge NSNumber *)kCFBooleanTrue,
        };
        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;
        }
        status = SecItemDelete((__bridge CFDictionaryRef)query); // remove temp item
        NSDictionary *dict = (__bridge_transfer NSDictionary *)result;
        NSString *accessGroup = dict[(__bridge NSString *)kSecAttrAccessGroup];
        NSArray *components = [accessGroup componentsSeparatedByString:@"."];
        NSString *bundleSeedID = [[components objectEnumerator] nextObject];
        return bundleSeedID;
    }