สร้างบัญชีใหม่ด้วยการแตะเพียงครั้งเดียว

หากคุณรองรับการลงชื่อเข้าใช้ด้วยบัญชี Google คุณก็สามารถใช้ไคลเอ็นต์การลงชื่อเข้าใช้ด้วย One Tap เพื่อมอบประสบการณ์การสร้างบัญชีที่ราบรื่นให้กับผู้ใช้ ซึ่งจะไม่พาผู้ใช้ออกไปจากบริบทของแอปอีกต่อไป

UI ลงชื่อสมัครใช้ด้วยการแตะเพียงครั้งเดียว

เมื่อคุณแสดง UI ของ One Tap ผู้ใช้จะได้รับแจ้งให้สร้างบัญชีใหม่ด้วยแอปของคุณโดยใช้บัญชี Google บัญชีใดบัญชีหนึ่งในอุปกรณ์ของตน หากผู้ใช้เลือกที่จะดำเนินการต่อ คุณจะได้รับโทเค็นรหัสที่มีข้อมูลโปรไฟล์พื้นฐาน ซึ่งได้แก่ ชื่อ รูปโปรไฟล์ และที่อยู่อีเมลที่ยืนยันแล้ว ซึ่งคุณนำไปใช้สร้างบัญชีใหม่ได้

การสร้างบัญชีด้วย One Tap มี 2 ส่วน ดังนี้

  • การผสานรวมไคลเอ็นต์ One Tap เข้ากับแอป ซึ่งอธิบายไว้ในหน้านี้ ซึ่งส่วนใหญ่แล้วจะเหมือนกับการลงชื่อเข้าใช้ด้วย One Tap แต่มีความแตกต่างบางอย่างในการกำหนดค่า
  • การเพิ่มความสามารถในการสร้างบัญชีผู้ใช้จากโทเค็นรหัส Google ลงในแบ็กเอนด์ ซึ่งจะมีการอธิบายในหัวข้อการใช้โทเค็นรหัสในแบ็กเอนด์

ฉันควรใช้การลงชื่อสมัครใช้ One Tap ที่ใด

แพลตฟอร์มที่ให้ผลลัพธ์สูงสุดในการเสนอการลงชื่อสมัครใช้ One Tap แก่ผู้ใช้คือในบริบทที่การลงชื่อเข้าใช้จะช่วยให้มีฟีเจอร์ใหม่ๆ ได้ ขั้นแรก ให้ลองลงชื่อเข้าใช้ให้ผู้ใช้ ด้วยข้อมูลรับรองที่บันทึกไว้ หากไม่พบข้อมูลเข้าสู่ระบบที่บันทึกไว้ ให้เสนอให้สร้างบัญชีใหม่สำหรับผู้ใช้

ก่อนเริ่มต้น

ตั้งค่าโปรเจ็กต์คอนโซล Google APIs และโปรเจ็กต์ Android ตามที่อธิบายไว้ในเริ่มต้นใช้งานการลงชื่อเข้าใช้ด้วย One Tap

1. กำหนดค่าไคลเอ็นต์ One Tap

หากต้องการกำหนดค่าไคลเอ็นต์ One Tap สำหรับสร้างบัญชี ให้ทำตามขั้นตอนต่อไปนี้

  • อย่าเปิดใช้คำขอข้อมูลเข้าสู่ระบบของรหัสผ่าน (การลงชื่อสมัครใช้ด้วยการแตะเพียงครั้งเดียวจะทำได้ ด้วยการตรวจสอบสิทธิ์ที่ใช้โทเค็นเท่านั้น)
  • เปิดใช้คำขอโทเค็น Google ID โดยใช้ setGoogleIdTokenRequestOptions() และการตั้งค่าต่อไปนี้

    • ตั้งค่ารหัสไคลเอ็นต์ของเซิร์ฟเวอร์เป็นรหัสที่คุณสร้างในคอนโซล Google APIs โปรดทราบว่านี่คือรหัสไคลเอ็นต์ของเซิร์ฟเวอร์ ไม่ใช่รหัสไคลเอ็นต์ Android ของคุณ
    • กำหนดค่าไคลเอ็นต์ให้แสดงบัญชี Google ทั้งหมดในอุปกรณ์ กล่าวคือไม่ต้องกรองตามบัญชีที่ได้รับอนุญาต
    • นอกจากนี้ คุณยังขอหมายเลขโทรศัพท์ที่ยืนยันแล้วสำหรับบัญชีได้ด้วย

