我正在尝试在我的 android 项目中实现 Google+ 注册。我有一个A
带有静态字段loginCredentials
和按钮的活动。按下按钮时,L
将启动活动并检查是否A.loginCredentials.isLogged() == false
使用 Google 登录或在 true 上显示登录/撤销消息。
但是,我需要按两次登录按钮才能登录。这是调试器的日志:第一次单击后:
08-08 10:23:04.925: D/DEBUG(28107): onCreate
08-08 10:23:04.975: D/DEBUG(28107): connection failed
08-08 10:23:04.975: D/DEBUG(28107): connection failed - has resolution
08-08 10:23:04.975: D/DEBUG(28107): startResolutionForResult
08-08 10:23:05.415: D/DEBUG(28107): onStop
08-08 10:23:05.606: D/DEBUG(28107): A - onResume
第二次点击后:
08-08 10:24:39.908: D/DEBUG(28107): onCreate
08-08 10:24:40.288: D/DEBUG(28107): onConnected
08-08 10:24:40.288: D/DEBUG(28107): getAndUseAuthTokenInAsyncTask
08-08 10:24:40.318: D/DEBUG(28107): token = xxxxxxxxxxxxxxx
08-08 10:24:40.318: D/DEBUG(28107): returnResultAndFinish
08-08 10:24:40.368: D/DEBUG(28107): A - onResume
08-08 10:24:40.448: D/DEBUG(28107): onStop
调用startResolutionForResult()
等待对话框后显示一秒钟,然后 L 活动神秘地停止,而 A 活动再次处于活动状态。这就是三星 Galaxy S4 的情况。
但是,在 Nexus V7 上它工作得很好,在第一个按钮单击后就是日志:
08-08 12:01:24.967: D/DEBUG(19455): onCreate
08-08 12:01:25.007: D/DEBUG(19455): connection failed
08-08 12:01:25.007: D/DEBUG(19455): connection failed - has resolution
08-08 12:01:25.007: D/DEBUG(19455): startResolutionForResult
08-08 12:01:25.377: D/DEBUG(19455): L: on activity result
08-08 12:01:25.667: D/DEBUG(19455): onConnected
08-08 12:01:25.667: D/DEBUG(19455): getAndUseAuthTokenInAsyncTask
08-08 12:01:25.687: D/DEBUG(19455): token = xxxxxxxx
08-08 12:01:25.687: D/DEBUG(19455): returnResultAndFinish
08-08 12:01:25.717: D/DEBUG(19455): A - onResume
你能给我一些提示吗?我以其他人的方式使用这些方法。这是代码:
一类:
package com.example.googlelogintest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class A extends Activity implements OnClickListener {
public static LoginCredentials loginCredentials = new LoginCredentials();
static final String TAG = "DEBUG";
static final int CODE_LOGIN = 100;
Button btnLogin;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_a);
btnLogin = (Button)findViewById(R.id.btnLogin);
btnLogin.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == btnLogin) {
Intent intent = new Intent(A.this, L.class);
startActivityForResult(intent, CODE_LOGIN);
}
}
@Override
protected void onResume() {
Log.d(TAG, "A - onResume");
super.onResume();
if (loginCredentials.isLogged()) {
btnLogin.setText(String.format("Log out (%s)", loginCredentials.getLoggedAs()));
}
else {
btnLogin.setText("Log in");
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
Log.d(TAG, "A: on activity result");
if (requestCode == CODE_LOGIN) {
Log.d(TAG, "A: on activity result CODE_LOGIN, resultCode=" + Integer.toString(resultCode));
}
}
}
L.类:
package com.example.googlelogintest;
import java.io.IOException;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.GooglePlayServicesAvailabilityException;
import com.google.android.gms.auth.UserRecoverableAuthException;
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.GooglePlayServicesUtil;
import com.google.android.gms.plus.PlusClient;
import com.google.android.gms.plus.PlusClient.OnAccessRevokedListener;
public class L extends Activity implements
ConnectionCallbacks, OnConnectionFailedListener {
static final int REQUEST_CODE_RESOLVE_ERR = 100;
static final int MY_ACTIVITYS_AUTH_REQUEST_CODE = 101;
static final String TAG = "DEBUG";
static final String G_PLUS_SCOPE = "oauth2:https://www.googleapis.com/auth/plus.me";
static final String USERINFO_SCOPE = "https://www.googleapis.com/auth/userinfo.profile";
static final String EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email";
static final String SCOPES = G_PLUS_SCOPE + " " + USERINFO_SCOPE + " " + EMAIL_SCOPE;
LoginCredentials loginCredentials = new LoginCredentials();
PlusClient plusClient;
boolean alreadyShown = false,
alreadyShown2 = false;
enum Action {
LOGIN, LOGOUT, REVOKE
};
Action action;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_l);
if (GooglePlayServicesUtil
.isGooglePlayServicesAvailable(getApplicationContext()) != ConnectionResult.SUCCESS) {
Toast.makeText(this, "No google services found",
Toast.LENGTH_LONG).show();
returnResultAndFinish();
}
plusClient = new PlusClient.Builder(this, this, this)
.setVisibleActivities("http://schemas.google.com/AddActivity",
"http://schemas.google.com/BuyActivity").build();
Log.d(TAG, "onCreate");
if (!A.loginCredentials.isLogged()) {
action = Action.LOGIN;
plusClient.connect();
}
else
displLoginRevokeDialog();
}
void displLoginRevokeDialog() {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
action = Action.LOGOUT;
break;
case DialogInterface.BUTTON_NEGATIVE:
action = Action.REVOKE;
break;
}
plusClient.connect();
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Logout or revoke?").setPositiveButton("logout", dialogClickListener)
.setNegativeButton("revoke", dialogClickListener).show();
}
@Override
protected void onStop() {
Log.d(TAG, "onStop");
super.onStop();
plusClient.disconnect();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
// The user clicked the sign-in button already. Start to resolve
// connection errors. Wait until onConnected() to dismiss the
// connection dialog.
Log.d(TAG, "connection failed");
if (result.hasResolution()) {
Log.d(TAG, "connection failed - has resolution");
try {
Log.d(TAG, "startResolutionForResult");
result.startResolutionForResult(this, REQUEST_CODE_RESOLVE_ERR);
alreadyShown2 = true;
}
catch (SendIntentException e) {
Log.d(TAG, "exception");
plusClient.connect();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
Log.d(TAG, "L: on activity result");
if (requestCode == REQUEST_CODE_RESOLVE_ERR && resultCode == RESULT_OK) {
plusClient.connect();
}
else if (requestCode == MY_ACTIVITYS_AUTH_REQUEST_CODE
&& resultCode == RESULT_OK) {
getAndUseAuthTokenInAsyncTask();
}
}
public void logOut() {
plusClient.clearDefaultAccount();
plusClient.disconnect();
returnResultAndFinish();
}
public void logIn() {
loginCredentials.setLoggedAs(plusClient.getAccountName());
getAndUseAuthTokenInAsyncTask();
}
public void revoke() {
// Prior to disconnecting, run clearDefaultAccount().
plusClient.clearDefaultAccount();
plusClient.revokeAccessAndDisconnect(new OnAccessRevokedListener() {
@Override
public void onAccessRevoked(ConnectionResult status) {
// mPlusClient is now disconnected and access has been revoked.
// Trigger app logic to comply with the developer policies
returnResultAndFinish();
}
});
}
@Override
public void onConnected(Bundle bundle) {
Log.d(TAG, "onConnected");
switch (action) {
case LOGIN:
action = null;
logIn();
break;
case LOGOUT:
action = null;
logOut();
break;
case REVOKE:
action = null;
revoke();
break;
}
}
@Override
public void onDisconnected() {
Log.d(TAG, "onDisconnected");
}
// Example of how to use the GoogleAuthUtil in a blocking, non-main thread
// context
String getAndUseAuthTokenBlocking() {
try {
// Retrieve a token for the given account and scope. It will always
// return either
// a non-empty String or throw an exception.
final String token = GoogleAuthUtil.getToken(
getApplicationContext(), loginCredentials.loggedAs,
SCOPES);
return token;
}
catch (GooglePlayServicesAvailabilityException playEx) {
Dialog alert = GooglePlayServicesUtil.getErrorDialog(
playEx.getConnectionStatusCode(), this,
MY_ACTIVITYS_AUTH_REQUEST_CODE);
alert.show();
}
catch (UserRecoverableAuthException userAuthEx) {
if (alreadyShown) {
return null;
}
alreadyShown = true;
// Start the user recoverable action using the intent returned by
// getIntent()
startActivityForResult(userAuthEx.getIntent(),
MY_ACTIVITYS_AUTH_REQUEST_CODE);
}
catch (IOException transientEx) {
// network or server error, the call is expected to succeed if you
// try again later.
// Don't attempt to call again immediately - the request is likely
// to
// fail, you'll hit quotas or back-off.
}
catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should
// not be
// retried.
}
return null;
}
// Example of how to use AsyncTask to call blocking code on a background
// thread.
void getAndUseAuthTokenInAsyncTask() {
Log.d(TAG, "getAndUseAuthTokenInAsyncTask");
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
String token = getAndUseAuthTokenBlocking();
if (token == null) {
loginCredentials.setLogged(false);
}
else {
loginCredentials.setToken(token);
loginCredentials.setLogged(true);
}
Log.d(TAG, "token = " + loginCredentials.getToken());
return null;
}
@Override
protected void onPostExecute(Void result) {
returnResultAndFinish();
}
};
task.execute();
}
void returnResultAndFinish() {
Log.d(TAG, "returnResultAndFinish");
A.loginCredentials = loginCredentials;
finish();
}
}
登录凭据.java
package com.example.googlelogintest;
public class LoginCredentials {
boolean isLogged = false;
String loggedAs = "";
String token = "";
public boolean isLogged() {
return isLogged;
}
public void setLogged(boolean isLogged) {
this.isLogged = isLogged;
}
public String getLoggedAs() {
return loggedAs;
}
public void setLoggedAs(String loggedAs) {
this.loggedAs = loggedAs;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}