如要自動驗證電話號碼,您必須同時實作驗證流程的用戶端和伺服器部分。本文說明如何在 Android 應用程式中實作用戶端部分。
如要在 Android 應用程式中啟動電話號碼驗證流程,請將電話號碼傳送至驗證伺服器,並呼叫 SMS Retriever API 開始監聽包含應用程式的一次性代碼的簡訊。收到訊息後,請將一次性代碼傳回伺服器,完成驗證程序。
事前準備
如要讓應用程式做好準備,請完成下列各節的步驟。
應用程式必要條件
請確認應用程式的版本檔案使用下列的值:
- minSdkVersion 為 19 以上
- compileSdkVersion 28 以上版本
設定應用程式
在專案層級的 build.gradle 檔案中,同時在 buildscript
和 allprojects
區段中加入 Google Maven 存放區和 Maven 中央存放區:
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
將 SMS Retriever API 的 Google Play 服務依附元件,新增至模組的 Gradle 版本檔案,通常為 app/build.gradle
:
dependencies {
implementation 'com.google.android.gms:play-services-auth:20.7.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:18.0.1'
}
1. 取得使用者的電話號碼
您可以透過任何適合應用程式的方式取得使用者的電話號碼。通常使用提示挑選器,提示使用者從裝置上儲存的電話號碼進行選擇,是最好的使用者體驗。這樣一來,使用者就不必手動輸入電話號碼。如何使用提示挑選器:
// Construct a request for phone numbers and show the picker
private void requestHint() {
HintRequest hintRequest = new HintRequest.Builder()
.setPhoneNumberIdentifierSupported(true)
.build();
PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
apiClient, hintRequest);
startIntentSenderForResult(intent.getIntentSender(),
RESOLVE_HINT, null, 0, 0, 0);
}
// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESOLVE_HINT) {
if (resultCode == RESULT_OK) {
Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
// credential.getId(); <-- will need to process phone number string
}
}
}
2. 啟動簡訊擷取工具
準備好驗證使用者的電話號碼時,請取得 SmsRetrieverClient
物件的執行個體、呼叫 startSmsRetriever
,並將成功和失敗的事件監聽器附加至簡訊擷取工作:
// Get an instance of SmsRetrieverClient, used to start listening for a matching
// SMS message.
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);
// Starts SmsRetriever, which waits for ONE matching SMS message until timeout
// (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
// action SmsRetriever#SMS_RETRIEVED_ACTION.
Task<Void> task = client.startSmsRetriever();
// Listen for success/failure of the start Task. If in a background thread, this
// can be made blocking using Tasks.await(task, [timeout]);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Successfully started retriever, expect broadcast intent
// ...
}
});
task.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Failed to start retriever, inspect Exception for more details
// ...
}
});
簡訊擷取工作將監聽最長五分鐘,其中包含用於識別您應用程式的專屬字串。
3. 將電話號碼傳送至你的伺服器
取得使用者的電話號碼並開始監聽簡訊之後,請透過任何方式 (通常透過 HTTPS POST 要求) 將使用者的電話號碼傳送至驗證伺服器。
您的伺服器會產生驗證訊息,並透過簡訊將驗證訊息傳送到您指定的電話號碼。請參閱在伺服器上執行簡訊驗證。
4. 接收驗證郵件
在使用者的裝置收到驗證訊息時,Play 服務會透過 SmsRetriever.SMS_RETRIEVED_ACTION
意圖明確向您的應用程式廣播,其中包含訊息文字。請使用 BroadcastReceiver
接收此驗證郵件。
在 BroadcastReceiver
的 onReceive
處理常式中,從意圖的額外項目取得驗證訊息文字:
/**
* BroadcastReceiver to wait for SMS messages. This can be registered either
* in the AndroidManifest or at runtime. Should filter Intents on
* SmsRetriever.SMS_RETRIEVED_ACTION.
*/
public class MySMSBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch(status.getStatusCode()) {
case CommonStatusCodes.SUCCESS:
// Get SMS message contents
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
// Extract one-time code from the message and complete verification
// by sending the code back to your server.
break;
case CommonStatusCodes.TIMEOUT:
// Waiting for SMS timed out (5 minutes)
// Handle the error ...
break;
}
}
}
}
使用意圖篩選器 com.google.android.gms.auth.api.phone.SMS_RETRIEVED
(SmsRetriever.SMS_RETRIEVED_ACTION
常數的值) 和應用程式中 AndroidManifest.xml
檔案中的權限 com.google.android.gms.auth.api.phone.permission.SEND
(SmsRetriever.SEND_PERMISSION
常數值) 註冊此 BroadcastReceiver
,如以下範例所示,或使用 Context.registerReceiver
以動態方式註冊。
<receiver android:name=".MySMSBroadcastReceiver" android:exported="true"
android:permission="com.google.android.gms.auth.api.phone.permission.SEND">
<intent-filter>
<action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
</intent-filter>
</receiver>
5. 將驗證訊息中的一次性驗證碼傳送至您的伺服器
現在您已取得驗證訊息的文字,請使用規則運算式或其他邏輯,從訊息中取得一次性代碼。一次性程式碼的格式,取決於您在伺服器中實作這些程式碼的方式。
最後,透過安全連線將一次性代碼傳送至伺服器。當您的伺服器收到一次性驗證碼時,會記錄該電話號碼已通過驗證。
選用:使用密碼專用 Smart Lock 儲存電話號碼
在使用者驗證電話號碼後,您還可以視需要提示使用者透過密碼專用 Smart Lock 儲存這個電話號碼帳戶。這樣一來,其他應用程式和其他裝置就會自動使用這個號碼,無需再次輸入或選取電話號碼:
Credential credential = new Credential.Builder(phoneNumberString)
.setAccountType("https://signin.example.com") // a URL specific to the app
.setName(displayName) // optional: a display name if available
.build();
Auth.CredentialsApi.save(apiClient, credential).setResultCallback(
new ResultCallback() {
public void onResult(Result result) {
Status status = result.getStatus();
if (status.isSuccess()) {
Log.d(TAG, "SAVE: OK"); // already saved
} else if (status.hasResolution()) {
// Prompt the user to save
status.startResolutionForResult(this, RC_SAVE);
}
}
});
當使用者重新安裝應用程式或在新裝置上安裝應用程式後,您就可以擷取已儲存的電話號碼,不必再次要求使用者提供電話號碼:
// On the next install, retrieve the phone number
mCredentialRequest = new CredentialRequest.Builder()
.setAccountTypes("https://signin.example.com") // the URL specific to the developer
.build();
Auth.CredentialsApi.request(apiClient, mCredentialRequest).setResultCallback(
new ResultCallback<CredentialRequestResult>() {
public void onResult(CredentialRequestResult credentialRequestResult) {
if (credentialRequestResult.getStatus().isSuccess()) {
credentialRequestResult.getCredential().getId(); // this is the phone number
}
}
});
// Then, initiate verification and sign the user in (same as original verification logic)