2016-10-15 50 views
0

我是新來的android,想知道如何撤銷使用GoogleSignInApi登錄我的應用的用戶的訪問權限。如何在我的android應用內撤銷Google帳戶訪問權限?

我希望我的應用在用戶撤銷應用內的訪問時詢問用戶的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","[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) { 

}*/ 
} 

我可能會錯過某些東西或者可能會做錯事。請指導我。

回答

1

花了兩天,試圖瞭解Android的活動週期後,我能找出解決這個問題。上面的代碼中有兩個主要缺陷。

  1. 我還沒有在GoogleApiClient中註冊回調。由於此代碼不在onConnected(),onConnectionSuspended()和onConnectionFailed()內部流動。解決辦法是將它們註冊,如下圖所示:

    mGoogleApiClient = new GoogleApiClient.Builder(this) 
         .addApi(Auth.GOOGLE_SIGN_IN_API, mGoogleSignInOptions) 
         .addConnectionCallbacks(this) 
         .addOnConnectionFailedListener(this) 
         .build(); 
    
  2. 我已使GoogleApiClient的自動管理CHINESE如在這個環節https://developers.google.com/identity/sign-in/android/。雖然這不是一個缺陷,但現在我無法爲我的利益使用它。

它會自動連接時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確保調用onConnected方法的布爾標誌調用revokeAccess方法,如下https://developers.google.com/identity/sign-in/android/disconnect建議之前已經取得進展。即 在調用revokeAccess之前,您必須確認已調用了GoogleApiClient.onConnected。

經過這些更改後,我的應用程序按原樣工作。撤銷訪問的代碼保持不變,除了我已經在其onResult方法中刪除了嵌套調用signOutIfConnected方法。

希望這個答案能幫助很多像我這樣的初學者。

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

+0

我可以退出。我希望我的應用在退出登錄時重新詢問Google帳戶ID。最初它要求我輸入谷歌賬戶ID和密碼。之後,當我撤銷訪問,然後註銷,然後再次嘗試登錄,它適用於silentSignIn。爲什麼它不再要求Google帳戶ID? – Tony

+0

答案在同一頁上。添加到上面。 – Kuffs

+0

我知道它在那裏,我的代碼也有該代碼。請閱讀我上面的評論。 – Tony

相關問題