경고 : 이 데이터는 Google 사용자 데이터 정책에 따라 제공됩니다. 정책을 검토하고 준수하십시오. 그렇게하지 않으면 프로젝트가 정지되거나 계정이 정지 될 수 있습니다.

탭 한 번으로 새 계정 만들기

Google 계정으로 로그인을 지원하는 경우 원탭 로그인 클라이언트를 사용하여 사용자가 앱의 컨텍스트에서 절대 벗어나지 않는 원활한 계정 생성 환경을 제공할 수도 있습니다.

원탭 가입 UI

원탭 UI를 표시하면 기기에 기기의 Google 계정 중 하나를 사용하여 앱으로 새 계정을 만들라는 메시지가 표시됩니다. 사용자가 계속 진행하면 기본 프로필 정보(이름, 프로필 사진, 인증된 이메일 주소)가 포함된 ID 토큰이 생성됩니다. 이 토큰을 사용하여 새 계정을 만들 수 있습니다.

원탭 계정 생성을 구현하는 작업은 다음과 같이 두 부분으로 구성됩니다.

  • 이 페이지에 설명된 대로 원탭 클라이언트를 앱에 통합합니다. 이는 원탭 로그인을 사용하는 것과 거의 동일하지만 구성상의 차이가 있습니다.
  • Google ID 토큰에서 사용자 계정을 만드는 기능이 백엔드에 추가되었습니다. 자세한 내용은 백엔드에서 ID 토큰 사용을 참조하세요.

원탭 가입은 어디에서 사용해야 하나요?

사용자에게 원탭 가입을 제공하는 가장 효과적인 방법은 로그인 시 새로운 기능이 사용 설정되는 것입니다. 먼저 저장된 사용자 인증 정보로 사용자 로그인을 시도합니다. 저장된 사용자 인증 정보가 없으면 해당 사용자의 새 계정을 만들라는 메시지가 표시됩니다.

시작하기 전에

원탭 로그인 시작하기에 설명된 대로 Google API 콘솔 프로젝트와 Android 프로젝트를 설정합니다.

1. 원탭 클라이언트 구성

계정 생성을 위해 원탭 클라이언트를 구성하려면 다음 안내를 따르세요.

  • 비밀번호 사용자 인증 정보 요청을 사용 설정하지 마세요. (원탭 가입은 토큰 기반 인증으로만 가능합니다.)
  • setGoogleIdTokenRequestOptions() 및 다음 설정을 사용하여 Google ID 토큰 요청을 사용 설정합니다.

    • 서버 클라이언트 ID를 Google API 콘솔에서 만든 ID로 설정합니다. 이는 Android 클라이언트 ID가 아니라 서버의 클라이언트 ID입니다.
    • 기기에 모든 Google 계정(즉, 승인된 계정으로 필터링하지 않음)을 표시하도록 클라이언트를 구성합니다.
    • 선택적으로 계정의 인증된 전화번호를 요청할 수도 있습니다.

자바

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 취소 추적하기

사용자가 메시지를 닫거나 탭 바깥을 탭하여 원탭 가입 사용을 이미 거부했는지 여부를 추적해야 합니다. 활동의 부울 속성만큼 간단할 수도 있습니다. (아래의 원탭 UI 표시 중지를 참고하세요.)

3. 원탭 가입 UI 표시

사용자가 원탭 사용으로 새 계정을 만들지 않은 경우 클라이언트 객체의 beginSignIn() 메서드를 호출하고 반환된 Task에 리스너를 연결합니다. 앱은 일반적으로 원탭 로그인 요청에서 저장된 사용자 인증 정보를 찾을 수 없을 때, 즉 로그인 요청의 실패 리스너에서 이 단계를 수행합니다.

사용자가 기기에 Google 계정을 하나 이상 설정한 경우 원탭 클라이언트에서 성공 리스너를 호출합니다. 성공 리스너의 Task 결과에서 대기 중인 인텐트를 가져와서 startIntentSenderForResult()에 전달하여 원탭 UI를 시작합니다.

사용자가 기기에 Google 계정을 보유하고 있지 않은 경우 원탭 클라이언트는 실패 리스너를 호출합니다. 이 경우 별도의 조치를 취할 필요가 없습니다. 앱의 로그아웃 환경을 제공하기만 하면 됩니다. 그러면 사용자가 일반적인 계정 생성 흐름으로 가입할 수 있습니다.

자바

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. 사용자의 응답 처리

원탭 가입 프롬프트에 대한 사용자의 응답은 내 활동의 onActivityResult() 메서드를 사용하여 앱에 보고됩니다. 사용자가 계정을 만들기로 선택하면 결과는 Google ID 토큰이 됩니다. 사용자가 원탭 UI를 닫거나 외부를 탭하여 가입을 거부하면 RESULT_CANCELED 코드와 함께 결과가 반환됩니다. 앱은 두 가능성을 모두 처리해야 합니다.

Google ID 토큰으로 계정 만들기

사용자가 Google 계정으로 가입하기로 결정했다면 onActivityResult()의 인텐트 데이터를 원탭 클라이언트의 getSignInCredentialFromIntent() 메서드에 전달하여 사용자의 ID 토큰을 가져올 수 있습니다. 사용자 인증 정보에는 null이 아닌 googleIdToken 속성이 포함됩니다.

ID 토큰을 사용하여 백엔드에 계정을 만들고 (ID 토큰을 사용하여 백엔드로 인증 참고) 사용자를 로그인 처리합니다.

사용자 인증 정보에는 계정의 확인된 전화번호와 같이 요청한 추가 세부정보도 포함됩니다.

자바

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 표시 중지

사용자가 로그인을 거부한 경우 getSignInCredentialFromIntent()를 호출하면 CommonStatusCodes.CANCELED 상태 코드와 함께 ApiException이 발생합니다. 이러한 상황에서는 원탭 로그인 UI 표시를 일시적으로 중단하여 반복적인 메시지로 사용자를 성가시게 하지 않아야 합니다. 다음 예에서는 활동에서 속성을 설정하여 사용자에게 한 번 로그인을 제공할지 여부를 결정하는 방법을 사용합니다. 그러나 값을 SharedPreferences에 저장하거나 다른 방법을 사용할 수도 있습니다.

원탭 로그인 메시지에 대해 비율 제한을 직접 구현하는 것이 중요합니다. 이 작업을 하지 않고 사용자가 연속으로 여러 개의 메시지를 취소하면 원탭 클라이언트가 사용자에게 다음 24시간 동안 메시지를 표시하지 않습니다.

자바

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})")
                        }
                    }
                }
            }
        }
    }
    // ...
}

다음 단계

사용자가 원탭 가입 절차를 완료하면 사용자의 이메일 주소, 전체 이름, 프로필 사진 URL 등 기본 프로필 정보가 포함된 Google ID 토큰이 제공됩니다. 대부분의 앱에서는 이 정보로 백엔드에서 사용자를 인증하고 새 계정을 만들 수 있습니다.

계정 생성을 완료하기 위해 추가 정보가 필요한 경우(예: 사용자의 생년월일) 사용자에게 추가 세부정보를 요청하는 가입 세부정보 흐름을 제공합니다. 그런 다음 백엔드로 전송하여 계정 생성을 완료합니다.