Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT/#7] kakao login #12

Merged
merged 8 commits into from
Dec 31, 2023
17 changes: 14 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,21 @@ android {
"BASE_URL",
gradleLocalProperties(rootDir).getProperty("base.url"),
)
buildConfigField(
"String",
"NATIVE_APP_KEY",
gradleLocalProperties(rootDir).getProperty("native.app.key"),
)
manifestPlaceholders["NATIVE_APP_KEY"] =
gradleLocalProperties(rootDir).getProperty("native.app.key")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
}
Expand Down Expand Up @@ -95,4 +102,8 @@ dependencies {
implementation(timber)
implementation(ossLicense)
}
}

KakaoDependencies.run {
implementation(user)
}
}
17 changes: 16 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@
android:usesCleartextTraffic="true"
tools:targetApi="31">

<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" />

<data
android:host="oauth"
android:scheme="kakao${NATIVE_APP_KEY}" />
</intent-filter>
</activity>

<activity
android:name="com.going.presentation.mock.MockActivity"
android:exported="true"
Expand All @@ -28,4 +43,4 @@

</application>

</manifest>
</manifest>
7 changes: 6 additions & 1 deletion app/src/main/java/com/going/going/MyApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.going.going

import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.kakao.sdk.common.KakaoSdk
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber

Expand All @@ -13,6 +14,7 @@ class MyApp : Application() {

initTimber()
setDayMode()
initKakaoSdk()
}

private fun initTimber() {
Expand All @@ -23,4 +25,7 @@ class MyApp : Application() {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}

}
private fun initKakaoSdk() {
KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY)
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ buildscript {

tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
}
}
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ object Constants {
const val targetSdk = 34
const val versionCode = 1
const val versionName = "1.0"
}
}
6 changes: 5 additions & 1 deletion buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,8 @@ object FirebaseDependencies {
const val crashlytics = "com.google.firebase:firebase-crashlytics-ktx"
const val analytics = "com.google.firebase:firebase-analytics-ktx"
const val remoteConfig = "com.google.firebase:firebase-config-ktx"
}
}

object KakaoDependencies {
const val user = "com.kakao.sdk:v2-user:${Versions.kakaoVersion}"
}
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ object Versions {
const val balloonVersion = "1.4.5"
const val lottieVersion = "6.0.0"
const val circularProgressBar = "3.1.0"
const val kakaoVersion = "2.14.0"
const val kakaoVersion = "2.19.0"
const val circleIndicatorVersion = "2.1.6"
const val shimmerVersion = "0.5.0"
const val navigationVersion = "2.6.0"
Expand All @@ -44,4 +44,4 @@ object Versions {

val javaVersion = JavaVersion.VERSION_17
const val jvmVersion = "17"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.going.domain.entity.response

data class AuthTokenModel(
val isResigned: Boolean,
val accessToken: String,
val refreshToken: String,
)
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Tue Dec 26 03:22:09 KST 2023
#Fri Dec 29 23:45:17 KST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
Expand Down
6 changes: 5 additions & 1 deletion presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,8 @@ dependencies {
implementation(circularProgressBar)
implementation(circleIndicator)
}
}

KakaoDependencies.run {
implementation(user)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.going.presentation.auth

import android.os.Bundle
import androidx.activity.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.going.presentation.R
import com.going.presentation.databinding.ActivityLoginBinding
import com.going.ui.base.BaseActivity
import com.going.ui.extension.UiState
import com.going.ui.extension.setOnSingleClickListener
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

class LoginActivity : BaseActivity<ActivityLoginBinding>(R.layout.activity_login) {
private val viewModel by viewModels<LoginViewModel>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initKakaoLoginButtonClickListener()
observeInfo()
}

private fun initKakaoLoginButtonClickListener() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요고 함수명 우리 ~ BtnClickListener 로 통일할까?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵! 이런 부분 공유 아주 조아용~

binding.btnSignIn.setOnSingleClickListener {
viewModel.startKakaoLogIn(this)
}
}

private fun observeInfo() {
observeIsAppLoginAvailable()
observePostChangeTokenState()
}
Comment on lines +31 to +34
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두개정도면 따로 함수화 추가적으로 진행 안하고 onCreate에 observe 함수 두개 두는건 어떨까나요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 앞으로 observe 할 값이 많아질 것이라고 예상돼서 묶어뒀습니다!
추후 observe할 데이터 갯수가 더 늘어나지 않거나 얼마 안된다면 onCreate에 합쳐두도록 하겠습니다 :)


private fun observeIsAppLoginAvailable() {
viewModel.isAppLoginAvailable.flowWithLifecycle(lifecycle).onEach { canLogin ->
if (!canLogin) viewModel.startKakaoLogIn(this)
}.launchIn(lifecycleScope)
}

