本文介绍了如何在我的Android应用程序中撤消Google帐户访问权限?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是android新手,想知道如何撤消使用GoogleSignInApi登录到我的应用程序的用户的访问权限.

I am new to android and would like to know how to revoke access of someone who has signed-in to my app using GoogleSignInApi.

我希望我的应用在用户撤消应用内的访问权限时询问用户的Google帐户ID.目前,即使用户单击了撤消访问按钮,我的应用程序也会在用户单击登录"按钮后自动登录.

I want my app to ask for the user's google account id when user revokes the access within the app. Currently my app automatically signs-in once the user clicks on SignIn button, even after the user has clicked revoke access button.

当用户单击我的应用程序的撤消"或退出"按钮时,我正在广播意图.以下是我的 MainActivity 的代码.

I am broadcasting an intent when the user clicks on revoke or sign out button of my app. Below is the code for my 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","[email protected]");
        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) {

}*/
}

我可能缺少某些东西或做错了什么.请引导我.

I may be missing something or may be doing something wrong. Please guide me.

推荐答案

花了两天时间,尝试了解Android活动的生命周期之后,我才能够找到解决该问题的方法.上面的代码有两个主要缺陷.

After spending two days, trying to understand Android activity life cycle, I was able to figure out the solution to this problem. There were two major flaws in the code above.

  1. 我尚未在GoogleApiClient中注册回调.由于此代码不在onConnected(),onConnectionSuspended()和onConnectionFailed()内部流动.解决方法是按如下所示进行注册:

  1. I had not registered the callbacks in GoogleApiClient. Due to this code was not flowing inside onConnected(), onConnectionSuspended() and onConnectionFailed(). Solution is to register them as shown below:

 mGoogleApiClient = new GoogleApiClient.Builder(this)
        .addApi(Auth.GOOGLE_SIGN_IN_API, mGoogleSignInOptions)
        .addConnectionCallbacks(this)
        .addOnConnectionFailedListener(this)
        .build();

  • 我已启用GoogleApiClient的自动管理,如此链接 https://developers .google.com/identity/sign-in/android/.尽管这不是一个缺陷,但现在我无法利用它来谋取利益.
  • I had enabled auto mangement of GoogleApiClient as shown in this link https://developers.google.com/identity/sign-in/android/. Though this is not a flaw, right now I am unable to use it for my benefit.
  • 它会在调用onStart时自动连接GoogleApiClient实例,并在调用onStop时自动断开连接.因此,当用户登录到我的应用程序时,该应用程序会将她带到MasterActivity.在此过程中,SignInActivity的onStop方法被调用.此断开连接的GoogleApiClient实例(记住自动托管).因此,解决方案是在我的代码中自己管理它.

    It automatically connects GoogleApiClient instance when onStart is called and disconnects it when onStop is called. So when a user logs in to my app, the app takes her to MasterActivity. Along the way, onStop method of SignInActivity is called. This disconnected GoogleApiClient instance (remember automanaged ). So the solution was to manage it myself within my code.

    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,以确保在调用revokeAccess方法之前已经对onConnected方法进行了调用,如此处 https://developers.google.com/identity/sign-in/android/disconnect . IE.在调用revokeAccess之前,必须确认已调用GoogleApiClient.onConnected.

    I also introduced a boolean flag isAccntConnected to ensure that call to onConnected method has been made before invoking revokeAccess method as suggested here https://developers.google.com/identity/sign-in/android/disconnect. i.e.You must confirm that GoogleApiClient.onConnected has been called before you call revokeAccess.

    这些更改之后,我的应用程序将按原样运行.撤消访问权限的代码保持不变,只是我删除了onResult方法中对signOutIfConnected方法的嵌套调用.

    After these changes, my app works as it was meant to be. The code to revoke access remains the same, except that I have removed nested call to signOutIfConnected method inside its onResult method.

    希望这个答案会对像我这样的许多初学者有所帮助.

    Hope this answer will help lots of beginners like me.

    这篇关于如何在我的Android应用程序中撤消Google帐户访问权限?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    09-03 12:05