카카오 로그인 추가

This commit is contained in:
klaus 2025-04-07 19:20:57 +09:00
parent a9885874ee
commit d4796257b3
10 changed files with 160 additions and 2 deletions

View File

@ -52,12 +52,14 @@ android {
buildConfigField 'String', 'NOTIFLY_PROJECT_ID', '"765102ec85855aa680da35f1b0f55712"'
buildConfigField 'String', 'NOTIFLY_USERNAME', '"voiceon"'
buildConfigField 'String', 'NOTIFLY_PASSWORD', '"c6c585db0aaa4189be44d0467c7d66b6@A"'
buildConfigField 'String', 'KAKAO_APP_KEY', '"231cf78acfa8252fca38b9eedf87c5cb"'
buildConfigField 'String', 'GOOGLE_CLIENT_ID', '"983594297130-5hrmkh6vpskeq6v34350kmilf74574h2.apps.googleusercontent.com"'
manifestPlaceholders = [
URISCHEME : "voiceon",
APPLINK_HOST : "voiceon.onelink.me",
FACEBOOK_APP_ID : "612448298237287",
FACEBOOK_CLIENT_TOKEN: "32af760f4a7b7cb7e3b1e7ffd0b0da70"
FACEBOOK_CLIENT_TOKEN: "32af760f4a7b7cb7e3b1e7ffd0b0da70",
KAKAO_APP_KEY: "231cf78acfa8252fca38b9eedf87c5cb"
]
}
@ -75,12 +77,14 @@ android {
buildConfigField 'String', 'NOTIFLY_PROJECT_ID', '"5f7ebe90d1ce5f0392164b8a53a662bc"'
buildConfigField 'String', 'NOTIFLY_USERNAME', '"voiceon"'
buildConfigField 'String', 'NOTIFLY_PASSWORD', '"c6c585db0aaa4189be44d0467c7d66b6@A"'
buildConfigField 'String', 'KAKAO_APP_KEY', '"20cf19413d63bfdfd30e8e6dff933d33"'
buildConfigField 'String', 'GOOGLE_CLIENT_ID', '"758414412471-mosodbj2chno7l1j0iihldh6edmk0gk9.apps.googleusercontent.com"'
manifestPlaceholders = [
URISCHEME : "voiceon-test",
APPLINK_HOST : "voiceon-test.onelink.me",
FACEBOOK_APP_ID : "608674328645232",
FACEBOOK_CLIENT_TOKEN: "3775e6ea83236a685d264b6c5a1bbb4d"
FACEBOOK_CLIENT_TOKEN: "3775e6ea83236a685d264b6c5a1bbb4d",
KAKAO_APP_KEY: "20cf19413d63bfdfd30e8e6dff933d33"
]
}
}
@ -197,4 +201,9 @@ dependencies {
//
implementation 'com.github.team-michael:notifly-android-sdk:1.12.0'
// Kakao
implementation "com.kakao.sdk:v2-common:2.21.0"
implementation "com.kakao.sdk:v2-auth:2.21.0"
implementation "com.kakao.sdk:v2-user:2.21.0"
}

View File

@ -229,3 +229,11 @@
# @Keep 애노테이션이 붙은 클래스, 메서드, 필드를 보호
-keep @androidx.annotation.Keep class * { *; }
-keep class com.kakao.sdk.**.model.* { <fields>; }
-keep class * extends com.google.gson.TypeAdapter
# https://github.com/square/okhttp/pull/6792
-dontwarn org.bouncycastle.jsse.**
-dontwarn org.conscrypt.*
-dontwarn org.openjsse.**

View File

@ -198,6 +198,20 @@
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
android:theme="@style/Theme.AppCompat.DayNight" />
<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Redirect URI: "kakao${NATIVE_APP_KEY}://oauth" -->
<data android:host="oauth"
android:scheme="kakao${KAKAO_APP_KEY}" />
</intent-filter>
</activity>
<service
android:name=".common.SodaLiveService"
android:foregroundServiceType="microphone|mediaPlayback"

