3

We have a website that is currently utilizing google plus signin for registering and logging in users.

This works fine, I'm now trying to integrate google plus signin for our Android app.

EDIT - The Issue is that when the user is new, it asks for permissions twice and this is being tested on a HTC One device - have already seen the question in: Android Google+ integration - repeated UserRecoverableAuthException

So we have created a project where there are two clients - one for web, and one for android.

Our Android app is just a webview to the mobile version of our site, and clicking on the Google Plus button within the webview will fire off a call to the function attemptGooglePlusSignin() within our WebAppInterface class, which subsequently calls the function googlePlusSignin in our Activity class.

googlePlusSignin attempts to get an ID token which we fire off to our backend server in sendGoogleIDToken() which is done via an ajax call from a javascript function. From there we can query our database for the user and log them in if we can find them. googlePlusSignin basically looks like this:

if (mPlusClient.isConnected()) {
    new AsyncTask<Void, Void, Boolean>() {
        @Override
        protected Boolean doInBackground(Void... params) {
            // This will get an ID Token - uses the web client 
            String scope = "audience:server:client_id:<web-client-id>.apps.googleusercontent.com";

            try {
                idToken = GoogleAuthUtil.getToken(getApplicationContext(),
                    mPlusClient.getAccountName(),
                    scope
                    );

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        webView.loadUrl("javascript:sendGoogleIDToken('" + idToken + "', 'android', '" + action + "')");
                    }
                }
            } catch (UserRecoverableAuthException e) {
                Intent recover = e.getIntent();
                startActivityForResult(recover, REQUEST_CODE_RESOLVE_CODE_LOGIN_ERR);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (GoogleAuthException e) {
                e.printStackTrace();
            }
        }
    }.execute();
}

If the user has previously authenticated (existing user from the website version) then this works great and the user is logged in.

This doesn't work when the user is has not previously authenticated (new user). Firstly it seems to ask for permissions once the user has selected which google account to sign into. This message is something like " needs permissions..." and the user can select 'Sign In' or 'Cancel'. Once the customer selects 'Sign In' the Token ID is sent to our backend server where it reports the user was not found. The callback from the ajax call will then call another function from the WebAppInterface which calls getOneTimeAuthCode() in the Activity class.

public void getOneTimeAuthCode(final String action)
{
    new AsyncTask<Void, Void, Boolean>() {
    @Override
    protected Boolean doInBackground(Void... params) {
        // This will get a One-Time Authorization Code.
        String scope = "oauth2:server:client_id:<web-client-id>:api_scope:" + PLUS_LOGIN_SCOPE + " " + PLUS_EMAIL_SCOPE;
        try {
            oneTimeAuthCode = GoogleAuthUtil.getToken(getApplicationContext(),
                mPlusClient.getAccountName(),
                scope
                );

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    webView.loadUrl("javascript:sendGoogleOneTimeAuthCode('" + oneTimeAuthCode + "', 'android', '" + action + "')");
                }
            });
        } catch (UserRecoverableAuthException e) {
            Intent recover = e.getIntent();
            startActivityForResult(recover, REQUEST_CODE_RESOLVE_CODE_LOGIN_ERR);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (GoogleAuthException e) {
            e.printStackTrace();
        }
    }.execute();           
}

Trying to get the one-time auth code throws a UserRecoverableAuthException - which then again asks for permissions, then the google plus app seems to launch with the message "signing in" and then it again asks you for permissions which you click 'sign in' to accept... then the whole app crashes with the Log error of:

EDIT - This Error was the result of a mistake in my onActivityResult method, please ignore this now

E/AndroidRuntime(6917): FATAL EXCEPTION: main E/AndroidRuntime(6917): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=9003, result=-1, data=Intent { (has extras) }} to activity {com.xxxx/com.xxxx.MainActivity}: java.lang.NullPointerException E/AndroidRuntime(6917): at android.app.ActivityThread.deliverResults(ActivityThread.java:3849)

So... there are two problems really

EDIT - the only problem is the first point now.

  1. It asks for permissions twice, which could be because I'm using the PlusClient from the google plus sdk, and then using the web servers client id in the getToken call

  2. For some reason it errors because it can't find my onActivityResult function within my Activity class for the startActivityForResult call in getOneTimeAuthCode().

I am testing on a HTC One.

I could be going about this in the wrong way, but I can't seem to find a clear way of achieving what I want here, does anybody have any ideas? Any help whatsoever would be greatfully received been struggling with this for a while now!

Cheers

EDIT - Here is a shortened copy of the Activity which may help aswell

public class MainActivity extends Activity implements
    ConnectionCallbacks, OnConnectionFailedListener
{
@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ...

    mPlusClient = new PlusClient.Builder(this, this, this)
                   .setScopes(PLUS_LOGIN_SCOPE, PLUS_EMAIL_SCOPE) //recommended login scope for social features
                   .build();
    // Progress bar to be displayed if the connection failure is not resolved.
    mConnectionProgressDialog = new ProgressDialog(this);
    mConnectionProgressDialog.setMessage("Signing in...");
    mPlusClient.connect();

    ...
}