Java

public class YourActivity extends AppCompatActivity {

  // ...

  private SignInClient oneTapClient;
  private BeginSignInRequest signUpRequest;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState,
                       @Nullable PersistableBundle persistentState) {
      super.onCreate(savedInstanceState, persistentState);

      oneTapClient = Identity.getSignInClient(this);
      signUpRequest = BeginSignInRequest.builder()
              .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder()
                      .setSupported(true)
                      // Your server's client ID, not your Android client ID.
                      .setServerClientId(getString(R.string.your_web_client_id))
                      // Show all accounts on the device.
                      .setFilterByAuthorizedAccounts(false)
                      .build())
              .build();

      // ...
  }
}

Kotlin

class YourActivity : AppCompatActivity() {
    // ...

    private lateinit var oneTapClient: SignInClient
    private lateinit var signUpRequest: BeginSignInRequest

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        oneTapClient = Identity.getSignInClient(this)
        signUpRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.your_web_client_id))
                    // Show all accounts on the device.
                    .setFilterByAuthorizedAccounts(false)
                    .build())
            .build()
        // ...
    }
    // ...
}

2. ติดตามการยกเลิก UI ของ One Tap

คุณควรติดตามว่าผู้ใช้ปฏิเสธที่จะใช้การลงชื่อสมัครใช้ One Tap แล้วหรือยังโดยการปิดข้อความแจ้งหรือแตะภายนอก ซึ่งอาจเป็นพร็อพเพอร์ตี้บูลีนของกิจกรรมได้ง่ายๆ (ดูหยุดแสดง UI ของ One Tap ด้านล่าง)

3. แสดง UI การลงชื่อสมัครใช้ด้วย One Tap

หากผู้ใช้ไม่ได้ปฏิเสธที่จะใช้ One Tap เพื่อสร้างบัญชีใหม่ ให้เรียกใช้เมธอด beginSignIn() ของออบเจ็กต์ไคลเอ็นต์ และแนบ Listener กับ Task ที่ส่งกลับ แอปมักจะทำขั้นตอนนี้เมื่อคำขอลงชื่อเข้าใช้ One Tap ไม่พบข้อมูลเข้าสู่ระบบที่บันทึกไว้ กล่าวคือใน Listener ความล้มเหลวของคำขอลงชื่อเข้าใช้

ไคลเอ็นต์ One Tap จะโทรหา Listener ที่สำเร็จหากผู้ใช้มีการตั้งค่าบัญชี Google ไว้อย่างน้อย 1 บัญชีในอุปกรณ์ ใน Listener ที่สำเร็จ ให้รับ Intent ที่รอดำเนินการจากผลลัพธ์ Task แล้วส่งไปยัง startIntentSenderForResult() เพื่อเริ่ม UI ของ One Tap

หากผู้ใช้ไม่มีบัญชี Google ในอุปกรณ์ ไคลเอ็นต์ One Tap จะเรียก Listener ที่ล้มเหลว ในกรณีนี้ คุณไม่จำเป็นต้องดำเนินการใดๆ คุณเพียงแค่นำเสนอประสบการณ์การออกจากระบบของแอปต่อไป และผู้ใช้จะลงชื่อสมัครใช้ผ่านขั้นตอนการสร้างบัญชีตามปกติได้

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 Google Accounts found. Just continue presenting the signed-out UI.
                Log.d(TAG, e.getLocalizedMessage());
            }
        });

Kotlin

oneTapClient.beginSignIn(signUpRequest)
    .addOnSuccessListener(this) { result ->
        try {
            startIntentSenderForResult(
                result.pendingIntent.intentSender, REQ_ONE_TAP,
                null, 0, 0, 0)
        } catch (e: IntentSender.SendIntentException) {
            Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
        }
    }
    .addOnFailureListener(this) { e ->
        // No Google Accounts found. Just continue presenting the signed-out UI.
        Log.d(TAG, e.localizedMessage)
    }

