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

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

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

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

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

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

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

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

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

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