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

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

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

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

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

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

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

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

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

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

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

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

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

    • ตั้งค่ารหัสไคลเอ็นต์ของเซิร์ฟเวอร์เป็น รหัสที่คุณสร้างในคอนโซล Google API โปรดทราบว่านี่คือรหัสไคลเอ็นต์ของเซิร์ฟเวอร์ ไม่ใช่รหัสไคลเอ็นต์ 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 ที่สำเร็จ ให้รับ PendingIntent จากผลลัพธ์ 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 หากผู้ใช้ปฏิเสธที่จะลงชื่อสมัครใช้ ไม่ว่าจะโดยการปิด UI ของ One Tap หรือแตะนอก UI ผลลัพธ์จะแสดงรหัส RESULT_CANCELED แอปของคุณต้องจัดการทั้ง 2 กรณี

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

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

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

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

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 รูปโปรไฟล์ของผู้ใช้ สำหรับแอปจำนวนมาก ข้อมูลนี้เพียงพอให้คุณ ตรวจสอบสิทธิ์ผู้ใช้ในแบ็กเอนด์และสร้างบัญชีใหม่

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