@Override
public void onConnectionFailed(ConnectionResult result) {
    // Save the result and resolve the connection failure upon a user click.
    mConnectionResult = result;

    if (mGooglePlusSignInClick)
    {
        googlePlusSignin();
    }
}

@Override
public void onConnected(Bundle connectionHint) {
    mConnectionResult = null;

    if (mGooglePlusSignInClick)
    {
        googlePlusSignin();
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
{
    // this is when the user has had to sign into their account and/or give permissions
    if (requestCode == REQUEST_CODE_RESOLVE_CONNECT_ERR)
    {
        if (resultCode == RESULT_OK)
        {
            mConnectionResult = null;
            if (mGooglePlusSignInClick)
            {
                googlePlusSignin();
            }
        }
    }
    else if (requestCode == REQUEST_CODE_RESOLVE_CODE_LOGIN_ERR)
    {
        if (resultCode == RESULT_OK)
        {
            mConnectionResult = null;
            if (mGooglePlusSignInClick)
            {
                googlePlusSignin();
            }
        }
    }
}

public void googlePlusSignin()
{
    mGooglePlusSignInClick = 1;

    if (mConnectionResult != null)
    {   
        if (mConnectionResult.hasResolution())
        {
            try {
                mConnectionResult.startResolutionForResult(this, REQUEST_CODE_RESOLVE_CONNECT_ERR);
            } catch (SendIntentException e) {
                mConnectionResult = null;
            }
        }
    }
    else
    {
        if (mPlusClient.isConnected())
        {           
            new AsyncTask<Void, Void, Boolean>()
            {   
                @Override
                protected Boolean doInBackground(Void... params)
                {
                    // This will get an ID Token
                    String scope = "audience:server:client_id:<web-component-client-id>";
                    try {
                         idToken = GoogleAuthUtil.getToken(getApplicationContext(),
                                    mPlusClient.getAccountName(),
                                    scope
                         );

                         runOnUiThread(new Runnable() 
                         {                  
                             @Override
                             public void run() 
                             {
                                 webView.loadUrl("javascript:sendGoogleIDToken('" + idToken + "', 'android')");
                             }
                         });

                     } catch (UserRecoverableAuthException e) {
                         Intent recover = e.getIntent();
                         startActivityForResult(recover, REQUEST_CODE_RESOLVE_CODE_LOGIN_ERR);
                     } catch (IOException e) {
                         e.printStackTrace();
                     } catch (GoogleAuthException e) {
                         e.printStackTrace();
                     }
                     return true;
                 }
             }.execute();
         }
        else
        {
            mPlusClient.connect();
        }
    }
}

public void getOneTimeAuthCode(final String action)
{
    new AsyncTask<Void, Void, Boolean>()
    {   
        @Override
            protected Boolean doInBackground(Void... params)
            {
                // This will get a One-Time Authorization Code.
                String scope = "oauth2:server:client_id:<web-component-client-id>:api_scope:" + PLUS_LOGIN_SCOPE + " " + PLUS_EMAIL_SCOPE;

                try {
                    oneTimeAuthCode = GoogleAuthUtil.getToken(getApplicationContext(),
                                        mPlusClient.getAccountName(),
                                        scope
                    );

                    runOnUiThread(new Runnable() 
                    {                   
                        @Override
                        public void run() 
                        {
                            webView.loadUrl("javascript:sendGoogleOneTimeAuthCode('" + oneTimeAuthCode + "', 'android', '" + action + "')");
                        }
                    });     
                } catch (UserRecoverableAuthException e) {
                    Intent recover = e.getIntent();
                    startActivityForResult(recover, REQUEST_CODE_RESOLVE_CODE_LOGIN_ERR);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (GoogleAuthException e) {
                    e.printStackTrace();
                }
                return true;
            }
        }.execute();
    }
}
Community
  • 1
  • 1
David Brent
  • 115
  • 7
  • Does your activity have the activity result method? Maybe you should post that entire activity. – cbrulak Jan 03 '14 at 16:42
  • Yes my onActivityResult is not even reached before the error is thrown. onActivityResult is successfully called in the first code sample for sendGoogleIDToken() which gets the ID Token. onActivityResult is not reached for the second code sample which is trying to get the one-time auth code getOneTimeAuthCode() – David Brent Jan 03 '14 at 16:43
  • I'm wondering if this is because you are calling startActivytForResult from within an anonymous class. Try doing this in the begin on the getOneTimeAuthCode method: final Activity parent = this; then in the catch block, do: parent.startActivity..... No guarantees :) – cbrulak Jan 03 '14 at 18:51
  • can you post more of your error log output? The whole stack trace would be helpful. – cbrulak Jan 03 '14 at 18:52
  • Thanks for your reply cbrulak. It appears to work without error now, I think this is because I wasn't handling the identifier that was getting sent with the startActivityForResult... I didn't think that would cause it to error, my apologies for that mistake. I am still having the problems with it asking for permissions twice though, so I've included a shortened version of the activity class in the question aswell. Thanks again – David Brent Jan 05 '14 at 18:52
  • hi,where do i get REQUEST_CODE_RESOLVE_CODE_LOGIN_ERR from ? – Rat-a-tat-a-tat Ratatouille Mar 01 '15 at 08:21

0 Answers0