Android - 使用登录屏幕登录Google而不是自动登录

时间:2014-05-26 14:09:55

标签: android login google-plus google-play-services google-api-client

我已经在我的Android应用中添加了Google登录(步骤可以在本文的第3页找到)。一切都按预期工作,但我想做一些小的调整。使用编辑3中的当前代码,每次启动应用程序时都会自动登录,而无需登录屏幕。我想禁用它,因为该应用程序将在平板电脑上使用,其中不同的员工应该每天登录应用程序。

我首先从mGoogleApiClient.connect();方法移除了onStart(),现在又重新启用了Google登录按钮。当我向mGoogleApiClient.connect();添加signInWithGoogle()时,我可以使用记住的用户登录。

我现在想要的是默认的Google登录屏幕,您可以在每次单击“登录”按钮时填写Google电子邮件和密码,而不是仅登录记住的用户。 (PS:请记住,在我的Android设备上,我目前只有Settings -> Google Accounts的用户,也许这就是为什么它会自动登录而不是选择选择应该连接的帐户。)< / p>

如果我的Android设备上有多个Google帐户,我会测试它是否会有所不同。好的,我已经在我的Android设备上添加了第二个Google帐户,但我的应用仍然当我点击登录时自动登录记住的用户..


编辑2:

我还没能找到解决问题的方法。

我确实找到了一些使用不同方式登录Google的教程,例如使用AccountManager,因此用户可以在设备上选择一个现有的Google帐户。 (我今天只读过这种方法,所以暂时还没有代码示例。但这也不是我想要的。)

