IT 프로그래밍-Android

[안드로이드] 카카오 로그인 API v2 적용하기

godsangin 2021. 10. 23. 15:36
반응형

안녕하세요. 오랜만에 안드로이드 개발기로 찾아 뵙습니다!!

 

오늘은 카카오 로그인 API v2 적용기를 다뤄보려 합니다.

 

해당 내용은 아래 Kakao Developers의 내용을 참고하여 작성하였습니다.

https://developers.kakao.com/docs/latest/ko/kakaologin/android

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

build.gradle 설정은 kakao v2-user로 설정되었다고 가정하고 진행하도록 하겠습니다.

//카카오
    implementation "com.kakao.sdk:v2-user:2.8.1" // 카카오 로그인

 

기본적으로 개발자 계정으로 카카오 애플리케이션을 등록하고 앱 키 발급, Redirect URL, 안드로이드 플랫폼 등록까지 마쳐야 합니다.

우선 개발자계정으로 애플리케이션을 등록한 뒤 내 애플리케이션-앱 설정-앱 키에 네이티브 앱 키를 사용하여 Manifest.xml, Application 설정에 추가해야 합니다.

<manifest
   ...>
   <application
        android:name=".application.MyApplication"
        ...>
        <activity android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity">
            <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{MyNativeAppKey}" />
            </intent-filter>
        </activity>
        ...
    </application>
    ...
</manifest>

<manifest.xml>

package com.myhome.onu.application

import android.app.Application
import android.util.Log
import com.kakao.sdk.common.KakaoSdk
import com.myhome.onu.R
//import com.myhome.onu.di.AppComponent
//import com.myhome.onu.di.DaggerAppComponent
//import com.uber.rxdogtag.RxDogTag
//import io.reactivex.plugins.RxJavaPlugins
import kotlin.system.exitProcess

class MyApplication : Application() {

    companion object {
        private val TAG = MyApplication::class.java.simpleName
    }

    //val appComponent:AppComponent by lazy {
    //    DaggerAppComponent.factory().create(this)
    //}
    private var androidDefaultUncaughtExceptionHandler: Thread.UncaughtExceptionHandler? = null
    private lateinit var uncaughtExceptionHandler:UncaughtExceptionHandler

    override fun onCreate() {
        //RxDogTag.install()
        //RxJavaPlugins.setErrorHandler{Log.w("APP#", it)}
        androidDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
        uncaughtExceptionHandler = UncaughtExceptionHandler()
        super.onCreate()
        // Kakao SDK 초기화
        KakaoSdk.init(this, getString(R.string.kakao_native_app_key))

    }

    class UncaughtExceptionHandler:Thread.UncaughtExceptionHandler{
        override fun uncaughtException(t: Thread, ex: Throwable) {
            Log.e(TAG, "error ------------>$ex")
            android.os.Process.killProcess(android.os.Process.myPid())
            exitProcess(0)
        }
    }
}

<MyApplication.kt>

var keyHash = Utility.getKeyHash(this)
Log.d("keyHash==", keyHash)

그런 뒤 위 코드를 실행하여 애플리케이션의 KeyHash를 복사하고 이를 앱 설정-플랫폼-Android에 등록합니다.

 

여기까지 수행했으면 거의 모든 절차가 끝났습니다.

마지막으로 애플리케이션-제품 설정-카카오 로그인을 활성화하고 Redirect URL을 설정합니다.(Redirect URL의 경우 애플리케이션의 특정 URL이 없다면 example.com/oauth 등으로 임시 설정해도 정상 동작합니다)

자 ! 이제 모든 준비가 끝났습니다.

그러면 로그인하려는 로직에 로그인 코드만 추가하면 정상적으로 로그인을 수행하실 수 있습니다.

package com.myhome.onu.main.certification

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.kakao.sdk.auth.AuthApiClient
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.user.UserApiClient
import com.myhome.onu.R
import com.myhome.onu.application.MyApplication
import com.myhome.onu.databinding.ActivitySignInBinding
import com.myhome.onu.main.MainActivity
import com.myhome.onu.model.User
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_sign_in.*
import javax.inject.Inject


class SignInActivity : AppCompatActivity() {

    private lateinit var mOAuthLoginModule:OAuthLogin
    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    lateinit var viewModel:SignInViewModel

