We use Dropbox Datastore API in our application and it works correctly. We've decided to add a iOS8 widget to our app. But we can't access to app datastore from it. We followed Datastore API install guide, except that you can't add URL Schema to a widget. What is problem?
UPDATE 1
When the below code (in the widget) runs, it returns nil:
DBAccount *account = [[DBAccountManager sharedManager] linkedAccount];
So I think Dropbox SDK can't retrieval authentication data, which it has saved when authentication is done at host app. Where does dropbox save these information? In keychain? Can I get access token from the host app and use it directly in widget? Because widgets can show a UIViewController for doing authentication.
UPDATE 2
I read Dropbox Core API source code. It seems dropbox saves authentication information in keychain. So I set a keychain group for host app and widget. I tested and both of them can read and write on same keychain. But still [[DBAccountManager sharedManager] linkedAccount] on the widget returns null and on the host app return linked account!
setting a keychain group was the first step to be able to use Dropbox account from your extension, but you also have to make a modification in DBKeychain-iOS.m !
By default it's setting kSecAttrService to something build with application's bundle identifier !
In your main app it will be "com.coybit.myapp" but in you extension it will be "com.coybit.myapp.extensionName" !
You can hardcode the kSecAttrService value to com.coybit.myapp.dropbox.auth or use a method that will only keep the first 3 elements of the bundle identifier to build kSecAttrService :
+ (NSString *)mainBundleName
{
// Always return main application bundle name (for app extensions, remove last component)
NSMutableArray *components = [NSMutableArray arrayWithArray:[[[NSBundle mainBundle] bundleIdentifier] componentsSeparatedByString:@"."]];
while ([components count] > 3) {
[components removeLastObject];
}
return [components componentsJoinedByString:@"."];
}
The initialize function will then looks like :
+ (void)initialize {
if ([self class] != [DBKeychain class]) return;
NSString *keychainId = [NSString stringWithFormat:@"%@.dropbox.auth", [self mainBundleName]];
kDBKeychainDict = [[NSDictionary alloc] initWithObjectsAndKeys:
(id)kSecClassGenericPassword, (id)kSecClass,
keychainId, (id)kSecAttrService,
#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
@"keychain_access_group_name",(id)kSecAttrAccessGroup,
#endif
nil];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With