View File

@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatDelegate
import com.appsflyer.AppsFlyerLib
import com.appsflyer.deeplink.DeepLinkResult
import com.facebook.FacebookSdk
import com.kakao.sdk.common.KakaoSdk
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
import kr.co.vividnext.sodalive.BuildConfig
@ -37,6 +38,8 @@ class SodaLiveApp : Application() {
FacebookSdk.fullyInitialize()
KakaoSdk.init(applicationContext, BuildConfig.KAKAO_APP_KEY)
setupAppsFlyer()
setupNotifly()

View File

@ -169,4 +169,11 @@ interface UserApi {
@Body request: SocialLoginRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<LoginResponse>>
@POST("/member/login/kakao")
fun loginKakao(
@Body request: SocialLoginRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<LoginResponse>>
}

View File

@ -133,4 +133,12 @@ class UserRepository(private val userApi: UserApi) {
request = request,
authHeader = token
)
fun kakaoLogin(
request: SocialLoginRequest,
token: String
) = userApi.loginKakao(
request = request,
authHeader = token
)
}

View File

@ -25,6 +25,10 @@ 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.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.model.ClientError
import com.kakao.sdk.common.model.ClientErrorCause
import com.kakao.sdk.user.UserApiClient
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
@ -147,6 +151,8 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::i
}
}
}
binding.ivLoginKakao.setOnClickListener { loginKakao() }
}
private fun handleSignIn(credential: Credential) {
@ -255,4 +261,59 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::i
)
}, 100)
}
private val kakaoLoginCallback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
loadingDialog.dismiss()
if (error != null) {
showToast("카카오 계정으로 로그인 하지 못했습니다. 다시 시도해 주세요")
} else if (token != null) {
handleKakaoLogin(token)
}
}
private fun loginKakao() {
loadingDialog.show(screenWidth)
if (UserApiClient.instance.isKakaoTalkLoginAvailable(this@LoginActivity)) {
UserApiClient.instance.loginWithKakaoTalk(this@LoginActivity) { token, error ->
if (error != null) {
Logger.e("error: ${error.message}, ${error.cause}")
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
loadingDialog.dismiss()
return@loginWithKakaoTalk
} else {
UserApiClient.instance.loginWithKakaoAccount(
this@LoginActivity,
callback = kakaoLoginCallback
)
}
} else if (token != null) {
handleKakaoLogin(token)
}
}
} else {
UserApiClient.instance.loginWithKakaoAccount(
this@LoginActivity,
callback = kakaoLoginCallback
)
}
}
private fun handleKakaoLogin(token: OAuthToken) {
viewModel.kakaoLogin(accessToken = token.accessToken) {
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)
}
}
}

View File

@ -22,6 +22,45 @@ class LoginViewModel(private val repository: UserRepository) : BaseViewModel() {
val isLoading: LiveData<Boolean>
get() = _isLoading
fun kakaoLogin(accessToken: String, onSuccess: () -> Unit) {
_isLoading.value = true
compositeDisposable.add(
repository.kakaoLogin(
request = SocialLoginRequest(marketingPid = SharedPreferenceManager.marketingPid),
token = "Bearer $accessToken"
)
.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 googleLogin(idToken: String, onSuccess: () -> Unit) {
_isLoading.value = true

View File

@ -103,6 +103,14 @@
android:layout_marginTop="20dp"
android:gravity="center">
<ImageView
android:id="@+id/iv_login_kakao"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="13.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_login_kakao" />
<ImageView
android:id="@+id/iv_login_google"
android:layout_width="wrap_content"

View File

@ -12,6 +12,7 @@ dependencyResolutionManagement {
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url = "https://devrepo.kakao.com/nexus/content/groups/public/" }
}
}
rootProject.name = "SodaLive"