From ad6d58b64f0be818a185e560b04c79b14955c321 Mon Sep 17 00:00:00 2001 From: winter223 Date: Sun, 17 Apr 2022 09:28:04 +0900 Subject: [PATCH] =?UTF-8?q?[#30]=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Google OneTabSiginin 작업 --- app/build.gradle | 3 + .../common/extension/ActivityExtension.kt | 5 + .../common/extension/FragmentExtension.kt | 5 + .../moyeorun_android/login/LoginActivity.kt | 101 +++++++++++++++++- app/src/main/res/values/strings.xml | 2 + 5 files changed, 114 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 30bd6ea..0d60182 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,6 +22,7 @@ android { def localProperties = new Properties() localProperties.load(rootProject.file('./local.properties').newDataInputStream()) buildConfigField("String", "BASE_URL", localProperties['baseUrl']) + buildConfigField("String", "WEB_CLIENT_ID", localProperties["webClientId"]) } signingConfigs { @@ -89,6 +90,8 @@ dependencies { implementation platform('com.google.firebase:firebase-bom:29.2.0') implementation 'com.google.firebase:firebase-analytics-ktx' implementation 'com.google.firebase:firebase-crashlytics-ktx' + implementation 'com.google.firebase:firebase-auth-ktx' + implementation 'com.google.android.gms:play-services-auth:20.1.0' // Hilt implementation "com.google.dagger:hilt-android:$hilt_version" diff --git a/app/src/main/java/com/moyerun/moyeorun_android/common/extension/ActivityExtension.kt b/app/src/main/java/com/moyerun/moyeorun_android/common/extension/ActivityExtension.kt index af4d5e4..49e089c 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/common/extension/ActivityExtension.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/common/extension/ActivityExtension.kt @@ -4,6 +4,7 @@ import android.app.Activity import android.widget.Toast import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentActivity +import com.moyerun.moyeorun_android.R fun Activity.toast(msg: String, isShort: Boolean = true) { Toast.makeText(this, msg, if (isShort) Toast.LENGTH_SHORT else Toast.LENGTH_LONG).show() @@ -14,4 +15,8 @@ inline fun FragmentActivity.showAllowingStateLoss( dialogFragmentFactory: () -> DialogFragment ) { supportFragmentManager.showAllowingStateLoss(tag, dialogFragmentFactory) +} + +fun Activity.showNetworkErrorToast() { + toast(getString(R.string.toast_network_error)) } \ No newline at end of file diff --git a/app/src/main/java/com/moyerun/moyeorun_android/common/extension/FragmentExtension.kt b/app/src/main/java/com/moyerun/moyeorun_android/common/extension/FragmentExtension.kt index e36ee18..e505621 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/common/extension/FragmentExtension.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/common/extension/FragmentExtension.kt @@ -4,6 +4,7 @@ import android.widget.Toast import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager +import com.moyerun.moyeorun_android.R fun Fragment.toast(msg: String, isShort: Boolean = false) { Toast.makeText(context, msg, if (isShort) Toast.LENGTH_SHORT else Toast.LENGTH_LONG).show() @@ -19,4 +20,8 @@ inline fun FragmentManager?.showAllowingStateLoss( val transaction = beginTransaction() transaction.add(dialogFragmentFactory(), tag) transaction.commitAllowingStateLoss() +} + +fun Fragment.showNetworkErrorToast() { + toast(getString(R.string.toast_network_error)) } \ No newline at end of file diff --git a/app/src/main/java/com/moyerun/moyeorun_android/login/LoginActivity.kt b/app/src/main/java/com/moyerun/moyeorun_android/login/LoginActivity.kt index 26df5b8..6150ff2 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/login/LoginActivity.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/login/LoginActivity.kt @@ -1,17 +1,114 @@ package com.moyerun.moyeorun_android.login -import androidx.appcompat.app.AppCompatActivity +import android.content.Intent +import android.content.IntentSender import android.os.Bundle +import android.provider.Settings +import androidx.activity.result.IntentSenderRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import com.google.android.gms.auth.api.identity.BeginSignInRequest +import com.google.android.gms.auth.api.identity.Identity +import com.google.android.gms.auth.api.identity.SignInClient +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.CommonStatusCodes +import com.moyerun.moyeorun_android.BuildConfig +import com.moyerun.moyeorun_android.R +import com.moyerun.moyeorun_android.common.Lg +import com.moyerun.moyeorun_android.common.extension.showNetworkErrorToast +import com.moyerun.moyeorun_android.common.extension.toast import com.moyerun.moyeorun_android.databinding.ActivityLoginBinding + class LoginActivity : AppCompatActivity() { + + private val oneTapClient: SignInClient by lazy { Identity.getSignInClient(this) } + private val signInRequest: BeginSignInRequest by lazy { getBeginSignInRequest() } + + private val beginSignInResultLauncher = + registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> + if (result != null) { + try { + val credential = oneTapClient.getSignInCredentialFromIntent(result.data) + val idToken = credential.googleIdToken + if (idToken != null) { + //Todo: 서버에 보내서 인증 @winter223 + // Todo: Firebase crashlytics userId 세팅 + Lg.d("Success. token : $idToken") + } else { + showUnknownErrorToast() + //Todo: #31 을 rebase 하고 주석 풀기 +// Lg.fe("No ID token") + } + } catch (e: ApiException) { + when (e.statusCode) { + CommonStatusCodes.CANCELED -> { /*Doing nothing*/ } + CommonStatusCodes.NETWORK_ERROR -> { + showNetworkErrorToast() + Lg.e("One-tap encountered a network error. $e") + } + else -> { + showUnknownErrorToast() + //Todo: #31 을 rebase 하고 주석 풀기 +// Lg.fe("Couldn't get credential from result.", e) + } + } + } + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = ActivityLoginBinding.inflate(layoutInflater) setContentView(binding.root) binding.buttonLoginGoogle.setOnClickListener { - //Todo: 구글 로그인 작업 @winter223 + oneTapClient.beginSignIn(signInRequest) + .addOnSuccessListener(this) { result -> + try { + val intentSenderRequest = + IntentSenderRequest.Builder(result.pendingIntent.intentSender).build() + beginSignInResultLauncher.launch(intentSenderRequest) + } catch (e: IntentSender.SendIntentException) { + showUnknownErrorToast() +// Lg.fe("Couldn't start One Tab UI", e) + } + } + .addOnFailureListener(this) { + // 기기에 등록된 계정이 없는 경우 호출 + startDeviceGoogleSignInActivity() + //Todo: #31 을 rebase 하고 주석 풀기 + // 간혹 등록된 계정이 있는데도 해당 콜백을 타는 경우가 있어서 로깅 +// Lg.fe("No Google Accounts found", it) + } } } + + private fun startDeviceGoogleSignInActivity() { + startActivity(Intent(Settings.ACTION_ADD_ACCOUNT).apply { + addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) + flags = Intent.FLAG_ACTIVITY_NEW_TASK + putExtra(Settings.EXTRA_ACCOUNT_TYPES, arrayOf("com.google")) + }) + } + + private fun getBeginSignInRequest(): BeginSignInRequest { + return BeginSignInRequest.builder() + .setGoogleIdTokenRequestOptions( + BeginSignInRequest.GoogleIdTokenRequestOptions.builder() + .setSupported(true) + .setServerClientId(BuildConfig.WEB_CLIENT_ID) + // false 로 설정해서 앱에 로그인한 적이 있는 계정뿐만 아니라 + // 기기에 등록된 구글 계정을 모두 보여준다 + .setFilterByAuthorizedAccounts(false) + .build() + ) + // 하나의 계정만 있다면 자동으로 선택 + .setAutoSelectEnabled(true) + .build() + } + + private fun showUnknownErrorToast() { + toast(getString(R.string.login_toast_unknown_error)) + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bc81fd2..d3e208c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,8 +4,10 @@ 취소 확인 + 네트워크 연결 상태를 확인해주세요. 시작하기 구글 계정으로 로그인 + 로그인에 실패하였습니다. \ No newline at end of file