구글 로그인 추가
This commit is contained in:
		| @@ -52,6 +52,7 @@ android { | ||||
|             buildConfigField 'String', 'NOTIFLY_PROJECT_ID', '"765102ec85855aa680da35f1b0f55712"' | ||||
|             buildConfigField 'String', 'NOTIFLY_USERNAME', '"voiceon"' | ||||
|             buildConfigField 'String', 'NOTIFLY_PASSWORD', '"c6c585db0aaa4189be44d0467c7d66b6@A"' | ||||
|             buildConfigField 'String', 'GOOGLE_CLIENT_ID', '"983594297130-5hrmkh6vpskeq6v34350kmilf74574h2.apps.googleusercontent.com"' | ||||
|             manifestPlaceholders = [ | ||||
|                 URISCHEME            : "voiceon", | ||||
|                 APPLINK_HOST         : "voiceon.onelink.me", | ||||
| @@ -74,6 +75,7 @@ android { | ||||
|             buildConfigField 'String', 'NOTIFLY_PROJECT_ID', '"5f7ebe90d1ce5f0392164b8a53a662bc"' | ||||
|             buildConfigField 'String', 'NOTIFLY_USERNAME', '"voiceon"' | ||||
|             buildConfigField 'String', 'NOTIFLY_PASSWORD', '"c6c585db0aaa4189be44d0467c7d66b6@A"' | ||||
|             buildConfigField 'String', 'GOOGLE_CLIENT_ID', '"758414412471-mosodbj2chno7l1j0iihldh6edmk0gk9.apps.googleusercontent.com"' | ||||
|             manifestPlaceholders = [ | ||||
|                 URISCHEME            : "voiceon-test", | ||||
|                 APPLINK_HOST         : "voiceon-test.onelink.me", | ||||
| @@ -154,6 +156,10 @@ dependencies { | ||||
|     implementation 'com.google.firebase:firebase-messaging-ktx' | ||||
|     implementation 'com.google.firebase:firebase-config-ktx' | ||||
|  | ||||
|     implementation 'androidx.credentials:credentials:1.3.0' | ||||
|     implementation 'androidx.credentials:credentials-play-services-auth:1.3.0' | ||||
|     implementation 'com.google.android.libraries.identity.googleid:googleid:1.1.1' | ||||
|  | ||||
|     // bootpay | ||||
|     implementation "io.github.bootpay:android:4.4.3" | ||||
|  | ||||
|   | ||||
| @@ -17,6 +17,7 @@ import kr.co.vividnext.sodalive.settings.signout.SignOutRequest | ||||
| import kr.co.vividnext.sodalive.user.find_password.ForgotPasswordRequest | ||||
| import kr.co.vividnext.sodalive.user.login.LoginRequest | ||||
| import kr.co.vividnext.sodalive.user.login.LoginResponse | ||||
| import kr.co.vividnext.sodalive.user.login.SocialLoginRequest | ||||
| import kr.co.vividnext.sodalive.user.signup.SignUpRequest | ||||
| import okhttp3.MultipartBody | ||||
| import retrofit2.http.Body | ||||
| @@ -162,4 +163,10 @@ interface UserApi { | ||||
|         @Path("id") id: Long, | ||||
|         @Header("Authorization") authHeader: String | ||||
|     ): Single<ApiResponse<GetMemberProfileResponse>> | ||||
|  | ||||
|     @POST("/member/login/google") | ||||
|     fun loginGoogle( | ||||
|         @Body request: SocialLoginRequest, | ||||
|         @Header("Authorization") authHeader: String | ||||
|     ): Single<ApiResponse<LoginResponse>> | ||||
| } | ||||
|   | ||||
| @@ -13,6 +13,7 @@ import kr.co.vividnext.sodalive.settings.notification.UpdateNotificationSettingR | ||||
| import kr.co.vividnext.sodalive.settings.signout.SignOutRequest | ||||
| import kr.co.vividnext.sodalive.user.find_password.ForgotPasswordRequest | ||||
| import kr.co.vividnext.sodalive.user.login.LoginRequest | ||||
| import kr.co.vividnext.sodalive.user.login.SocialLoginRequest | ||||
| import kr.co.vividnext.sodalive.user.signup.SignUpRequest | ||||
| import okhttp3.MultipartBody | ||||
|  | ||||
| @@ -124,4 +125,12 @@ class UserRepository(private val userApi: UserApi) { | ||||
|         id: Long, | ||||
|         token: String | ||||
|     ) = userApi.getMemberProfile(id = id, authHeader = token) | ||||
|  | ||||
|     fun googleLogin( | ||||
|         request: SocialLoginRequest, | ||||
|         token: String | ||||
|     ) = userApi.loginGoogle( | ||||
|         request = request, | ||||
|         authHeader = token | ||||
|     ) | ||||
| } | ||||
|   | ||||
| @@ -14,10 +14,22 @@ import android.widget.Toast | ||||
| import androidx.annotation.OptIn | ||||
| import androidx.constraintlayout.widget.ConstraintLayout | ||||
| import androidx.constraintlayout.widget.ConstraintSet | ||||
| import androidx.credentials.Credential | ||||
| import androidx.credentials.CredentialManager | ||||
| import androidx.credentials.CustomCredential | ||||
| import androidx.credentials.GetCredentialRequest | ||||
| import androidx.credentials.exceptions.GetCredentialException | ||||
| import androidx.lifecycle.lifecycleScope | ||||
| import androidx.media3.common.util.UnstableApi | ||||
| import com.google.android.libraries.identity.googleid.GetGoogleIdOption | ||||
| import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential | ||||
| import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential.Companion.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL | ||||
| import com.jakewharton.rxbinding4.widget.textChanges | ||||
| import com.orhanobut.logger.Logger | ||||
| import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers | ||||
| import io.reactivex.rxjava3.schedulers.Schedulers | ||||
| import kotlinx.coroutines.launch | ||||
| import kr.co.vividnext.sodalive.BuildConfig | ||||
| import kr.co.vividnext.sodalive.base.BaseActivity | ||||
| import kr.co.vividnext.sodalive.common.Constants | ||||
| import kr.co.vividnext.sodalive.common.LoadingDialog | ||||
| @@ -101,6 +113,67 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::i | ||||
|                 ) | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         binding.ivLoginGoogle.setOnClickListener { | ||||
|             loadingDialog.show(width = screenWidth) | ||||
|             val credentialManager = CredentialManager.create(this) | ||||
|  | ||||
|             val googleIdOption = GetGoogleIdOption.Builder() | ||||
|                 .setServerClientId(BuildConfig.GOOGLE_CLIENT_ID) | ||||
|                 .setFilterByAuthorizedAccounts(false) | ||||
|                 .setAutoSelectEnabled(false) | ||||
|                 .build() | ||||
|  | ||||
|             // Create the Credential Manager request | ||||
|             val request = GetCredentialRequest.Builder() | ||||
|                 .addCredentialOption(googleIdOption) | ||||
|                 .build() | ||||
|  | ||||
|             lifecycleScope.launch { | ||||
|                 try { | ||||
|                     // Launch Credential Manager UI | ||||
|                     val result = credentialManager.getCredential( | ||||
|                         context = this@LoginActivity, | ||||
|                         request = request | ||||
|                     ) | ||||
|                     loadingDialog.dismiss() | ||||
|  | ||||
|                     // Extract credential from the result returned by Credential Manager | ||||
|                     handleSignIn(result.credential) | ||||
|                 } catch (e: GetCredentialException) { | ||||
|                     showToast("로그인을 하지 못했습니다. 다시 시도해 주세요") | ||||
|                     Logger.e("Couldn't retrieve user's credentials: ${e.localizedMessage}") | ||||
|                     loadingDialog.dismiss() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun handleSignIn(credential: Credential) { | ||||
|         // Check if credential is of type Google ID | ||||
|         if (credential is CustomCredential && credential.type == TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) { | ||||
|             // Create Google ID Token | ||||
|             val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data) | ||||
|             viewModel.googleLogin(idToken = googleIdTokenCredential.idToken) { | ||||
|                 finishAffinity() | ||||
|                 val nextIntent = Intent(applicationContext, MainActivity::class.java) | ||||
|                 val extras = intent.getBundleExtra(Constants.EXTRA_DATA) | ||||
|                     ?: if (intent.extras != null) { | ||||
|                         intent.extras | ||||
|                     } else { | ||||
|                         null | ||||
|                     } | ||||
|                 if (extras != null) { | ||||
|                     nextIntent.putExtra(Constants.EXTRA_DATA, extras) | ||||
|                 } | ||||
|                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | ||||
|                 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) | ||||
|                 startActivity(nextIntent) | ||||
|             } | ||||
|         } else { | ||||
|             showToast("로그인을 하지 못했습니다. 다시 시도해 주세요") | ||||
|             Logger.e("Credential is not of type Google ID!") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun login() { | ||||
|   | ||||
| @@ -22,6 +22,45 @@ class LoginViewModel(private val repository: UserRepository) : BaseViewModel() { | ||||
|     val isLoading: LiveData<Boolean> | ||||
|         get() = _isLoading | ||||
|  | ||||
|     fun googleLogin(idToken: String, onSuccess: () -> Unit) { | ||||
|         _isLoading.value = true | ||||
|  | ||||
|         compositeDisposable.add( | ||||
|             repository.googleLogin( | ||||
|                 request = SocialLoginRequest(marketingPid = SharedPreferenceManager.marketingPid), | ||||
|                 token = "Bearer $idToken" | ||||
|             ) | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|                 .subscribe( | ||||
|                     { | ||||
|                         _isLoading.value = false | ||||
|                         if (it.success && it.data != null) { | ||||
|                             SharedPreferenceManager.token = it.data.token | ||||
|                             SharedPreferenceManager.email = it.data.email | ||||
|                             SharedPreferenceManager.userId = it.data.userId | ||||
|                             SharedPreferenceManager.nickname = it.data.nickname | ||||
|                             SharedPreferenceManager.profileImage = it.data.profileImage | ||||
|                             onSuccess() | ||||
|                         } else { | ||||
|                             if (it.message != null) { | ||||
|                                 _toastLiveData.postValue(it.message) | ||||
|                             } else { | ||||
|                                 _toastLiveData.postValue( | ||||
|                                     "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." | ||||
|                                 ) | ||||
|                             } | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         _isLoading.value = false | ||||
|                         it.message?.let { message -> Logger.e(message) } | ||||
|                         _toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.") | ||||
|                     } | ||||
|                 ) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fun login(onSuccess: (String?) -> Unit) { | ||||
|         if (email.isBlank()) { | ||||
|             _toastLiveData.postValue("이메일을 입력하세요.") | ||||
|   | ||||
| @@ -0,0 +1,10 @@ | ||||
| package kr.co.vividnext.sodalive.user.login | ||||
|  | ||||
| import androidx.annotation.Keep | ||||
| import com.google.gson.annotations.SerializedName | ||||
|  | ||||
| @Keep | ||||
| data class SocialLoginRequest( | ||||
|     @SerializedName("container") val container: String = "aos", | ||||
|     @SerializedName("marketingPid") val marketingPid: String | ||||
| ) | ||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_login_google.png
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_login_google.png
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_login_kakao.png
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable-xxhdpi/ic_login_kakao.png
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.9 KiB | 
| @@ -96,6 +96,21 @@ | ||||
|             android:textColor="@color/white" | ||||
|             android:textSize="15sp" /> | ||||
|  | ||||
|         <LinearLayout | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginHorizontal="13.3dp" | ||||
|             android:layout_marginTop="20dp" | ||||
|             android:gravity="center"> | ||||
|  | ||||
|             <ImageView | ||||
|                 android:id="@+id/iv_login_google" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:contentDescription="@null" | ||||
|                 android:src="@drawable/ic_login_google" /> | ||||
|         </LinearLayout> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/tv_forgot_password" | ||||
|             android:layout_width="wrap_content" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user