private fun observePostChangeTokenState() {
viewModel.postChangeTokenState.flowWithLifecycle(lifecycle).onEach { tokenState ->
when (tokenState) {
is UiState.Success -> {
// 성공 했을 때 로직
}

is UiState.Failure -> {
// 실패 했을 때 로직
}

is UiState.Empty -> {
// 여튼 로직
}

is UiState.Loading -> {
// 로딩 중 로직
}
}
}.launchIn(lifecycleScope)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.going.presentation.auth

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.going.domain.entity.response.AuthTokenModel
import com.going.ui.extension.UiState
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 kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class LoginViewModel : ViewModel() {
private val _postChangeTokenState = MutableStateFlow<UiState<AuthTokenModel>>(UiState.Empty)
val postChangeTokenState: StateFlow<UiState<AuthTokenModel?>> = _postChangeTokenState

private val _isAppLoginAvailable = MutableStateFlow(true)
val isAppLoginAvailable: StateFlow<Boolean> = _isAppLoginAvailable

private var webLoginCallback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error == null && token != null) {
changeTokenFromServer(
accessToken = token.accessToken,
)
}
}

private var appLoginCallback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
// 뒤로가기 경우 예외 처리
if (!(error is ClientError && error.reason == ClientErrorCause.Cancelled)) {
_isAppLoginAvailable.value = false
}
} else if (token != null) {
changeTokenFromServer(
accessToken = token.accessToken,
)
}
}

fun startKakaoLogIn(context: Context) {
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context) && isAppLoginAvailable.value) {
UserApiClient.instance.loginWithKakaoTalk(
context = context,
callback = appLoginCallback,
)
} else {
UserApiClient.instance.loginWithKakaoAccount(
context = context,
callback = webLoginCallback,
)
}
}

// 서버통신 - 카카오 토큰 보내서 서비스 토큰 받아오기 - 서버와 협의 후 수정예정
private fun changeTokenFromServer(
accessToken: String,
social: String = KAKAO,
) {
_postChangeTokenState.value = UiState.Loading

viewModelScope.launch {
// 통신 로직

// 성공시 서버에서 준 정보를 넣는 예시 코드
_postChangeTokenState.value = UiState.Success(
AuthTokenModel(
isResigned = true,
accessToken = "testAccessToekn",
refreshToken = "testRefreshToekn",
),
)
}
}

companion object {
const val KAKAO = "KAKAO"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,4 @@ class MockActivity() : BaseActivity<ActivityMockBinding>(R.layout.activity_mock)
super.onDestroy()
_adapter = null
}

}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions presentation/src/main/res/layout/activity_login.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/tv_sign_in_title"
android:layout_width="match_parent"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

match_parent 대신 0dp를 사용합시당 ~ 아마 그러면 android:gravity="center" 도 안해도 될듯

Copy link
Member Author

@chattymin chattymin Dec 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 자꾸 까먹네요... 습관 들이게 노력하겠습니다 :)
근데 gravity center안하니까 왼쪽으로 가버리네요 ㅋㅋㅋ
센터 설정은 유지하겠습니당

android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="8dp"
android:gravity="center"
android:lineHeight="42dp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lineHeight 한줄로 설정해두는 것들도 typo에 넣어뒀으니 나중에 UI 수정할때 활용하면 좋을듯합니닷

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 추후에 디자인이 확정되고, 전체 수정할때 참고하도록 하겠습니다!
typo 만드느라 고생하셨습니당 🫶

android:text="@string/sign_in_tv_title"
android:textColor="@color/white"
app:layout_constraintBottom_toTopOf="@id/iv_sign_in"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<ImageView
android:id="@+id/iv_sign_in"
android:layout_width="0dp"
android:layout_height="0dp"
android:minHeight="340dp"
android:scaleType="centerCrop"
android:src="@drawable/img_sign_in_main"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageView
android:id="@+id/btn_sign_in"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:src="@drawable/img_sign_in_kakao_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_sign_in" />

<TextView
android:id="@+id/tv_sign_in_terms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="8dp"
android:gravity="center"
android:lineHeight="42dp"
android:text="@string/sign_in_tv_terms"
android:textColor="@color/white"
app:layout_constraintTop_toBottomOf="@id/btn_sign_in"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
3 changes: 3 additions & 0 deletions presentation/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@

<string name="server_error">서버 통신에 실패했습니다.</string>

<string name="sign_in_tv_title">여행을 시작해보세요</string>
<string name="sign_in_tv_terms"><u>개인정보처리방침</u></string>

</resources>
3 changes: 3 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()

// KakaoSDK repository
maven(url = "https://devrepo.kakao.com/nexus/content/groups/public/")
}
}

Expand Down