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.
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
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();
}
}