ใช้ไคลเอ็นต์การลงชื่อเข้าใช้ One Tap เพื่อขอสิทธิ์จากผู้ใช้ในการดึงข้อมูลเข้าสู่ระบบที่ใช้เพื่อลงชื่อเข้าใช้แอปมาก่อนหน้านี้ ข้อมูลเข้าสู่ระบบเหล่านี้อาจเป็นบัญชี Google หรือชุดชื่อผู้ใช้-รหัสผ่านที่ Google บันทึกไว้โดยใช้ Chrome, การป้อนข้อความอัตโนมัติของ Android หรือ Smart Lock สําหรับรหัสผ่าน
เมื่อดึงข้อมูลเข้าสู่ระบบสําเร็จ คุณสามารถใช้เพื่อลงชื่อเข้าใช้แอปของคุณได้อย่างราบรื่น
หากผู้ใช้ไม่ได้บันทึกข้อมูลเข้าสู่ระบบไว้ จะไม่มี UI ใดๆ เกิดขึ้นและคุณสามารถให้ประสบการณ์เมื่อออกจากระบบตามปกติได้
ฉันควรใช้การลงชื่อเข้าใช้ด้วย One Tap ที่ใด
หากแอปของคุณกําหนดให้ผู้ใช้ลงชื่อเข้าใช้ ให้แสดง UI แบบแตะครั้งเดียวบนหน้าจอการลงชื่อเข้าใช้ วิธีนี้มีประโยชน์เมื่อคุณมีปุ่ม "Sign in with Google" อยู่แล้ว: เนื่องจากสามารถกําหนดค่า UI ของ One Tap ให้แสดงเฉพาะข้อมูลรับรองที่ผู้ใช้เคยลงชื่อเข้าใช้ ซึ่งอาจเป็นการเตือนให้ผู้ใช้ลงชื่อเข้าใช้เป็นประจํา ทุกครั้งที่ผ่านมา รวมทั้งป้องกันไม่ให้ผู้ใช้สร้างบัญชีใหม่ด้วยแอปโดยไม่ตั้งใจ
หากแอปของคุณไม่จําเป็นต้องลงชื่อเข้าใช้ ให้พิจารณาใช้การลงชื่อเข้าใช้ด้วย One Tap ในหน้าจอที่มีประสบการณ์การใช้งานที่ดีขึ้นด้วยการลงชื่อเข้าใช้ เช่น หากผู้ใช้เรียกดูเนื้อหาด้วยแอปขณะออกจากระบบ แต่สามารถโพสต์ความคิดเห็นหรือเพิ่มรายการลงในรถเข็นช็อปปิ้งเท่านั้นหลังจากที่ลงชื่อเข้าใช้ ถือว่าเป็นบริบทที่สมเหตุสมผลสําหรับการลงชื่อเข้าใช้ด้วย One Tap
แอปเสริมการลงชื่อเข้าใช้ยังควรใช้การลงชื่อเข้าใช้ด้วย One Tap ในหน้าจอลงชื่อเข้าใช้ด้วย ด้วยเหตุผลที่ระบุไว้ข้างต้น
ก่อนเริ่มต้น
- ตั้งค่าโปรเจ็กต์คอนโซล Google API และโปรเจ็กต์ Android ตามที่อธิบายไว้ในเริ่มต้นใช้งานการลงชื่อเข้าใช้ด้วย One Tap
- หากคุณรองรับการลงชื่อเข้าใช้ด้วยรหัสผ่าน ให้เพิ่มประสิทธิภาพแอปสําหรับการป้อนรหัสผ่านอัตโนมัติ (หรือใช้ Smart Lock สําหรับรหัสผ่าน) ซึ่งจะช่วยให้ผู้ใช้บันทึกข้อมูลเข้าสู่ระบบของรหัสผ่านได้หลังจากลงชื่อเข้าใช้
1. กําหนดค่าไคลเอ็นต์การลงชื่อเข้าใช้ One Tap
คุณจะกําหนดค่าไคลเอ็นต์การลงชื่อเข้าใช้ One Tap เพื่อลงชื่อเข้าใช้ให้ผู้ใช้ด้วยรหัสผ่าน ที่บันทึกไว้ บัญชี Google ที่บันทึกไว้ หรือทั้ง 2 อย่างก็ได้ (แนะนําให้ใช้ทั้ง 2 บัญชี เพื่อสร้างบัญชีแบบแตะครั้งเดียวสําหรับผู้ใช้ใหม่ รวมไปถึงการลงชื่อเข้าใช้โดยอัตโนมัติหรือการแตะครั้งเดียว สําหรับผู้ใช้ที่กลับมามากที่สุด)
หากแอปใช้การลงชื่อเข้าใช้ด้วยรหัสผ่าน ให้ใช้ setPasswordRequestOptions()
เพื่อเปิดใช้คําขอข้อมูลเข้าสู่ระบบรหัสผ่าน
หากแอปใช้ Google Sign-In ให้ใช้ setGoogleIdTokenRequestOptions()
เพื่อเปิดใช้และกําหนดค่าคําขอโทเค็นรหัส Google
ตั้งค่ารหัสไคลเอ็นต์ของเซิร์ฟเวอร์เป็นรหัสที่คุณสร้างไว้ในคอนโซล Google APIs โปรดทราบว่านี่คือรหัสไคลเอ็นต์ของเซิร์ฟเวอร์ ไม่ใช่รหัสไคลเอ็นต์ของ Android
กําหนดค่าไคลเอ็นต์ให้กรองตามบัญชีที่ได้รับอนุญาต เมื่อเปิดใช้ตัวเลือกนี้ ไคลเอ็นต์ One Tap จะบอกให้ผู้ใช้ลงชื่อเข้าใช้แอปของคุณด้วย บัญชี Google ที่ผู้ใช้เคยใช้แล้วเท่านั้น ซึ่งจะช่วยผู้ใช้ลงชื่อเข้าใช้ได้สําเร็จเมื่อ #39 ไม่แน่ใจว่ามีบัญชีหรือไม่หรือบัญชี Google ใดที่ใช้อยู่แล้ว และป้องกันไม่ให้ผู้ใช้สร้างบัญชีใหม่ด้วยแอปโดยไม่ตั้งใจ
หากต้องการให้ผู้ใช้ลงชื่อเข้าใช้โดยอัตโนมัติทุกครั้งที่ทําได้ ให้เปิดใช้ฟีเจอร์นี้ด้วย
setAutoSelectEnabled()
การลงชื่อเข้าใช้อัตโนมัติจะทําได้ในกรณีที่เป็นไปตามเกณฑ์ต่อไปนี้- ผู้ใช้มีข้อมูลรับรองที่บันทึกไว้สําหรับแอปของคุณ 1 รายการ นั่นคือรหัสผ่านที่บันทึกไว้ 1 รายการหรือบัญชี Google 1 บัญชีที่บันทึกไว้
- ผู้ใช้ไม่ได้ปิดการลงชื่อเข้าใช้อัตโนมัติในการตั้งค่าบัญชี Google
แม้เราจะไม่บังคับให้ใช้ แต่เราขอแนะนําอย่างยิ่งให้คุณลองใช้ nonces เพื่อปรับปรุงความปลอดภัยในการลงชื่อเข้าใช้และหลีกเลี่ยงการเล่นซ้ํา ใช้ setNonce เพื่อรวม nonce ในคําขอแต่ละรายการ ดูที่ SafetyNet'ขอการเชื่อมต่อ เพื่อดูคําแนะนําและรายละเอียดเพิ่มเติมเกี่ยวกับการสร้าง
Java
public class YourActivity extends AppCompatActivity { // ... private SignInClient oneTapClient; private BeginSignInRequest signInRequest; @Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { super.onCreate(savedInstanceState, persistentState); oneTapClient = Identity.getSignInClient(this); signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.default_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build(); // ... } // ... }
Kotlin
class YourActivity : AppCompatActivity() { // ... private lateinit var oneTapClient: SignInClient private lateinit var signInRequest: BeginSignInRequest override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) oneTapClient = Identity.getSignInClient(this) signInRequest = BeginSignInRequest.builder() .setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder() .setSupported(true) .build()) .setGoogleIdTokenRequestOptions( BeginSignInRequest.GoogleIdTokenRequestOptions.builder() .setSupported(true) // Your server's client ID, not your Android client ID. .setServerClientId(getString(R.string.your_web_client_id)) // Only show accounts previously used to sign in. .setFilterByAuthorizedAccounts(true) .build()) // Automatically sign in when exactly one credential is retrieved. .setAutoSelectEnabled(true) .build() // ... } // ... }
2. ตรวจหาผู้ใช้ที่ลงชื่อเข้าใช้
หากผู้ใช้ที่ลงชื่อเข้าใช้หรือผู้ใช้ที่ออกจากระบบยังใช้ได้ ให้ตรวจสอบสถานะของผู้ใช้ก่อนที่จะแสดง UI การลงชื่อเข้าใช้ด้วย One Tap
คุณควรติดตามด้วยว่าผู้ใช้ได้ปฏิเสธที่จะใช้การลงชื่อเข้าใช้ด้วย One Tap แล้วหรือยัง โดยปิดข้อความแจ้งหรือแตะภายนอก ซึ่งทําได้ง่ายๆ เหมือนพร็อพเพอร์ตี้บูลีนของกิจกรรม (โปรดดูหัวข้อหยุดแสดง UI ของ One Tap ด้านล่าง)
3. แสดง UI การลงชื่อเข้าใช้แบบแตะครั้งเดียว
หากผู้ใช้ไม่ได้ลงชื่อเข้าใช้และยังไม่ได้ปฏิเสธการลงชื่อเข้าใช้ด้วย One Tap โปรดเรียกใช้เมธอด beginSignIn()
ของออบเจ็กต์ไคลเอ็นต์ และแนบ Listener เข้ากับ
Task
ที่แสดงผล โดยปกติแล้ว แอปจะทําวิธีนี้ในเมธอด onCreate()
ของกิจกรรมหรือหลังจากการเปลี่ยนหน้าจอเมื่อใช้สถาปัตยกรรม"กิจกรรม"เดียว
ไคลเอ็นต์ One Tap จะเรียกใช้ Listener สําเร็จหากผู้ใช้มีข้อมูลรับรองที่บันทึกไว้สําหรับแอปของคุณ ใน Listener ความสําเร็จ ให้รับ Intent ที่รอดําเนินการจากผลลัพธ์ Task
และส่งไปยัง startIntentSenderForResult()
เพื่อเริ่ม UI การลงชื่อเข้าใช้ One Tap
หากผู้ใช้ไม่มีข้อมูลเข้าสู่ระบบที่บันทึกไว้ ไคลเอ็นต์ One Tap จะเรียกใช้ Listener ความล้มเหลว ในกรณีนี้ คุณไม่จําเป็นต้องดําเนินการใดๆ เพียงแค่นําเสนอประสบการณ์ออกจากระบบของแอปต่อไป อย่างไรก็ตาม หากคุณรองรับการลงชื่อสมัครใช้ด้วย One Tap คุณสามารถเริ่มขั้นตอนดังกล่าวที่นี่เพื่อให้การสร้างบัญชีเป็นไปอย่างราบรื่น ดูสร้างบัญชีใหม่ด้วยการแตะครั้งเดียว
Java
oneTapClient.beginSignIn(signUpRequest)
.addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
@Override
public void onSuccess(BeginSignInResult result) {
try {
startIntentSenderForResult(
result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.getLocalizedMessage());
}
});
Kotlin
oneTapClient.beginSignIn(signInRequest)
.addOnSuccessListener(this) { result ->
try {
startIntentSenderForResult(
result.pendingIntent.intentSender, REQ_ONE_TAP,
null, 0, 0, 0, null)
} catch (e: IntentSender.SendIntentException) {
Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
.addOnFailureListener(this) { e ->
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d(TAG, e.localizedMessage)
}
4. จัดการคําตอบของผู้ใช้
ระบบจะรายงานคําตอบของผู้ใช้ผ่านข้อความแจ้งให้ลงชื่อเข้าใช้ด้วย One Tap ในแอปของคุณโดยใช้เมธอด onActivityResult()
ของกิจกรรม หากผู้ใช้เลือกที่จะลงชื่อเข้าใช้
ผลการค้นหาจะเป็นข้อมูลเข้าสู่ระบบที่บันทึกไว้ หากผู้ใช้ปฏิเสธการลงชื่อเข้าใช้ ไม่ว่าจะปิด UI ของ One Tap หรือแตะภายนอก ผลลัพธ์จะแสดงด้วยรหัส RESULT_CANCELED
แอปของคุณต้องรองรับความเป็นไปได้ทั้ง 2 อย่าง
ลงชื่อเข้าใช้ด้วยข้อมูลเข้าสู่ระบบที่ดึงมาใช้
หากผู้ใช้เลือกที่จะแชร์ข้อมูลเข้าสู่ระบบกับแอปของคุณ คุณจะดึงข้อมูลได้โดยส่งข้อมูล Intent จาก onActivityResult()
ไปยังเมธอด One Tap ของไคลเอ็นต์ getSignInCredentialFromIntent()
ข้อมูลเข้าสู่ระบบจะมีพร็อพเพอร์ตี้ googleIdToken
ที่ไม่เป็นค่าว่าง หากผู้ใช้แชร์ข้อมูลรับรองของบัญชี Google กับแอปของคุณ หรือพร็อพเพอร์ตี้ password
ที่ไม่ใช่ Null หากผู้ใช้แชร์รหัสผ่านที่บันทึกไว้
ใช้ข้อมูลเข้าสู่ระบบเพื่อตรวจสอบสิทธิ์กับแบ็กเอนด์ของแอป
- หากได้เรียกข้อมูลชื่อผู้ใช้และรหัสผ่านแล้ว ให้ใช้ชื่อผู้ใช้เพื่อลงชื่อเข้าใช้ด้วยวิธีเดียวกับที่คุณจะให้ผู้ใช้ระบุด้วยตัวเอง
หากดึงข้อมูลเข้าสู่ระบบของบัญชี Google แล้ว ให้ใช้โทเค็นรหัสเพื่อตรวจสอบสิทธิ์กับแบ็กเอนด์ หากคุณเลือกใช้ nonces เพื่อช่วยหลีกเลี่ยงการเล่นซ้ํา ให้ตรวจสอบค่าการตอบกลับในเซิร์ฟเวอร์แบ็กเอนด์ของคุณ โปรดดูหัวข้อตรวจสอบสิทธิ์ด้วยแบ็กเอนด์โดยใช้โทเค็นรหัส
Java
public class YourActivity extends AppCompatActivity { // ... private static final int REQ_ONE_TAP = 2; // Can be any integer unique to the Activity. private boolean showOneTapUI = true; // ... @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQ_ONE_TAP: try { SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data); String idToken = credential.getGoogleIdToken(); String username = credential.getId(); String password = credential.getPassword(); if (idToken != null) { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token."); } else if (password != null) { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password."); } } catch (ApiException e) { // ... } break; } } }
Kotlin
class YourActivity : AppCompatActivity() { // ... private val REQ_ONE_TAP = 2 // Can be any integer unique to the Activity private var showOneTapUI = true // ... override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { REQ_ONE_TAP -> { try { val credential = oneTapClient.getSignInCredentialFromIntent(data) val idToken = credential.googleIdToken val username = credential.id val password = credential.password when { idToken != null -> { // Got an ID token from Google. Use it to authenticate // with your backend. Log.d(TAG, "Got ID token.") } password != null -> { // Got a saved username and password. Use them to authenticate // with your backend. Log.d(TAG, "Got password.") } else -> { // Shouldn't happen. Log.d(TAG, "No ID token or password!") } } } catch (e: ApiException) { // ... } } } } // ... }
หยุดแสดง UI แบบแตะครั้งเดียว
หากผู้ใช้ปฏิเสธการลงชื่อเข้าใช้ การเรียก getSignInCredentialFromIntent()
จะแสดง ApiException
พร้อมกับรหัสสถานะ CommonStatusCodes.CANCELED
เมื่อเกิดกรณีเช่นนี้ คุณควรปิดใช้ UI การลงชื่อเข้าใช้ด้วย One Tap ชั่วคราวเพื่อไม่ให้รบกวนผู้ใช้บ่อยๆ เมื่อมีข้อความแจ้งซ้ําๆ ตัวอย่างต่อไปนี้ทําให้สําเร็จโดยการตั้งค่าพร็อพเพอร์ตี้ในกิจกรรม ซึ่งจะใช้เพื่อกําหนดว่าจะเสนอการลงชื่อเข้าใช้ One Tap แก่ผู้ใช้หรือไม่ แต่คุณจะบันทึกค่าลงใน SharedPreferences
หรือใช้วิธีอื่นก็ได้
คุณจําเป็นต้องใช้อัตราการจํากัดอัตราข้อความแจ้งในการลงชื่อเข้าใช้ด้วย One Tap ของคุณเอง หากไม่ดําเนินการ และผู้ใช้ยกเลิกข้อความแจ้งหลายรายการติดต่อกัน ไคลเอ็นต์ One Tap จะไม่ถามผู้ใช้ตลอด 24 ชั่วโมงข้างหน้า
Java
public class YourActivity extends AppCompatActivity { // ... private static final int REQ_ONE_TAP = 2; // Can be any integer unique to the Activity. private boolean showOneTapUI = true; // ... @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQ_ONE_TAP: try { // ... } catch (ApiException e) { switch (e.getStatusCode()) { case CommonStatusCodes.CANCELED: Log.d(TAG, "One-tap dialog was closed."); // Don't re-prompt the user. showOneTapUI = false; break; case CommonStatusCodes.NETWORK_ERROR: Log.d(TAG, "One-tap encountered a network error."); // Try again or just ignore. break; default: Log.d(TAG, "Couldn't get credential from result." + e.getLocalizedMessage()); break; } } break; } } }
Kotlin
class YourActivity : AppCompatActivity() { // ... private val REQ_ONE_TAP = 2 // Can be any integer unique to the Activity private var showOneTapUI = true // ... override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { REQ_ONE_TAP -> { try { // ... } catch (e: ApiException) { when (e.statusCode) { CommonStatusCodes.CANCELED -> { Log.d(TAG, "One-tap dialog was closed.") // Don't re-prompt the user. showOneTapUI = false } CommonStatusCodes.NETWORK_ERROR -> { Log.d(TAG, "One-tap encountered a network error.") // Try again or just ignore. } else -> { Log.d(TAG, "Couldn't get credential from result." + " (${e.localizedMessage})") } } } } } } // ... }
5. จัดการการออกจากระบบ
เมื่อผู้ใช้ออกจากระบบแอป ให้เรียกใช้เมธอด signOut()
ของไคลเอ็นต์ One Tap
การโทร signOut()
จะปิดใช้การลงชื่อเข้าใช้อัตโนมัติจนกว่าผู้ใช้จะลงชื่อเข้าใช้อีกครั้ง
ขั้นตอนนี้สําคัญอย่างยิ่งเนื่องจากจะช่วยให้คุณไม่ต้องลงชื่อเข้าใช้เอง แม้ว่าผู้ใช้จะออกจากระบบแอปไปแล้วก็ตาม และระบบจะรีเซ็ตสถานะการตรวจสอบสิทธิ์ของ API ของบริการ Play ที่คุณใช้ด้วย
ขั้นตอนถัดไป
หากคุณกําหนดค่าไคลเอ็นต์ One Tap เพื่อดึงข้อมูลเข้าสู่ระบบ Google แอปจะรับโทเค็นรหัส Google ที่แสดงถึงผู้ใช้และบัญชี Google ของคุณได้ ดูวิธีใช้โทเค็นเหล่านี้ในแบ็กเอนด์
หากรองรับ Google Sign-In คุณยังใช้ไคลเอ็นต์ One Tap เพื่อเพิ่มขั้นตอนการสร้างบัญชีที่ราบรื่นในแอปได้ด้วย