我可能已在上面的帖子中说清楚了,但这是我想要在图片中解释的内容:

  1. 用户在他/她的Android设备上启动应用程序。
  2. 用户输入他的Google帐户用户名(使用过的电子邮件)和密码List item
  3. 用户成功登录后,我们可以使用该应用程序执行其他操作
  4. PS:为了确保这个登录屏幕是Google本身的屏幕。所以它不是我自己创建的登录屏幕。理论上这使我能够保存输入的密码,这违反了Google OAuth的协议。


    编辑3(守则):

    到目前为止,我所做的使Google服务工作的步骤如下。现在我只需要弄清楚如何强制登录屏幕或完全注销,每次都会导致登录屏幕。

    我已按照以下教程: http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/

    使用以下教程/网站中的额外信息:

    这产生了以下代码:

    的AndroidManifest.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.testproject_gmaillogin"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="9"
            android:targetSdkVersion="19" />
    
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.GET_ACCOUNTS" />
        <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
    
            <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
    
            <activity
                android:name="com.example.testproject_gmaillogin.MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    的strings.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <string name="app_name">TestProject_GmailLogin</string>
        <string name="action_settings">Settings</string>
    
        <string name="profile_pic_description">Google Profile Picture</string>
        <string name="btn_logout_from_google">Logout from Google</string>
        <string name="btn_revoke_access">Revoke Access</string>
    
    </resources>
    

    activity_main.xml中:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp"
        tools:context=".MainActivity" >
    
        <LinearLayout
            android:id="@+id/profile_layout"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="20dp"
            android:orientation="horizontal"
            android:weightSum="3"
            android:visibility="gone">
    
            <ImageView
                android:id="@+id/img_profile_pic"
                android:contentDescription="@string/profile_pic_description"
                android:layout_width="80dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"/>
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:orientation="vertical"
                android:layout_weight="2" >
    
                <TextView
                    android:id="@+id/txt_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="5dp"
                    android:textSize="20sp" />
    
                <TextView
                    android:id="@+id/txt_email"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="5dp"
                    android:textSize="18sp" />
            </LinearLayout>
        </LinearLayout>
    
        <com.google.android.gms.common.SignInButton
            android:id="@+id/btn_sign_in"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="20dp"/>
    
        <Button
            android:id="@+id/btn_sign_out"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/btn_logout_from_google"
            android:visibility="gone"
            android:layout_marginBottom="10dp"/>
    
        <Button
            android:id="@+id/btn_revoke_access"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/btn_revoke_access"
            android:visibility="gone" />
    
    </LinearLayout>
    

    MainActivity.java:

    package com.example.testproject_gmaillogin;
    
    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.GooglePlayServicesUtil;
    import com.google.android.gms.common.SignInButton;
    import com.google.android.gms.common.api.GoogleApiClient;
    import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
    import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
    import com.google.android.gms.common.api.ResultCallback;
    import com.google.android.gms.common.api.Status;
    import com.google.android.gms.plus.Plus;
    import com.google.android.gms.plus.model.people.Person;
    
    import android.support.v7.app.ActionBarActivity;
    import android.content.Intent;
    import android.content.IntentSender.SendIntentException;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    
    public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, OnClickListener
    {
        // Logcat tag
        private static final String TAG = "MainActivity";
    
        // Profile pix image size in pixels
        private static final int PROFILE_PIC_SIZE = 400;
    
        // 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;
    
        // The used UI-elements
        private SignInButton btnSignIn;
        private Button btnSignOut, btnRevokeAccess;
        private ImageView imgProfilePic;
        private TextView txtName, txtEmail;
        private LinearLayout profileLayout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Get the UI-elements
            btnSignIn = (SignInButton) findViewById(R.id.btn_sign_in);
            btnSignOut = (Button) findViewById(R.id.btn_sign_out);
            btnRevokeAccess = (Button) findViewById(R.id.btn_revoke_access);
            imgProfilePic = (ImageView) findViewById(R.id.img_profile_pic);
            txtName = (TextView) findViewById(R.id.txt_name);
            txtEmail = (TextView) findViewById(R.id.txt_email);
            profileLayout = (LinearLayout) findViewById(R.id.profile_layout);
    
            // Set the Button onClick-listeners
            btnSignIn.setOnClickListener(this);
            btnSignOut.setOnClickListener(this);
            btnRevokeAccess.setOnClickListener(this);
    
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(Plus.API, null)
                .addScope(Plus.SCOPE_PLUS_LOGIN)
                .build();
        }
    
        @Override
        protected void onStart(){
            super.onStart();
            mGoogleApiClient.connect(); // <- REMOVED (EDIT 4: Added again)
        }
    
        @Override
        protected void onStop(){
            super.onStop();
    
            if(mGoogleApiClient.isConnected())
                mGoogleApiClient.disconnect();
        }
    
        @Override
        public void onClick(View view){
            switch(view.getId()){
                case R.id.btn_sign_in:
                    signInWithGPlus();
                    break;
                case R.id.btn_sign_out:
                    signOutFromGPlus();
                    break;
                case R.id.btn_revoke_access:
                    revokeGPlusAccess();
                    break;
            }
        }
    
        @Override
        public void onConnectionFailed(ConnectionResult result) {
            if(!result.hasResolution()){
                GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, 0).show();
                return;
            }
    
            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
                    resolveSignInErrors();
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int responseCode, Intent intent){
            if(requestCode == RC_SIGN_IN && responseCode == RESULT_OK)
                SignInClicked = true;
    
                mIntentInProgress = false;
    
                if(!mGoogleApiClient.isConnecting())
                    mGoogleApiClient.connect();
            }
        }
    
        @Override
        public void onConnected(Bundle connectionHint) {
            mSignInClicked = false;
            Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show();
    
            // Get all the user's information
            getProfileInformation();
    
            // Update the UI after sign-in
            updateUI(true);
        }
    
        @Override
        public void onConnectionSuspended(int cause){
            mGoogleApiClient.connect();
            updateUI(false);
        }
    
        // Updating the UI, showing/hiding buttons and profile layout
        private void updateUI(boolean isSignedIn){
            if(isSignedIn){
                btnSignIn.setVisibility(View.GONE);
                btnSignOut.setVisibility(View.VISIBLE);
                btnRevokeAccess.setVisibility(View.VISIBLE);
                profileLayout.setVisibility(View.VISIBLE);
            }
            else{
                btnSignIn.setVisibility(View.VISIBLE);
                btnSignOut.setVisibility(View.GONE);
                btnRevokeAccess.setVisibility(View.GONE);
                profileLayout.setVisibility(View.GONE);
            }
        }
    
        // Sign-in into Google
        private void signInWithGPlus(){
            //if(!mGoogleApiClient.isConnecting()) // <- ADDED (EDIT 4: Removed again)
                //mGoogleApiClient.connect(); // <- ADDED (EDIT 4: Removed again)
    
            if(!mGoogleApiClient.isConnecting()){
                mSignInClicked = true;
                resolveSignInErrors();
            }
        }
    
        // Method to resolve any sign-in errors
        private void resolveSignInErrors(){
            if(mConnectionResult.hasResolution()){
                try{
                    mIntentInProgress = true;
    
                    //Toast.makeText(this, "Resolving Sign-in Errors", Toast.LENGTH_SHORT).show();
    
                    mConnectionResult.startResolutionForResult(this, RC_SIGN_IN);
                }
                catch(SendIntentException e){
                    // The intent was cancelled before it was sent. Return to the default
                    // state and attempt to connect to get an updated ConnectionResult
                    mIntentInProgress = false;
                    mGoogleApiClient.connect();
                }
            }
        }
    
        // Fetching the user's infromation name, email, profile pic
        private void getProfileInformation(){
            try{
                if(Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null){
                    Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
                    String personName = currentPerson.getDisplayName();
                    String personPhotoUrl = currentPerson.getImage().getUrl();
                    String personGooglePlusProfile = currentPerson.getUrl();
                    String personEmail = Plus.AccountApi.getAccountName(mGoogleApiClient);
    
                    Log.e(TAG, "Name: " + personName + ", "
                            + "plusProfile: " + personGooglePlusProfile + ", "
                            + "email: " + personEmail + ", "
                            + "image: " + personPhotoUrl);
    
                    txtName.setText(personName);
                    txtEmail.setText(personEmail);
    
                    // by default the profile url gives 50x50 px image,
                    // but we can replace the value with whatever dimension we
                    // want by replacing sz=X
                    personPhotoUrl = personPhotoUrl.substring(0, personPhotoUrl.length() - 2)
                            + PROFILE_PIC_SIZE;
    
                    new LoadProfileImage(imgProfilePic).execute(personPhotoUrl);
                }
                else{
                    Toast.makeText(getApplicationContext(), "Person information is null", Toast.LENGTH_LONG).show();
                }
            }
            catch(Exception ex){
                ex.printStackTrace();
            }
        }
    
        // Sign-out from Google
        private void signOutFromGPlus(){
            if(mGoogleApiClient.isConnected()){
                Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
                mGoogleApiClient.disconnect();
                mGoogleApiClient.connect();
                updateUI(false);
            }
        }
    
        // Revoking access from Google
        private void revokeGPlusAccess(){
            if(mGoogleApiClient.isConnected()){
                Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
                Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient)
                    .setResultCallback(new ResultCallback<Status>(){
                        @Override
                        public void onResult(Status s){
                            Log.e(TAG, "User access revoked!");
                            mGoogleApiClient.connect();
                            updateUI(false);
                        }
                    });
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, 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;
    
            return super.onOptionsItemSelected(item);
        }
    }
    

    LoadProfileImage.java:

    package com.example.testproject_gmaillogin;
    
    import java.io.InputStream;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.util.Log;
    import android.widget.ImageView;
    
    /**
     * Background async task to load user profile picture from url
     **/
    public class LoadProfileImage extends AsyncTask<String, Void, Bitmap> {
        private ImageView bmImage;
    
        public LoadProfileImage(ImageView bmImage){
            this.bmImage = bmImage;
        }
    
        @Override
        protected Bitmap doInBackground(String... urls){
            String urlDisplay = urls[0];
            Bitmap mIcon11 = null;
            try{
                InputStream in = new java.net.URL(urlDisplay).openStream();
                mIcon11 = BitmapFactory.decodeStream(in);
            }
            catch(Exception ex){
                Log.e("Error", ex.getMessage());
                ex.printStackTrace();
            }
            return mIcon11;
        }
    
        @Override
        protected void onPostExecute(Bitmap result){
            bmImage.setImageBitmap(result);
        }
    }
    

    我做的其他步骤是:

    https://console.developers.google.com/project我创建了一个项目:

    Google+ API:

    Google+ API on

    使用正确的SHA1创建的客户端ID以及与项目完全相同的命名空间:

    And a Client ID created with the correct SHA1

    在Eclipse:

    我已经安装了google-play-services库:

    Google-play services installed

    并将其添加到项目中:

    Google-play services library added (2) Google-play services library added (2)

    我还创建了一个版本为Google 4.4.2的模拟器(所以不是Android 4.4.2),并且还将项目更改为Google 4.4.2而不是Android 4.4.2:

    Solution Error Solution Error Emulator


    编辑4:

    好的,我有自己案例的临时解决方案。在我的情况下,我制作的应用程序应该在平板电脑上运行,该平板电脑明确用于我的应用程序。因为是这种情况,我可以在有人撤销访问权限时从设备设置中删除所有Google帐户(作为退出功能)。

    我首先删除了之前的更改(将.connect();重新添加到onStart()并将其从signInWithGPlus()中删除)

    然后我在revokeGPlusAccess - 方法中添加了一行:

    // Revoking access from Google
    private void revokeGPlusAccess(){
        if(mGoogleApiClient.isConnected()){
            Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
            Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient)
                .setResultCallback(new ResultCallback<Status>(){
                    @Override
                    public void onResult(Status s){
                        Log.e(TAG, "User access revoked!");
                        removeAllGoogleAccountsFromDevice(); // <- Added
                        mGoogleApiClient.connect();
                        updateUI(false);
                    }
                });
        }
    }
    

    使用以下方法:

    // Method to remove ALL Google Accounts from the Android Device
    private void removeAllGoogleAccountsFromDevice(){
        // Ask if this really is what you want
        new AlertDialog.Builder(MainActivity.mActivity)
            .setMessage("Are you sure you want to delete all Google Accounts from this Android Device?\r\n\r\n" +
                    "WARNING: If you run this app on the Work Tablet, click YES. If you run this on your own device, it's recommended to click NO.")
            .setCancelable(false)
            .setPositiveButton("Yes, continue", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // AccountManager is final because we use it in the separate Thread below
                    final AccountManager accountManager = AccountManager.get(MainActivity.this);
                    Account[] googleAccounts = accountManager.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
                    // Account is final because we use it in the separate Thread below
                    for(final Account a : googleAccounts){
                        // Separate Thread because AccountManager #removeAccount is an async operation
                        Thread worker = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                accountManager.removeAccount(a, null, null);
                            }
                        });
                        worker.start();
                    }
                }
            })
            .setNegativeButton("No", null)
            .show();
    }
    

    不过,这只适用于我的情况。这不会在个人设备上工作,您显然不想删除所有设备的Google帐户。如果您不想删除任何设备的Google帐户,我仍然想知道一个解决方案。

