安卓 谷歌智能锁

在本教程中,我们将讨论智能锁功能,并在我们的Android应用程序中实现它。

谷歌智能锁

Smart Lock用于通过一次性保存凭据来自动登录您的应用程序。这意味着,如果你在一段时间后重新安装你的应用程序,你可以自动使用之前保存的凭据登录,前提是你没有从Chrome密码中删除它们。

谷歌智能锁只需轻点即可登录。

为了在您的应用程序中集成Smart Lock,您需要使用凭据API。凭据API允许用户:

  • 打开应用程序时请求凭据。
  • 保存登录表单中的凭据。
  • 在应用程序和网站之间同步凭据。
  • 显示电子邮件提示,以防我们希望在登录/注册过程中帮助用户。

要在您的应用程序中使用Google Smart Lock,您需要添加以下依赖项:

1dependencies {
2    implementation 'com.google.android.gms:play-services-auth:16.0.0'
3}

SmartLock需要在Android应用程序中设置GoogleApiClient。SmartLock允许在只有一个凭据时自动登录。当有多个凭据时,它们会显示在对话框中。

早些时候,我们常常依赖SharedPreferences在本地自动签名和保存凭据。现在,有了谷歌智能锁,一切都由谷歌服务器来处理。

以下是凭据API中提供的主要方法:

  • 保存(GoogleApiClient客户端,凭据凭据)
  • 请求(GoogleApiClient客户端,证书请求) -请求为应用保存的所有凭据。
  • getHintPickerIntent(GoogleApiClient客户端,HintRequestRequest)` -显示您拥有的登录帐户列表,以便快速填写登录表单。
  • disableAutoSignIn(GoogleApiClient客户端)
  • 删除(GoogleApiClient客户端,凭据凭据)

你可以通过访问passwords.google.com.查看为谷歌账户保存的所有凭据智能锁应用的流程是什么? 您需要按照以下方式组织您的登录屏幕代码:

  • 检查凭据。如果存在单一凭据,请自动签署或自动填写登录表。
  • 如果有多个凭据,请在对话框中显示并让用户选择。
  • 如果没有保存的凭据,您可以让用户填写表单,或通过自动填充或显示一个提示对话框来使其更容易登录。

入门

让我们开始在Android应用程序中实现智能锁功能。设置GoogleApiClient

1mGoogleApiClient = new GoogleApiClient.Builder(this)
2                .addConnectionCallbacks(this)
3                .addApi(Auth.CREDENTIALS_API)
4                .enableAutoManage(this, this)
5                .build();

实现GoogleApiClient接口并实现方法。初始化凭证客户端

1CredentialsOptions options = new CredentialsOptions.Builder()
2                .forceEnableSaveDialog()
3                .build();
4
5CredentialsClient mCredentialsApiClient = Credentials.getClient(this, options);

Android Oreo及以上版本需要forceEnableSaveDialog() 。** 创建证书请求**

1CredentialRequest mCredentialRequest = new CredentialRequest.Builder()
2                .setPasswordLoginSupported(true)
3                .setAccountTypes(IdentityProviders.GOOGLE)
4                .build();

取回凭据

1Auth.CredentialsApi.request(mGoogleApiClient, mCredentialRequest).setResultCallback(this);

setResultCallBack需要我们从接口ResultCallback<CredentialRequestResult>重写方法onResult

 1@Override
 2    public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {
 3
 4        Status status = credentialRequestResult.getStatus();
 5        if (status.isSuccess()) {
 6            onCredentialRetrieved(credentialRequestResult.getCredential());
 7        } else {
 8            if (status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED) {
 9                try {
10                    isResolving = true;
11                    status.startResolutionForResult(this, RC_READ);
12                } catch (IntentSender.SendIntentException e) {
13                    Log.d(TAG, e.toString());
14                }
15            } else {
16
17                showHintDialog();
18            }
19        }
20    }

有三种情况-

单个凭据-成功-多个凭据-解析它们并在对话框中显示所有可用凭据

  • 无凭据-显示包含所有可用登录帐户的提示对话框

状态码RESOLUTION_REQUIRED表示有多个凭证需要解析。为此,我们调用startResolutionForResult,它在onActivityResult方法中返回结果。我们使用布尔标志来防止出现多个解析。这将导致构建多个对话框。现在我们已经了解了SmartLock功能的要点,让我们通过保存和删除凭据功能来完全实现它。

项目结构

安卓谷歌智能锁project

代码

Active_main.xml布局的代码如下所示:

 1<?xml version="1.0" encoding="utf-8"?>
 2<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
 3    xmlns:app="https://schemas.android.com/apk/res-auto"
 4    xmlns:tools="https://schemas.android.com/tools"
 5    android:layout_width="match_parent"
 6    android:layout_height="match_parent"
 7    android:importantForAutofill="noExcludeDescendants">
 8
 9    <Button
10        android:id="@+id/btnLogin"
11        android:layout_width="wrap_content"
12        android:layout_height="wrap_content"
13        android:layout_marginLeft="8dp"
14        android:layout_marginRight="8dp"
15        android:layout_marginTop="24dp"
16        android:text="Login"
17        app:layout_constraintLeft_toLeftOf="parent"
18        app:layout_constraintRight_toRightOf="parent"
19        app:layout_constraintTop_toBottomOf="@+id/inPassword" />
20
21    <EditText
22        android:id="@+id/inEmail"
23        android:layout_width="0dp"
24        android:layout_height="wrap_content"
25        android:layout_marginLeft="16dp"
26        android:layout_marginRight="16dp"
27        android:layout_marginTop="32dp"
28        android:ems="10"
29        android:hint="email"
30        android:inputType="textEmailAddress"
31        app:layout_constraintHorizontal_bias="0.503"
32        app:layout_constraintLeft_toLeftOf="parent"
33        app:layout_constraintRight_toRightOf="parent" />
34
35    <EditText
36        android:id="@+id/inPassword"
37        android:layout_width="0dp"
38        android:layout_height="wrap_content"
39        android:layout_marginLeft="16dp"
40        android:layout_marginRight="16dp"
41        android:layout_marginTop="8dp"
42        android:ems="10"
43        android:hint="password"
44        android:inputType="textPassword"
45        app:layout_constraintLeft_toLeftOf="parent"
46        app:layout_constraintRight_toRightOf="parent"
47        app:layout_constraintTop_toBottomOf="@+id/inEmail" />
48
49</android.support.constraint.ConstraintLayout>

android:importantForAutofill=noExcludeDescendants>用于在编辑文本字段上禁用自动填充。我们将在单独的教程中讨论自动填充API。下面给出了MainActivity.java类的代码:

  1package com.journaldev.androidgooglesmartlock;
  2
  3import android.app.PendingIntent;
  4import android.content.Intent;
  5import android.content.IntentSender;
  6import android.support.annotation.NonNull;
  7import android.support.annotation.Nullable;
  8import android.support.v7.app.AppCompatActivity;
  9import android.os.Bundle;
 10import android.text.TextUtils;
 11import android.util.Log;
 12import android.util.Patterns;
 13import android.view.View;
 14import android.widget.Button;
 15import android.widget.EditText;
 16import android.widget.Toast;
 17
 18import com.google.android.gms.auth.api.Auth;
 19import com.google.android.gms.auth.api.credentials.Credential;
 20import com.google.android.gms.auth.api.credentials.CredentialPickerConfig;
 21import com.google.android.gms.auth.api.credentials.CredentialRequest;
 22import com.google.android.gms.auth.api.credentials.CredentialRequestResponse;
 23import com.google.android.gms.auth.api.credentials.CredentialRequestResult;
 24import com.google.android.gms.auth.api.credentials.Credentials;
 25import com.google.android.gms.auth.api.credentials.CredentialsClient;
 26import com.google.android.gms.auth.api.credentials.CredentialsOptions;
 27import com.google.android.gms.auth.api.credentials.HintRequest;
 28import com.google.android.gms.auth.api.credentials.IdentityProviders;
 29import com.google.android.gms.auth.api.signin.GoogleSignIn;
 30import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
 31import com.google.android.gms.auth.api.signin.GoogleSignInClient;
 32import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
 33import com.google.android.gms.common.ConnectionResult;
 34import com.google.android.gms.common.api.ApiException;
 35import com.google.android.gms.common.api.CommonStatusCodes;
 36import com.google.android.gms.common.api.GoogleApiClient;
 37import com.google.android.gms.common.api.ResolvableApiException;
 38import com.google.android.gms.common.api.ResultCallback;
 39import com.google.android.gms.common.api.Status;
 40import com.google.android.gms.tasks.OnCompleteListener;
 41import com.google.android.gms.tasks.Task;
 42
 43import java.util.regex.Pattern;
 44
 45public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<CredentialRequestResult> {
 46
 47    private GoogleApiClient mGoogleApiClient;
 48    CredentialsClient mCredentialsApiClient;
 49    CredentialRequest mCredentialRequest;
 50    public static final String TAG = "API123";
 51    private static final int RC_READ = 3;
 52    private static final int RC_SAVE = 1;
 53    private static final int RC_HINT = 2;
 54    boolean isResolving;
 55
 56    Button btnLogin;
 57    EditText inEmail, inPassword;
 58
 59    @Override
 60    protected void onCreate(Bundle savedInstanceState) {
 61        super.onCreate(savedInstanceState);
 62        setContentView(R.layout.activity_main);
 63
 64        setUpGoogleApiClient();
 65
 66        //needed for Android Oreo.
 67        CredentialsOptions options = new CredentialsOptions.Builder()
 68                .forceEnableSaveDialog()
 69                .build();
 70
 71        mCredentialsApiClient = Credentials.getClient(this, options);
 72        createCredentialRequest();
 73
 74        btnLogin = findViewById(R.id.btnLogin);
 75        inEmail = findViewById(R.id.inEmail);
 76        inPassword = findViewById(R.id.inPassword);
 77
 78        btnLogin.setOnClickListener(new View.OnClickListener() {
 79            @Override
 80            public void onClick(View view) {
 81
 82                String email = inEmail.getText().toString();
 83                String password = inPassword.getText().toString();
 84                if (TextUtils.isEmpty(email) || TextUtils.isEmpty(password) || !Patterns.EMAIL_ADDRESS.matcher(email).matches())
 85                    showToast("Please enter valid email and password");
 86
 87                else {
 88
 89                    Credential credential = new Credential.Builder(email)
 90                            .setPassword(password)
 91                            .build();
 92
 93                    saveCredentials(credential);
 94                }
 95
 96            }
 97        });
 98    }
 99
100    public void setUpGoogleApiClient() {
101
102        mGoogleApiClient = new GoogleApiClient.Builder(this)
103                .addConnectionCallbacks(this)
104                .addApi(Auth.CREDENTIALS_API)
105                .enableAutoManage(this, this)
106                .build();
107    }
108
109    public void createCredentialRequest() {
110        mCredentialRequest = new CredentialRequest.Builder()
111                .setPasswordLoginSupported(true)
112                .setAccountTypes(IdentityProviders.GOOGLE)
113                .build();
114    }
115
116    public void requestCredentials() {
117        Auth.CredentialsApi.request(mGoogleApiClient, mCredentialRequest).setResultCallback(this);
118    }
119
120    private void onCredentialRetrieved(Credential credential) {
121        String accountType = credential.getAccountType();
122        if (accountType == null) {
123            // Sign the user in with information from the Credential.
124            gotoNext();
125        } else if (accountType.equals(IdentityProviders.GOOGLE)) {
126
127            GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
128                    .requestEmail()
129                    .build();
130
131            GoogleSignInClient signInClient = GoogleSignIn.getClient(this, gso);
132            Task<GoogleSignInAccount> task = signInClient.silentSignIn();
133
134            task.addOnCompleteListener(new OnCompleteListener<GoogleSignInAccount>() {
135                @Override
136                public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
137                    if (task.isSuccessful()) {
138                        // See "Handle successful credential requests"
139                        populateLoginFields(task.getResult().getEmail(), null);
140                    } else {
141                        showToast("Unable to do a google sign in");
142                    }
143                }
144            });
145        }
146    }
147
148    public void gotoNext() {
149        startActivity(new Intent(this, SecondActivity.class));
150        finish();
151    }
152
153    public void showToast(String s) {
154        Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
155    }
156
157    @Override
158    public void onConnected(@Nullable Bundle bundle) {
159        Log.d("API123", "onConnected");
160        requestCredentials();
161
162    }
163
164    @Override
165    public void onConnectionSuspended(int i) {
166
167    }
168
169    @Override
170    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
171
172    }
173
174    @Override
175    protected void onDestroy() {
176        mGoogleApiClient.disconnect();
177        super.onDestroy();
178    }
179
180    @Override
181    public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {
182
183        Status status = credentialRequestResult.getStatus();
184        if (status.isSuccess()) {
185            onCredentialRetrieved(credentialRequestResult.getCredential());
186        } else {
187            if (status.getStatusCode() == CommonStatusCodes.RESOLUTION_REQUIRED) {
188                try {
189                    isResolving = true;
190                    status.startResolutionForResult(this, RC_READ);
191                } catch (IntentSender.SendIntentException e) {
192                    Log.d(TAG, e.toString());
193                }
194            } else {
195
196                showHintDialog();
197            }
198        }
199    }
200
201    @Override
202    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
203        super.onActivityResult(requestCode, resultCode, data);
204
205        Log.d(TAG, "onActivityResult");
206        if (requestCode == RC_READ) {
207            if (resultCode == RESULT_OK) {
208                Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
209                onCredentialRetrieved(credential);
210            } else {
211                Log.d(TAG, "Request failed");
212            }
213            isResolving = false;
214        }
215
216        if (requestCode == RC_HINT) {
217            if (resultCode == RESULT_OK) {
218                Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
219                populateLoginFields(credential.getId(), "");
220            } else {
221                showToast("Hint dialog closed");
222            }
223        }
224
225        if (requestCode == RC_SAVE) {
226            if (resultCode == RESULT_OK) {
227                Log.d(TAG, "SAVE: OK");
228                gotoNext();
229                showToast("Credentials saved");
230            }
231        }
232
233    }
234
235    public void populateLoginFields(String email, String password) {
236        if (!TextUtils.isEmpty(email))
237            inEmail.setText(email);
238
239        if (!TextUtils.isEmpty(password))
240            inPassword.setText(password);
241    }
242
243    public void showHintDialog() {
244        HintRequest hintRequest = new HintRequest.Builder()
245                .setHintPickerConfig(new CredentialPickerConfig.Builder()
246                        .setShowCancelButton(true)
247                        .build())
248                .setEmailAddressIdentifierSupported(true)
249                .setAccountTypes(IdentityProviders.GOOGLE)
250                .build();
251
252        PendingIntent intent = mCredentialsApiClient.getHintPickerIntent(hintRequest);
253        try {
254            startIntentSenderForResult(intent.getIntentSender(), RC_HINT, null, 0, 0, 0);
255        } catch (IntentSender.SendIntentException e) {
256            Log.e(TAG, "Could not start hint picker Intent", e);
257        }
258    }
259
260    public void saveCredentials(Credential credential) {
261
262        mCredentialsApiClient.save(credential).addOnCompleteListener(new OnCompleteListener<Void>() {
263            @Override
264            public void onComplete(@NonNull Task<Void> task) {
265                if (task.isSuccessful()) {
266                    Log.d(TAG, "SAVE: OK");
267                    showToast("Credentials saved");
268                    return;
269                }
270
271                Exception e = task.getException();
272                if (e instanceof ResolvableApiException) {
273                    // Try to resolve the save request. This will prompt the user if
274                    // the credential is new.
275                    ResolvableApiException rae = (ResolvableApiException) e;
276                    try {
277                        rae.startResolutionForResult(MainActivity.this, RC_SAVE);
278                    } catch (IntentSender.SendIntentException f) {
279                        // Could not resolve the request
280                        Log.e(TAG, "Failed to send resolution.", f);
281                        showToast("Saved failed");
282                    }
283                } else {
284                    // Request has no resolution
285                    showToast("Saved failed");
286                }
287            }
288        });
289
290    }
291}

在onConnected方法中,我们请求可用的凭据。这意味着一旦活动启动,就会检索凭据(如果有的话)。如果存在单个凭据,则它将自动签名并转到下一个活动。Activity_Second.xml布局的代码如下所示:

 1<?xml version="1.0" encoding="utf-8"?>
 2<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
 3    xmlns:app="https://schemas.android.com/apk/res-auto"
 4    xmlns:tools="https://schemas.android.com/tools"
 5    android:layout_width="match_parent"
 6    android:layout_height="match_parent"
 7    tools:context=".SecondActivity">
 8
 9    <Button
10        android:id="@+id/btnDeleteAccount"
11        android:layout_width="wrap_content"
12        android:layout_height="wrap_content"
13        android:layout_marginTop="8dp"
14        android:text="Delete account"
15        app:layout_constraintEnd_toEndOf="parent"
16        app:layout_constraintStart_toStartOf="parent"
17        app:layout_constraintTop_toBottomOf="@+id/btnSignOut" />
18
19    <TextView
20        android:id="@+id/textView"
21        android:layout_width="wrap_content"
22        android:layout_height="wrap_content"
23        android:text="You are logged in."
24        app:layout_constraintBottom_toBottomOf="parent"
25        app:layout_constraintEnd_toEndOf="parent"
26        app:layout_constraintStart_toStartOf="parent"
27        app:layout_constraintTop_toTopOf="parent" />
28
29    <Button
30        android:id="@+id/btnSignOut"
31        android:layout_width="wrap_content"
32        android:layout_height="wrap_content"
33        android:layout_marginTop="8dp"
34        android:text="SIGN OUT"
35        app:layout_constraintEnd_toEndOf="parent"
36        app:layout_constraintStart_toStartOf="parent"
37        app:layout_constraintTop_toBottomOf="@+id/textView" />
38
39    <Button
40        android:id="@+id/btnSignOutDisableAutoSign"
41        android:layout_width="wrap_content"
42        android:layout_height="wrap_content"
43        android:text="SIGN OUT AND DISABLE AUTO SIGN IN"
44        app:layout_constraintEnd_toEndOf="parent"
45        app:layout_constraintStart_toStartOf="parent"
46        app:layout_constraintTop_toBottomOf="@+id/btnDeleteAccount" />
47</android.support.constraint.ConstraintLayout>

在Second Activity中,我们将执行三个不同的操作-注销、注销,并在下次禁用自动登录、删除凭据。Second Activity.Java类的代码如下所示:

  1package com.journaldev.androidgooglesmartlock;
  2
  3import android.content.Intent;
  4import android.content.IntentSender;
  5import android.support.annotation.NonNull;
  6import android.support.annotation.Nullable;
  7import android.support.v7.app.AppCompatActivity;
  8import android.os.Bundle;
  9import android.util.Log;
 10import android.view.View;
 11import android.widget.Button;
 12import android.widget.Toast;
 13
 14import com.google.android.gms.auth.api.Auth;
 15import com.google.android.gms.auth.api.credentials.Credential;
 16import com.google.android.gms.auth.api.credentials.CredentialRequest;
 17import com.google.android.gms.auth.api.credentials.CredentialRequestResult;
 18import com.google.android.gms.auth.api.credentials.Credentials;
 19import com.google.android.gms.auth.api.credentials.CredentialsClient;
 20import com.google.android.gms.common.ConnectionResult;
 21import com.google.android.gms.common.api.GoogleApiClient;
 22import com.google.android.gms.common.api.ResultCallback;
 23import com.google.android.gms.common.api.Status;
 24
 25public class SecondActivity extends AppCompatActivity implements View.OnClickListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<CredentialRequestResult> {
 26
 27    Button btnSignOut, btnSignOutDisableAuto, btnDelete;
 28    private GoogleApiClient mGoogleApiClient;
 29    CredentialsClient mCredentialsApiClient;
 30    CredentialRequest mCredentialRequest;
 31    public static final String TAG = "API123";
 32    private static final int RC_REQUEST = 4;
 33
 34    @Override
 35    protected void onCreate(Bundle savedInstanceState) {
 36        super.onCreate(savedInstanceState);
 37        setContentView(R.layout.activity_second);
 38
 39        setUpGoogleApiClient();
 40        mCredentialsApiClient = Credentials.getClient(this);
 41
 42        btnSignOut = findViewById(R.id.btnSignOut);
 43        btnSignOutDisableAuto = findViewById(R.id.btnSignOutDisableAutoSign);
 44        btnDelete = findViewById(R.id.btnDeleteAccount);
 45
 46        btnSignOut.setOnClickListener(this);
 47        btnSignOutDisableAuto.setOnClickListener(this);
 48        btnDelete.setOnClickListener(this);
 49    }
 50
 51    @Override
 52    public void onClick(View view) {
 53        switch (view.getId()) {
 54            case R.id.btnSignOut:
 55                signOut(false);
 56                break;
 57            case R.id.btnSignOutDisableAutoSign:
 58                signOut(true);
 59                break;
 60            case R.id.btnDeleteAccount:
 61                requestCredentials();
 62
 63                break;
 64        }
 65    }
 66
 67    @Override
 68    public void onConnected(@Nullable Bundle bundle) {
 69
 70    }
 71
 72    @Override
 73    public void onConnectionSuspended(int i) {
 74
 75    }
 76
 77    @Override
 78    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
 79
 80    }
 81
 82    @Override
 83    public void onResult(@NonNull CredentialRequestResult credentialRequestResult) {
 84
 85        Status status = credentialRequestResult.getStatus();
 86        if (status.isSuccess()) {
 87            onCredentialSuccess(credentialRequestResult.getCredential());
 88        } else {
 89            if (status.hasResolution()) {
 90                try {
 91                    status.startResolutionForResult(this, RC_REQUEST);
 92                } catch (IntentSender.SendIntentException e) {
 93                    Log.d(TAG, e.toString());
 94                }
 95            } else {
 96                showToast("Request Failed");
 97            }
 98        }
 99    }
100
101    public void setUpGoogleApiClient() {
102
103        mGoogleApiClient = new GoogleApiClient.Builder(this)
104                .addConnectionCallbacks(this)
105                .addApi(Auth.CREDENTIALS_API)
106                .enableAutoManage(this, this)
107                .build();
108    }
109
110    private void requestCredentials() {
111        mCredentialRequest = new CredentialRequest.Builder()
112                .setPasswordLoginSupported(true)
113                .build();
114
115        Auth.CredentialsApi.request(mGoogleApiClient, mCredentialRequest).setResultCallback(this);
116    }
117
118    @Override
119    protected void onDestroy() {
120        mGoogleApiClient.disconnect();
121        super.onDestroy();
122    }
123
124    private void onCredentialSuccess(Credential credential) {
125
126        Auth.CredentialsApi.delete(mGoogleApiClient, credential).setResultCallback(new ResultCallback<Status>() {
127            @Override
128            public void onResult(@NonNull Status status) {
129                if (status.isSuccess()) {
130                    signOut(false);
131                } else {
132                    showToast("Account Deletion Failed");
133                }
134            }
135        });
136
137    }
138
139    @Override
140    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
141        super.onActivityResult(requestCode, resultCode, data);
142        if (requestCode == RC_REQUEST) {
143            if (resultCode == RESULT_OK) {
144                showToast("Deleted");
145                Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
146                onCredentialSuccess(credential);
147            } else {
148                Log.d(TAG, "Request failed");
149            }
150        }
151    }
152
153    public void showToast(String s) {
154        Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
155    }
156
157    private void signOut(boolean disableAutoSignIn) {
158
159        if (disableAutoSignIn)
160            Auth.CredentialsApi.disableAutoSignIn(mGoogleApiClient);
161
162        startActivity(new Intent(this, MainActivity.class));
163        finish();
164    }
165}

上述应用程序的实际运行输出如下:Android SmartLock output我们创建了第一个帐户,并看到每次打开应用程序时,它都会自动登录。除非我们禁用自动签名功能。然后,它会在登录之前请求许可。我们创建了另一个帐户。这一次是我们删除它的时候。并且应用程序在删除后自动登录到第一个帐户。这就是本教程的结束。您可以从下面的链接下载该项目:

AndroidGoogleSmartLock

GitHub项目Link

Published At
Categories with 技术
Tagged with
comments powered by Disqus