我是Android新手,想知道如何撤销使用GoogleSignInApi登录我的应用的用户的访问权限。
当用户撤消应用内的访问权限时,我希望我的应用询问用户的Google帐户ID。目前,即使用户点击了撤销访问按钮,我的应用也会在用户点击“登录”按钮后自动登录。
当用户点击我的应用的撤销或退出按钮时,我正在广播一个意图。以下是我的 MainActivity 的代码。
public class MasterActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = MasterActivity.class.getSimpleName();
private SharedPreferences sp;
private SharedPreferences.Editor editor;
private BroadcastReceiver mSignOutReceiver;
private IntentFilter mSignOutFilter;
private IntentFilter mRevokeAccessFilter;
private BroadcastReceiver mRevokeAccessReceiver;
private String mUserName;
private String mPhotoUrl;
private String mEmailId;
private static final String ANONYMOUS = "anonymous";
private ImageView profileImageView;
private TextView profileDisplayName, profileEmailId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// [START Check for sign out broadcast.]
mSignOutFilter = new IntentFilter();
mSignOutFilter.addAction(getString(R.string.action_signout));
mSignOutReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Sign Out in progress.");
Intent signinIntent = new Intent(getApplicationContext(), SigninActivity.class);
startActivity(signinIntent);
finish();
}
};
this.registerReceiver(mSignOutReceiver, mSignOutFilter);
// [END Check for sign out broadcast.]
mRevokeAccessFilter = new IntentFilter();
mRevokeAccessFilter.addAction(getString(R.string.action_revoke));
mRevokeAccessReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Revoke access in progress.");
Intent revokeIntent = new Intent(getApplicationContext(), SigninActivity.class);
startActivity(revokeIntent);
finish();
}
};
this.registerReceiver(mRevokeAccessReceiver, mRevokeAccessFilter);
setContentView(R.layout.activity_master);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
/* FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});*/
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
sp = getSharedPreferences(getString(R.string.user_cred_sp),MODE_PRIVATE);
editor = sp.edit();
if(!sp.contains("USER_ID")){
//Not signed in, launch the Sign In activity
Log.d(TAG, "User id not is present.");
startActivity(new Intent(this, SigninActivity.class));
finish();
return;
} else {
// [START Set the navigation header details]
mUserName = sp.getString("USER_DISPLAY_NAME",ANONYMOUS);
mPhotoUrl = sp.getString("USER_PIC_URL",null);
mEmailId = sp.getString("USER_EMAIL","noemailid@unknown.com");
View headerView = navigationView.inflateHeaderView(R.layout.nav_header_master);
profileDisplayName = (TextView) headerView.findViewById(R.id.UserNameProfile);
profileDisplayName.setText(mUserName);
profileEmailId = (TextView) headerView.findViewById(R.id.EmailIdProfile);
profileEmailId.setText(mEmailId);
profileImageView = (ImageView) headerView.findViewById(R.id.ImageViewProfile);
if(mPhotoUrl!=null){
Glide.with(getApplicationContext()).load(mPhotoUrl)
.thumbnail(0.5f)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(profileImageView);
}
//TODO: The orientation of views and image is not proper
// [END Set the navigation header details]
}
}
/*@Override
protected void onResume(){
super.onResume();
this.registerReceiver(mSignOutReceiver, signOutFilter);
}*/
@Override
protected void onDestroy(){
super.onDestroy();
this.unregisterReceiver(mSignOutReceiver);
this.unregisterReceiver(mRevokeAccessReceiver);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.master, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
} else if (id == R.id.sign_out_menu ){
signOutBroadCast();
return true;
} else if (id == R.id.revoke_menu){
revokeAccessBroadCast();
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_logout) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
private void signOutBroadCast(){
// 1. Clear the shared preference.
editor.clear();
editor.apply();
// 2.Send a sign out broadcast
Intent signOutIntent = new Intent();
signOutIntent.setAction(getString(R.string.action_signout));
sendBroadcast(signOutIntent);
// 3. Start the login Activity
/*Intent signinIntent = new Intent(this,SigninActivity.class);
startActivity(signinIntent);
finish();*/
}
private void revokeAccessBroadCast(){
// 1. Clear the shared preference.
editor.clear();
editor.apply();
// 2.Send a revoke intent.
Intent revokeIntent = new Intent();
revokeIntent.setAction(getString(R.string.action_revoke));
sendBroadcast(revokeIntent);
//signOutBroadCast();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed: "+ connectionResult);
}
}
这是 SignInActivity 的代码。
public class SigninActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, View.OnClickListener,
GoogleApiClient.ConnectionCallbacks{
private static final String TAG = SigninActivity.class.getSimpleName();
private static final int REQ_ACCPICK = 1;
private static final int RC_SIGN_IN = 2;
private GoogleSignInOptions mGoogleSignInOptions;
private GoogleApiClient mGoogleApiClient;
private SharedPreferences sp;
private SharedPreferences.Editor editor;
private IntentFilter mSignOutFilter;
private BroadcastReceiver mSignOutReceiver;
private IntentFilter mRevokeAccessFilter;
private BroadcastReceiver mRevokeAccessReceiver;
private boolean isAccntConnected;
private SignInButton btnSignIn;
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSignOutFilter = new IntentFilter();
mSignOutFilter.addAction(getString(R.string.action_signout));
mSignOutReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
signOutIfConnected();
Log.d(TAG, "Sign out complete.");
}
};
this.registerReceiver(mSignOutReceiver, mSignOutFilter);
mRevokeAccessFilter = new IntentFilter();
mRevokeAccessFilter.addAction(getString(R.string.action_revoke));
mRevokeAccessReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"Revoke access");
revokeAccess();
Log.d(TAG, "Complete access revoked.");
}
};
this.registerReceiver(mRevokeAccessReceiver, mRevokeAccessFilter);
// [START Sign out if connected.]
//signOutIfConnected();
// [END Sign out if connected.]
setContentView(R.layout.activity_signin);
btnSignIn = (SignInButton) findViewById(R.id.btn_sign_in);
btnSignIn.setOnClickListener(this);
// [START Configure sign in]
// configure sign in options for google account
mGoogleSignInOptions= new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
// [END Configure sign in]
isAccntConnected= false;
// [START Build Google api client]
/*mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();*/
// [END Build Google api client]
btnSignIn.setSize(SignInButton.SIZE_STANDARD);
btnSignIn.setScopes(mGoogleSignInOptions.getScopeArray());
sp = getSharedPreferences(getString(R.string.user_cred_sp), MODE_PRIVATE);
editor = sp.edit();
}
/*@Override
protected void onResume(){
super.onResume();
this.registerReceiver(mSignOutReceiver, mSignOutFilter);
this.registerReceiver(mRevokeAccessReceiver, mRevokeAccessFilter);
}*/
/*@Override
protected void onPause(){
super.onPause();
this.unregisterReceiver(mSignOutReceiver);
this.unregisterReceiver(mRevokeAccessReceiver);
}*/
@Override
protected void onDestroy(){
super.onDestroy();
this.unregisterReceiver(mSignOutReceiver);
this.unregisterReceiver(mRevokeAccessReceiver);
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed: " + connectionResult);
}
private void initGAC(){
/*mGoogleSignInOptions= new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.setAccountName(acntName)
.build();*/
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, mGoogleSignInOptions)
//.setAccountName(acntName)
.build();
}
@Override
public void onStart() {
super.onStart();
if(mGoogleApiClient!=null){
OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
if (opr.isDone()) {
// If the user's cached credentials are valid, the OptionalPendingResult will be "done"
// and the GoogleSignInResult will be available instantly.
Log.d(TAG, "Got cached sign in");
GoogleSignInResult result = opr.get();
handleSignInResult(result);
} else {
// If the user has not previously signed in on this device or the sign-in has expired,
// this asynchronous branch will attempt to sign in the user silently. Cross-device
// single sign-on will occur in this branch.
showProgressDialog();
opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
@Override
public void onResult(GoogleSignInResult googleSignInResult) {
hideProgressDialog();
handleSignInResult(googleSignInResult);
}
});
}
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_sign_in) {
signIn();
}
}
private void signIn() {
/*startActivityForResult(AccountPicker.newChooseAccountIntent(
null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null
),REQ_ACCPICK);*/
Log.d(TAG, "Sign in method called.");
initGAC();
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
/*if(requestCode == REQ_ACCPICK){
if(data!=null && data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)!=null){
mEmail = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
initGAC(mEmail);
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
} else*/
if (requestCode == RC_SIGN_IN) {
Log.d(TAG, "Sign in request");
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}
private void handleSignInResult(GoogleSignInResult result) {
Log.d(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// Sign in successful. Show authenticated UI
// Set the data in intent and send it to next activity
GoogleSignInAccount acct = result.getSignInAccount();
Log.d(TAG, "Account Profile URL: "+acct.getPhotoUrl().toString());
String userId = acct.getId();
String userDisplayName = acct.getDisplayName();
String userPhotoUrl = acct.getPhotoUrl().toString();
String userEmail = acct.getEmail();
//Set the id in shared preferences so that it can be used to log out
editor.putString("USER_ID", userId);
editor.putString("USER_DISPLAY_NAME", userDisplayName);
editor.putString("USER_PIC_URL", userPhotoUrl);
editor.putString("USER_EMAIL", userEmail);
editor.commit();
//dataIntent.putExtra("USER_EMAIL",userEmail);
Intent dataIntent = new Intent(this, MasterActivity.class);
startActivity(dataIntent);
}
}
private void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage(getString(R.string.loading));
mProgressDialog.setIndeterminate(true);
}
mProgressDialog.show();
}
private void hideProgressDialog() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.hide();
}
}
private void signOutIfConnected() {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
//mEmail=null;
mGoogleApiClient.clearDefaultAccountAndReconnect();
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
Log.d(TAG, "Sign Out using Google Api.");
mGoogleApiClient.disconnect();
isAccntConnected = false;
}
});
}
}
private void revokeAccess(){
if (mGoogleApiClient != null && mGoogleApiClient.isConnected() && isAccntConnected == true) {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
Log.d(TAG, "Revoke access using Google Api.");
signOutIfConnected();
}
});
}
}
@Override
public void onConnected(@Nullable Bundle bundle) {
this.isAccntConnected = true;
}
@Override
public void onConnectionSuspended(int i) {
}
/*@Override
public void onConnected(@Nullable Bundle bundle) {
if(!sp.contains("USER_ID_TOKEN")){
signOut();
}
}
@Override
public void onConnectionSuspended(int i) {
}*/
}
我可能会遗漏某些东西或者可能做错了什么。请指导我。
答案 0 :(得分:2)
花了两天时间,试图了解Android活动生命周期,我能够找出解决这个问题的方法。上面的代码有两个主要缺陷。
我没有在GoogleApiClient中注册回调。由于此代码不在onConnected(),onConnectionSuspended()和onConnectionFailed()内部流动。解决方案是注册它们,如下所示:
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Auth.GOOGLE_SIGN_IN_API, mGoogleSignInOptions)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
调用onStart
时自动连接GoogleApiClient实例,并在调用onStop
时断开连接。因此,当用户登录我的应用程序时,应用程序会将她带到MasterActivity。一路上,调用了SignInActivity的onStop
方法。此断开连接的GoogleApiClient实例(记住自动管理)。因此解决方案是在我的代码中自己管理它。
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN && resultCode == RESULT_OK) {
Log.d(TAG, "Sign in request");
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
mGoogleApiClient.connect();//CALL TO CONNECT GoogleApiClient
handleSignInResult(result);
}
}
private void signOutIfConnected() {
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.clearDefaultAccountAndReconnect();
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
Log.d(TAG, "Sign Out using Google Api.");
mGoogleApiClient.disconnect();
//CALL TO DISCONNECT GoogleApiClient
isAccntConnected = false;
}
});
}
}
private void revokeAccess(){
if (isAccntConnected == true) {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
Log.d(TAG, "Revoke access using Google Api.");
//signOutIfConnected(); //REMOVED
}
});
}
}
@Override
public void onConnected(@Nullable Bundle bundle) {
isAccntConnected = true;
}
我还引入了一个布尔标志isAccntConnected,以确保在调用此https://developers.google.com/identity/sign-in/android/disconnect建议的onConnected
方法之前调用revokeAccess
方法。即
在调用revokeAccess之前,您必须确认已调用GoogleApiClient.onConnected。
经过这些更改后,我的应用程序按原样运行。撤消访问权限的代码保持不变,只是我已在其signOutIfConnected
方法中删除了对onResult
方法的嵌套调用。
希望这个答案能帮助像我这样的很多初学者。
答案 1 :(得分:0)
private void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
// ...
}
});
}
private void revokeAccess() {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
// ...
}
});
}
https://developers.google.com/identity/sign-in/android/disconnect