Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Plus Sign in iOS using UIWebView

I am using google+ sign in my app using the Google Plus SDK. When the user taps on the sign in button the user gets redirected to safari. (Standard Process).

However Apple seems to have changed some rules for this. My App was rejected due to this, stating the following

The app launches mobile Safari to complete signing into Google+ before returning to the app. However, the use should not have to exit the app to use it.

To resolve the issue, it would be appropriate to revise your app to allow the user to log through the app, to create another authentication method for your app, or to remove this requirement from using your app

Is someone else facing the same issue and has a solution? A work around could be using a UIWebView and use the OAuth Access Token. However this fails to provide me a Single Sign On feature. Also does anyone know how to share an image using the Access Token (Without SDK features). I have found the GTMOAuth2ViewControllerTouch file in the sdk but still no luck with it. Can anyone help me with this class?

like image 917
rameez Avatar asked Jun 16 '14 12:06

rameez


People also ask

Does Chrome iOS use UIWebView?

As of version 48, Chrome for iOS uses WKWebView, which is the same view used in Safari.

Can I still use UIWebView?

UIWebView APIs are still supported in the upcoming iOS 13 release as well as macOS Catalina but are still going away in future releases. Sometime in the future, iOS apps may be blocked from release to the App Store when Apple decides to enforce blocking apps that use UIWebView.

Can I use WebView in iOS?

WebView can be defined as an object which can display the interactive web content and load HTML strings within the iOS application for an in-app browser. It is an instance of the WKWebView class, which inherits the UIView class.

How do I sign into Google on iOS?

On your iPhone or iPad, open the Safari app. Go to www.google.com. Tap your profile image or Sign in. Follow the sign-in steps.


2 Answers

Update

Google has released a new iOS SDK that does supports WebView Sign In, among several other updates and features. (Thanks to John Hjelmstad and Co for working on this)

Original Post