4. จัดการการตอบสนองของผู้ใช้

ระบบจะรายงานการตอบสนองของผู้ใช้ต่อข้อความแจ้งให้ลงชื่อสมัครใช้ One Tap ไปยังแอปของคุณโดยใช้เมธอด onActivityResult() ของกิจกรรม หากผู้ใช้เลือกสร้างบัญชี ผลลัพธ์ที่ได้จะเป็นโทเค็น Google ID หากผู้ใช้ปฏิเสธการลงชื่อสมัครใช้ ไม่ว่าจะด้วยการปิด One Tap UI หรือแตะภายนอก UI ดังกล่าว ระบบจะแสดงผลลัพธ์พร้อมรหัส RESULT_CANCELED แอปของคุณต้องจัดการความเป็นไปได้ทั้ง 2 อย่าง

สร้างบัญชีด้วยโทเค็น Google ID

หากผู้ใช้เลือกลงชื่อสมัครใช้ด้วยบัญชี Google คุณจะรับโทเค็นรหัสสำหรับผู้ใช้ได้โดยส่งข้อมูล Intent จาก onActivityResult() ไปยังเมธอด getSignInCredentialFromIntent() ของไคลเอ็นต์ One Tap ข้อมูลเข้าสู่ระบบจะมีพร็อพเพอร์ตี้ googleIdToken ที่ไม่เป็นค่าว่าง

ใช้โทเค็นรหัสเพื่อสร้างบัญชีบนแบ็กเอนด์ (ดูตรวจสอบสิทธิ์ด้วยแบ็กเอนด์โดยใช้โทเค็นรหัส) แล้วลงชื่อเข้าใช้ให้ผู้ใช้

ข้อมูลเข้าสู่ระบบยังมีรายละเอียดเพิ่มเติมอื่นๆ ที่คุณขอมา เช่น หมายเลขโทรศัพท์ที่ยืนยันแล้วของบัญชี (หากมี)

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();
                  if (idToken !=  null) {
                      // Got an ID token from Google. Use it to authenticate
                      // with your backend.
                      Log.d(TAG, "Got ID token.");
                  }
              } 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
                    when {
                        idToken != null -> {
                            // Got an ID token from Google. Use it to authenticate
                            // with your backend.
                            Log.d(TAG, "Got ID token.")
                        }
                        else -> {
                            // Shouldn't happen.
                            Log.d(TAG, "No ID token!")
                        }
                    }
                } catch (e: ApiException) {
                    // ...
            }
        }
    }
    // ...
}

หยุดแสดง UI ของ One Tap

หากผู้ใช้ปฏิเสธการลงชื่อเข้าใช้ สายที่โทรหา 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})")
                        }
                    }
                }
            }
        }
    }
    // ...
}

ขั้นตอนถัดไป

เมื่อผู้ใช้ลงชื่อสมัครใช้ One Tap เสร็จเรียบร้อย คุณจะได้รับโทเค็นรหัส Google ซึ่งประกอบด้วยข้อมูลโปรไฟล์พื้นฐานบางส่วน เช่น ที่อยู่อีเมล ชื่อเต็มของผู้ใช้ และ URL รูปโปรไฟล์ สำหรับแอปจำนวนมาก ข้อมูลนี้เพียงพอแล้วที่คุณจะ ตรวจสอบสิทธิ์ผู้ใช้ในระบบแบ็กเอนด์และสร้างบัญชีใหม่

หากคุณต้องการข้อมูลเพิ่มเติมเพื่อการสร้างบัญชีให้เสร็จสมบูรณ์ เช่น วันเกิดของผู้ใช้ ให้แจ้งผู้ใช้ด้วยขั้นตอนรายละเอียดการลงชื่อสมัครใช้ ซึ่งคุณจะขอข้อมูลเพิ่มเติมนี้ได้ จากนั้นให้ส่งไปยังแบ็กเอนด์เพื่อสร้างบัญชีให้เสร็จสมบูรณ์