3 个答案:

答案 0 :(得分:12)

正确答案是here

需要致电mClient.clearDefaultAccountAndReconnect()以清除以前缓存的帐户 每次用户点击登录按钮时都这样做是很好的做法,这样每次都会向用户显示他的所有帐户。

答案 1 :(得分:2)

尝试signing out the user,然后再次登录该用户。如果您想强制用户每次都登录,只要他们退出应用程序就可以签名。我不建议您更改应用退出行为,因为它可能会让用户感到惊讶。

确保running the Google+ Android Quickstart sample正确设置了开发人员环境。如果示例应用中的登录行为与您所看到的相同,则说明您的开发环境存在问题(例如GMS版本,Android API版本)或登录按钮行为不符合您的预期是。

最后,您可以从this article which covers a few common problem spots with Android Sign-In中受益。它涵盖了Android登录流程中各种授权和解决步骤的高级视图。

答案 2 :(得分:0)

退出无法帮助您解决问题。每当您退出应用程序或每次要从应用程序注销并再次登录时,您都必须撤消访问权限。所以,只需在退出应用中按后退方法调用撤消访问方法,如下所示:

 @Override
    public void onBackPressed() {
       Log.d("CDA", "onBackPressed Called");
       revokeGplusAccess();
       super.onBackPressed();
    }

这肯定会解决您的问题。

相关问题