    @SuppressLint("LongLogTag")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_sign_in)
        (application as MyApplication).appComponent.inject(this)
        val binding = DataBindingUtil.setContentView<ActivitySignInBinding>(this, R.layout.activity_sign_in)
        viewModel = ViewModelProviders.of(this, viewModelFactory)[SignInViewModel::class.java]
        binding.model = viewModel

        val owner = this as LifecycleOwner
        binding.lifecycleOwner = owner

        viewModel.apply {
            kakaoLoginEvent.observe(owner, Observer {
                val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
                    if (error != null) {
                        Log.e("TAG", "로그인 실패", error)
                    }
                    else if (token != null) {
                        Log.i("TAG", "로그인 성공 ${token.accessToken}")
                        saveKakaoUser(token.accessToken)
                    }
                    Log.d("result==", "11")
                }

                // 카카오톡이 설치되어 있으면 카카오톡으로 로그인, 아니면 카카오계정으로 로그인
                if (UserApiClient.instance.isKakaoTalkLoginAvailable(this@SignInActivity)) {
                    Log.d("isKakaoTalkLoginAvailable", "isKakaoTalkLoginAvailable(true) ")
                    UserApiClient.instance.loginWithKakaoTalk(this@SignInActivity, callback = callback)
                } else {
                    Log.d("isKakaoTalkLoginAvailable", "isKakaoTalkLoginAvailable(false) ")
                    UserApiClient.instance.loginWithKakaoAccount(this@SignInActivity, callback = callback)
                }
            })
        }


    }

    fun saveKakaoUser(token:String){
        val user = User(
            0,
            1,
            token,
            "myNickName",
            ""
        )
        viewModel.apply {
            _dataLoading.postValue(true)
            kakaoCallBack(user)
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    _dataLoading.postValue(false)
                    user.id = it
                    userRepository.setUser(user)
                    val intent = Intent(applicationContext, MainActivity::class.java)
                    startActivity(intent)
                    finish()
                },{
                    it.printStackTrace()
                })
        }
    }
}

저는 MVVM 패턴을 사용하여 ViewModel에서 특정 이벤트를 감지하였습니다(kakaoLoginEvent). 다른 부분을 크게 신경 쓰실 필요가 없고 kakaoLogEvent를 옵저빙 하고 있는 안의 코드를 주시하시면 됩니다. ViewModel 패턴이 생소하시다면 특정 버튼의 클릭이벤트 리스너 안에 해당 코드를 삽입하실 수 있습니다. 우선 로그인 이벤트의 동작에 따른 콜백 이벤트를 등록하고 단말기에 카카오톡의 설치 유무에 따라 카카오톡 실행 / API를 통한 로그인의 동작으로 구분하여 메소드를 실행합니다.(loginWithKakaoTalk / loginWithKakaoAccount)

이후 저는 로그인 성공 시 해당 토큰 ID를 통해 내 애플리케이션의 User ID를 등록할 수 있는 로직을 구현하였습니다. 해당 부분은 애플리케이션의 컨셉에 따라 자유롭게 구현하시면 됩니다 !!

 

추가적으로 카카오 로그인을 예제를 적용하면서 저는 로그인 콜백이 정상적으로 동작하지 않는 문제를 겪었습니다.

이는 Manifest에서 앱 키 등을 정상적으로 등록하였지만 로그인 앱 키를 등록을 위한 인텐트 필터의 작성 위치를 커스텀 로그인 액티비티에 작성하여 발생한 문제였습니다.

<activity android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"> intent-filter~~ (O)

<activity android:name=".main.certification.SignInActivity"> intent-filter~~ (X)

 

이외에도 콜백이 수행되지 않는 원인에는 대부분 Manifest의 앱 키 등록이 적절하게 작성되지 않은 경우가 많으니(앱 키 앞에 kakao를 추가해야 하는 등의 이유), 해당 부분을 면밀히 확인해보시기를 추천드립니다!!

그리고 관련한 문제 발생 시 아래와 같이 카카오 데브톡에 문의하면 친절하게 답변해주시니 참고하시기 바랍니다.

https://devtalk.kakao.com/t/v2-loginwithkakaoaccount/118648

 

카카오 데브톡

카카오 데브톡. 카카오 플랫폼 서비스 관련 질문 및 답변을 올리는 개발자 커뮤니티 사이트입니다.

devtalk.kakao.com

이상으로 부족한 글 읽어주셔서 감사합니다.

도움이 되셨다면 공감 버튼 부탁드립니다 !!