22

I am trying to create a share extension for my application which requires to login to Google from the extension. I've setup the sharing group keychain and am able to write from the main application and read the extension target. But I can't login to Google from the extension because GIDSignIn.sharedInstance().hasAuthInKeychain() always returns false.

Is there any way to login to Google from an extension and how do I do that? Any help would be appreciated.

Pandalover
  • 2,388
  • 3
  • 21
  • 19
sahara108
  • 2,829
  • 1
  • 22
  • 41
  • You need to go with Action extension you can't do that in Share- extension There are some restrictions for extensions Please refer this link----http://stackoverflow.com/questions/35626898/scan-functionality-doesnt-work-on-action-extensionno-camera-opening-to-scan – Sanju Aug 29 '16 at 05:39
  • Hmm, I am not sure. The only thing here is how google framework handle the keychain. But I will give it a try. Thanks – sahara108 Aug 29 '16 at 07:35

3 Answers3

5

1. In Bridging-Header.h

import <GoogleSignIn/GoogleSignIn.h>
import <Google/Core.h>

2. In AppDelegate.swift

import Google

In application:didFinishLaunchingWithOptionslaunchOptions: configure the GGLContext object:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var configureError: NSError?
        GGLContext.sharedInstance().configureWithError(&configureError)
        assert(configureError == nil, "Error configuring Google services: \(configureError)")
        GIDSignIn.sharedInstance().clientID = "client id"
        GIDSignIn.sharedInstance.shouldFetchBasicProfile = true
        GIDSignIn.sharedInstance().delegate = self
}

Then, add a GIDSignInButton view to your app.

Lastly, in the view controller, implement the signIn:didSignInForUser: delegate method that will be called when the sign-in button is tapped: when authorizing the app.

- (void)signIn:(GIDSignIn *)signIn
    didSignInForUser:(GIDGoogleUser *)user
           withError:(NSError *)error {
  // Perform any operations on signed in user here.
  // ...
}

3. Sharing Credentials between apps/extensions

When you sign-in the Google framework will have to use native iOS methods to add the new credentials to the iOS Keychain. Thus they will be using the SecItemAdd(_:_:) method that will add one or more items to a keychain.

To access the same keychain item in both the app and the extension, you need to enable the "Keychain Sharing" for both the app and the extension from the Xcode's Capabilities section in your project settings. When you do this, Xcode will probably want to update your app ID and provisioning profiles, because they need to reflect this new capability. You'll probably have to reauthorize the app (Step 2) to get the credentials into the right group.

Apple Documentation clearly states:

If you want the new keychain item to be shared among multiple applications, include the kSecAttrAccessGroup key in the attributes dictionary. The value of this key must be the name of a keychain access group to which all of the programs that will share this item belong.

When you use Xcode to create an application, Xcode adds an application-identifier entitlement to the application bundle. Keychain Services uses this entitlement to grant the application access to its own keychain items. You can also add a keychain-access-groups entitlement to the application and, in the entitlement property list file, specify an array of keychain access groups to which the application belongs.

4. Extra Hints from Google that I haven't mentioned above.

Please see "Google Sign-In for iOS". Here is sample code to use GIDSignIn:

  1. Get a reference to the GIDSignIn shared instance: GIDSignIn *signIn = [GIDSignIn sharedInstance];
  2. Set the OAuth 2.0 scopes you want to request: [signIn setScopes:[NSArray arrayWithObject:@"https://www.googleapis.com/auth/plus.login"]];
  3. Call [signIn setDelegate:self];
  4. Set up delegate method signIn:didSignInForUser:withError:.
  5. Call handleURL on the shared instance from application:openUrl:... in your app delegate.
  6. Call signIn on the shared instance;
TechSeeko
  • 1,521
  • 10
  • 19
  • 1
    Thank you for your answer. But the section 3 is not relevant. I did enable sharing keychain but the problem is that GIDSignIn somehow doesn't have credential in the share extension. Is there anyway to overwrite the keychain behaviour of GIDSignIn? – sahara108 Sep 05 '16 at 02:32
  • There is a way if you plan on using Google Plus Sign In instead of Google Sign In. GPPSignIn saves the credentials in the keychain but you can call .keychainName in both the extension and the app to specify the same group you want to retrieve the credentials from. Anyhow, to refresh the token and give access to the extension you need to call the signInSilently (or it's equivalent in GPPSignIn). I'll let you know if I find anything else specific to GIDSIgnIn. – TechSeeko Sep 05 '16 at 06:57
  • With GIDSignIn I can use this `GIDSignIn.sharedInstance().setValue(kGoogleClientKeychainname, forKey: "_keychainName") //GIDSignIn._keychainName`. But it doesn't help at all. – sahara108 Sep 05 '16 at 06:58
  • Also Google+ SignIn is deprecated @sahara108, See https://developers.google.com/+/mobile/ios/sign-in – David Jan 18 '17 at 12:19
  • is keychain sharing still an option since GIDSignIn 5.0.0? GIDSignIn doesn't seem to write to keychain or at least specify it. – NSRover Sep 08 '20 at 18:32
0

To do this you need to enable Keychain Sharing in your project's "Capabilities" pane. This will allow both the extension and the main app to share the password.

Apple's documentation on Keychain Sharing is here.

Casey
  • 6,531
  • 24
  • 43
0

No answer until now. I finally rewrite the Google login by using Aerogear framework. Now I can able to login from both main target and extension target. This also fix this google logout issue.

sahara108
  • 2,829
  • 1
  • 22
  • 41