Domanda

I have studied google plus login from https://developers.google.com/+/mobile/android/getting-started

When I launch my app there is a toast message "User is connected!" and then I press G+ Sign in button my app force close.

This is the message form logcat

04-08 18:31:21.680  24231-24231/app.umitems.test.testgoogleplus1.app D/﹕ onClick()
04-08 18:31:21.680  24231-24231/app.umitems.test.testgoogleplus1.app D/AndroidRuntime﹕ Shutting down VM
04-08 18:31:21.680  24231-24231/app.umitems.test.testgoogleplus1.app W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41f99ce0)
04-08 18:31:21.685  24231-24231/app.umitems.test.testgoogleplus1.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: app.umitems.test.testgoogleplus1.app, PID: 24231
    java.lang.NullPointerException
        at app.umitems.test.testgoogleplus1.app.ExampleActivity.resolveSignInError(ExampleActivity.java:68)
        at app.umitems.test.testgoogleplus1.app.ExampleActivity.onClick(ExampleActivity.java:166)
        at com.google.android.gms.common.SignInButton.onClick(Unknown Source)
        at android.view.View.performClick(View.java:4445)
        at android.view.View$PerformClick.run(View.java:18446)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5081)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
        at dalvik.system.NativeStart.main(Native Method)

Here is my code

package app.umitems.test.testgoogleplus1.app;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.plus.Plus;

public class ExampleActivity extends Activity implements
                                          ConnectionCallbacks, 
                                          OnConnectionFailedListener,
                                          GoogleApiClient.ConnectionCallbacks,
                                          GoogleApiClient.OnConnectionFailedListener, 
                                          View.OnClickListener  {

  /* Request code used to invoke sign in user interactions. */
  private static final int RC_SIGN_IN = 0;

  /* Client used to interact with Google APIs. */
  private GoogleApiClient mGoogleApiClient;

  /* A flag indicating that a PendingIntent is in progress and prevents
   * us from starting further intents.
   */
  private boolean mIntentInProgress;

  /* Track whether the sign-in button has been clicked so that we know to resolve
   * all issues preventing sign-in without waiting.
   */
  private boolean mSignInClicked;

  /* Store the connection result from onConnectionFailed callbacks so that we can
   * resolve them when the user clicks sign-in.
   */
  private ConnectionResult mConnectionResult;
  View btn;

  public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_example);

     mGoogleApiClient = new GoogleApiClient.Builder(this)
           .addConnectionCallbacks(this)
           .addOnConnectionFailedListener(this)
           .addApi(Plus.API, null)
           //.addScope(Plus.SCOPE_PLUS_LOGIN)
           .build();

        btn = findViewById(R.id.sign_in_button);
        btn.setOnClickListener(this);
  }

  protected void onStart() {
     super.onStart();
     mGoogleApiClient.connect();
  }

  /* A helper method to resolve the current ConnectionResult error. */
  public void resolveSignInError() {
     Log.d("","resolveSignInError()");
     if (mConnectionResult.hasResolution()) {
        Log.d("","resolveSignInError() mConnectionResult.hasResolution()");
        try {
           mIntentInProgress = true;
           /*startIntentSenderForResult(mConnectionResult.getIntentSender(),
                                      RC_SIGN_IN, null, 0, 0, 0);*/

           mConnectionResult.startResolutionForResult(this, // your activity
                                           RC_SIGN_IN);
        } catch (IntentSender.SendIntentException e) {
           // The intent was canceled before it was sent.  Return to the default
           // state and attempt to connect to get an updated ConnectionResult.
           Log.d("","resolveSignInError() mConnectionResult.hasResolution() catch");
           mIntentInProgress = false;
           mGoogleApiClient.connect();
        }
     }
  }

  protected void onStop() {
     super.onStop();

     if (mGoogleApiClient.isConnected()) {
        mGoogleApiClient.disconnect();
     }
  }

  @Override public void onConnected(Bundle bundle){
     // We've resolved any connection errors.  mGoogleApiClient can be used to
     // access Google APIs on behalf of the user.
     mSignInClicked = false;
     Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
  }

  @Override public void onConnectionSuspended(int i){
     mGoogleApiClient.connect();
  }

  @Override public void onDisconnected(){

  }

  @Override
  public void onConnectionFailed(ConnectionResult result) {
     if (!mIntentInProgress) {
        // Store the ConnectionResult so that we can use it later when the user clicks
        // 'sign-in'.
        mConnectionResult = result;

        if (mSignInClicked) {
           // The user has already clicked 'sign-in' so we attempt to resolve all
           // errors until the user is signed in, or they cancel.
           resolveSignInError();
        }
     }
  }
  /*@Override
  public void onConnectionFailed(ConnectionResult result){
     if (!mIntentInProgress && result.hasResolution()) {
        try {
           mIntentInProgress = true;*//*
           startIntentSenderForResult(result.getIntentSender(),
                                      RC_SIGN_IN, null, 0, 0, 0);*//*

           result.startResolutionForResult(this, // your activity
                                           RC_SIGN_IN);
        } catch (IntentSender.SendIntentException e) {
           // The intent was canceled before it was sent.  Return to the default
           // state and attempt to connect to get an updated ConnectionResult.
           mIntentInProgress = false;
           mGoogleApiClient.connect();
        }
     }
  }*/

  protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
     if (requestCode == RC_SIGN_IN) {
        if (responseCode != RESULT_OK) {
           mSignInClicked = false;
        }

        mIntentInProgress = false;

        if (!mGoogleApiClient.isConnecting()) {
           mGoogleApiClient.connect();
        }
     }
  }

  @Override public void onClick(View view){

     Log.d("","onClick()");
     if (view.getId() == R.id.sign_in_button
         && !mGoogleApiClient.isConnecting()) {
        mSignInClicked = true;
        resolveSignInError();
     }
  }
}

I just found that the app will automatically connected to Google+ without ask any permission. I don't need to press sign in button but I can post via my account. Is this a bug about privacy?

È stato utile?

Soluzione

OK! So that toast is because you have signed in, and when you click you are trying to sign in again: because you don't have a connection result with an error to resolve, you get the NPE.

This is how it works:

  1. Your sign in state is stored in Google Play services.
  2. When you connect, your app connects to Google Play services and tries to see if you have signed in before.
  3. If you have, it calls back to onConnected.
  4. If you have not, it calls back to onConnectionFailed and gives you a ConnectionResult.
  5. When the use clicks sign in, you "resolve the error" on the ConnectionResult - this is just a pending Intent which triggers the account chooser and consent screen.
  6. When the user consents, your app gets called back in onActivityResult, and you reconnect (and the flow starts again, this time ending at step 3).

So, if you get onConnected you should hide the sign in button - the user has signed in!

Now, perhaps for whatever reason you want the user to have to click the button to get started. That's fine too. In the onClick, you just need to test whether mPlusClient isConnected. If it is, go straight to whatever you wanted to do post sign in. If not, then resolve the connection result.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top