问题
I have an app(app1) which is in appstore with bundle id com.x.y Now i was developing another app(app2) under same developer account with bundle id com.x.z
I wanted to make the keychain value stored in app1 available to app2.
This availablity of keychain is determined by keychain-access-groups. so if i add prefix( current Team id) to both the bundle id i am able to get the values. example teamid.com.x.y teamid.com.x.z
Issue is When i add the prefix to app1 which is in appstore, it ask for login credentials again which i dont want as app has lots of users. I wasn't using prefix earlier i just added them. Is there a way i could get the keychain access for both the apps without having user to login again.
回答1:
First, it's important to realize that Xcode is already adding the AppIdentifierPrefix to your identifier. It unfortunately hides it in the GUI, but if you open the entitlements plist, you'll see it. This is the identifier that is used to sign the app, and it's the piece that is used to enforce access control. I don't believe the teamid
prefix you're adding really does anything. I generally would recommend an access group com.x.shared
or com.x.appgroup.shared
and not use com.x.z
(I'm assuming com.x.y
already exists, so you can't change that).
I'm assuming here that you don't want to have to force users to upgrade App1, correct? I'm moving forward on that assumption.
If you can upgrade App1 (not require an upgrade, but make sure that all new customers have an upgraded version), then only store in com.x.y
if it exists. Otherwise, store in com.x.shared
:
- When you read from the keychain, don't use an access group. This will get the first matching record.
- When you write to the keychain, use the access group that was in the record you read.
If you don't want to upgrade App1 at all right now (required or not), then just always read and write to com.x.y
in App2.
When you're ready to end-of-life the com.x.y
group (if you're able to finally upgrade all App1 supported users), then you can switch to:
- Read from
com.x.y
. If it's found, delete it, and recreate it ascom.x.shared
. You can do this one-time in the application startup (just write anNSUserDefaults
that says you've done it. - From then on, always use
com.x.shared
explicitly.
The key tool here is that when you ask for an explicitly access group, you have to provide the whole thing, including you AppId (which isn't displayed in the Xcode GUI). You can of course hard-code it, but a better solution is to dynamically query it. I use an updated version of 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;
}
This will tell you your prefix at runtime. It does so b creating a bogus keychain entry, then querying it and seeing what access group was attached to it.
You may be interested in the first section of Getting Security and Privacy Right from Renaissance.io 2014. You can skip to "Protecting Secrets with Keychain."
来源:https://stackoverflow.com/questions/32183189/adding-prefix-to-your-current-bundle-id-resets-the-keychain