I recommend strongly against using the outdated GTMAuth2Controller. If you really want this feature please add your voice to the official Google thread. The more voices we add there the higher the chance that Google will introduce this feature. Currently Apple are rejecting all Apps that force the user to flip flop from Safari to your App for Google+ Sign In. Even though Apple are aware that this is how Googles SDK does this (Nevermind the fact that Facebook does the same but won't get your app rejected).

Its petty and lame but unfortunately all we can do is appeal to Google to add support for this.

Here's what Google had to say about this issue (I also protested the use of their outdated controller)

Hi all -- at Google, we aim to make our services available to as many users and developers as possible. We have heard a very small number of reports of problems of this type, but those app developers appear to have eventually gotten approval to launch by working through Apple’s standard process.

Meantime, we're continuing to work on improved mechanisms for login. I do agree with Daniel that direct use of GTMOauth2ViewControllerTouch, or the equivalent UIWebView trickery, is not recommended. Oct 16, 2014

like image 170
Daniel Galasko Avatar answered Oct 18 '22 15:10

Daniel Galasko


I tried merging sample apps for Gmail API and GooglePlus to use UIWebView login instead of Safari and it seems to work:

  1. create google project BUT when setting up credentials Installed application type choose Other
  2. add/enable Google+ API to your google project
  3. add/enable Gmail API to google project
  4. follow Google+ instructions and add all frameworks and drag ONE BY ONE GoogleOpenSource.framework, GooglePlus.framework and GooglePlus.bundle (you may not need this since we are not using SignInButton, well just in case it is there) in your project
  5. add other linker flags -all_load -ObjC, disable ARC
  6. DRAG GTMOAuth2ViewTouch.xib into your project files (from OAuth2)

enter image description here

my viewcontroller .h file I added 2 buttons to login and retrieve data, textview to display retrieved data, connected them in the builder. ALSO added interface and property for GTMOAuth2Authentication:

#import <UIKit/UIKit.h>
#import <GoogleOpenSource/GoogleOpenSource.h>
#import <GooglePlus/GooglePlus.h>

@interface MyViewController : UIViewController{
IBOutlet UIButton *loginBttn;
IBOutlet UIButton *retriveBttn;
IBOutlet UITextView *profileTextView;

GTMOAuth2Authentication *mAuth;
}

@property (retain, nonatomic) IBOutlet UIButton *loginBttn;
@property (retain, nonatomic) IBOutlet UIButton *retriveBttn;
@property (nonatomic, retain) IBOutlet UITextView *profileTextView;

@property (nonatomic, retain) GTMOAuth2Authentication *auth;

-(IBAction)dologin;
-(IBAction)doretrive;

@end

my viewcontroller .m file:

#import "MyViewController.h"
#import "AppDelegate.h"
#import <GoogleOpenSource/GoogleOpenSource.h>
#import <GooglePlus/GooglePlus.h>

static NSString *const kKeychainItemName = @"Google OAuth2 For gglplustest";
static NSString *const kClientID = @"your client id";
static NSString *const kClientSecret = @"your client secret";

@interface MyViewController ()
@end

@implementation MyViewController
@synthesize loginBttn,retriveBttn;
@synthesize auth = mAuth;
@synthesize profileTextView;

-(IBAction)doretrive{
    GTLServicePlus* plusService = [[[GTLServicePlus alloc] init] autorelease];
    plusService.retryEnabled = YES;

    [plusService setAuthorizer:self.auth];//!!!here use our authentication object!!!

    GTLQueryPlus *query = [GTLQueryPlus queryForPeopleGetWithUserId:@"me"];

    [plusService executeQuery:query
            completionHandler:^(GTLServiceTicket *ticket,
                                GTLPlusPerson *person,
                                NSError *error) {
                if (error) {
                    GTMLoggerError(@"Error: %@", error);
                } else {
                    // Retrieve the display name and "about me" text
                    [person retain];
                    NSString *description = [NSString stringWithFormat:
                                             @"%@\n%@\n%@", person.displayName,
                                             person.aboutMe,person.emails];
                    [profileTextView setText:description];
                }
            }];
}

- (void)auth:(GTMOAuth2Authentication *)auth finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher error:(NSError *)error {
    [self viewController:nil finishedWithAuth:auth error:error];
     if (error != nil) {
     // Refresh failed
         NSLog(@"Authentication Error %@", error.localizedDescription);
         self.auth=nil;
         return;
     }
     self.auth=auth;
}

- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
{
    if (error != nil) {
        // Authentication failed
        NSLog(@"Authentication Error %@", error.localizedDescription);
        self.auth=nil;
        return;
    }
    self.auth=auth;
    [viewController release];//no ARC
}

-(IBAction)dologin{
    NSString *scope = kGTLAuthScopePlusLogin;//Google+ scope
    GTMOAuth2Authentication * auth = [GTMOAuth2ViewControllerTouch 
    authForGoogleFromKeychainForName:kKeychainItemName
    clientID:kClientID
    clientSecret:kClientSecret];
    if ([auth refreshToken] == nil) {
        GTMOAuth2ViewControllerTouch *authController;
        authController = [[GTMOAuth2ViewControllerTouch alloc] 
        initWithScope:scope 
        clientID:kClientID 
        clientSecret:kClientSecret  
        keychainItemName:kKeychainItemName
        delegate:self
        finishedSelector:@selector(viewController:finishedWithAuth:error:)];
        [[self navigationController] pushViewController:authController animated:YES];
    }else{
        [auth beginTokenFetchWithDelegate:self didFinishSelector:@selector(auth:finishedRefreshWithFetcher:error:)];
    }
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

So now, when view is loaded it does not try to login.

Then on a view when I touch loginBttn that will run dologin method (from GmailMail sample) where I setup the scope to GooglePlus: 1st it will check if there is saved info in keychain, if it is, it will proceed without asking you to login. If not, it will do it as for Gmail login in UIWebView directly inside my app.

enter image description here

here how it looks after login:

enter image description here

Then I can touch retriveBttn to run retrieve method (e.g. to get Name, About and emails) that uses GooglePlus sample HOWEVER I set Authorizer to the authenticator that I saved after successful login like that: [plusService setAuthorizer:self.auth];

here is the view before and after retrieve is complete:

enter image description here

enter image description here

Seems like it is doing what is is supposed to.

like image 24
Boris Gafurov Avatar answered Oct 18 '22 16:10

Boris Gafurov