현재 안드로이드 프로젝트를 진행 중에 있기 때문에, 프로젝트를 하면서 도움이 될 수 있는 카카오 소셜 로그인 구현 방법에 대해서 포스팅을 해보겠습니다!
0️⃣ 카카오 로그인 과정과 시퀀스 다이어그램
아래의 사진을 참고해주세요!


1️⃣ 카카오 Developers 세팅
1. https://developers.kakao.com/ 에서 회원가입하고, 로그인을 한다.
2. '내 어플리케이션' 클릭 -> 어플리케이션을 추가한다.
3. 일단 고유한 해시키를 알아야한다.
4. 터미널에 아래 코드 입력하면 해시키를 알 수 있다!
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -storepass android -keypass android | openssl sha1 -binary | openssl base64
5. 그리고 나서 릴리즈키도 구해준다.
6. 터미널에 아래 코드를 입력해서 릴리즈키를 얻을 수 있다.
keytool -exportcert -alias release -keystore /Users/joanna/keystore/release.keystore -storepass yourpassword | openssl sha1 -binary | openssl base64
7. 그럼 카카오 디벨로퍼에서 앱키 목록들을 확인할 수 있는데, 우리가 사용할 것은 네이티브 앱 키 이다.

카카오 Developers 세팅을 끝냈으면 이제 안드로이드 스튜디오 설정을 해야한다!
2️⃣ 안드로이드 스튜디오 설정
공식문서에 아주 자세하게 설명이 나와있으므로 참고하자. (https://developers.kakao.com/docs/latest/ko/android/getting-started) AndroidManifest.xml
1. 일단 AndroidManifest에 인터넷을 사용할 수 있는 권한을 추가해준다.
//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 인터넷 사용 권한 설정-->
<uses-permission android:name="android.permission.INTERNET" />
<application
...
2. 공식 문서에 나와있는 대로 Gradle을 설정한다.
//settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = java.net.URI("https://devrepo.kakao.com/nexus/content/groups/public/") }
}
}
//build.gradle.kts(Module)
dependencies {
implementation "com.kakao.sdk:v2-all:2.20.6" // 전체 모듈 설치, 2.11.0 버전부터 지원
implementation "com.kakao.sdk:v2-user:2.20.6" // 카카오 로그인 API 모듈
implementation "com.kakao.sdk:v2-share:2.20.6" // 카카오톡 공유 API 모듈
implementation "com.kakao.sdk:v2-talk:2.20.6" // 카카오톡 채널, 카카오톡 소셜, 카카오톡 메시지 API 모듈
implementation "com.kakao.sdk:v2-friend:2.20.6" // 피커 API 모듈
implementation "com.kakao.sdk:v2-navi:2.20.6" // 카카오내비 API 모듈
implementation "com.kakao.sdk:v2-cert:2.20.6" // 카카오톡 인증 서비스 API 모듈
...
}
3️⃣ 초기화
1. 카카오 Android SDK를 사용하기 위해서 가장 먼저 우리가 전에 받아놓은 네이티브 앱 키로 초기화를 해줘야한다.
GlobalApplication 코틀린 클래스를 하나 생성하고, 초기화 코드를 넣어준다.
//FlobalApplication.kt
class GlobalApplication : Application() {
override fun onCreate() {
super.onCreate()
// Kakao SDK 초기화
KakaoSdk.init(this, "네이티브 앱 키를 여기에 넣으면 된다")
}
}
2. AndroidManifest.xml의 application에도 Kakao SDK 초기화를 수행한 클래스의 이름을 설정한다. GlobalApplication 클래스에서 초기화를 했으므로 아래와 같이 동일한 이름을 설정에 추가해준다.
//AndroidManifest.xml
<application
<!-- android:name 설정 -->
android:name=".GlobalApplication"
...
>
그럼 초기화 완료!
4️⃣ Redirect URI 설정
- AndroidManifest.xml에 들어가서 android:name=".GlobalApplication" 코드와 meta-data 코드를 추가해준다. (name은 그대로 적으면 되고, value 값은 네이티브 앱 키 값이다.)
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="네이티브 앱 키 적으면 된다"/>
- 카카오 로그인 기능을 구현하기 위해서는 리다이렉션(Redirection)을 통해 인가 코드를 받아야 하기 때문에 코드를 추가해준다. (🚨주의: 네이티브 앱 키 앞에 kakao를 붙여주어야 오류가 안난다.)
<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${NATIVE_APP_KEY}" />
</intent-filter>
</activity>
💡 네이티브 앱 키는 정말 중요하기 때문에 함부로 공개되면 안된다. 꼭 가려주자! 깃허브에 올릴 때에도 .gitignore에 추가해서 숨겨줘야 한다.
최종 AndroidManifest.xml 파일 참고!

5️⃣ AuthCodeHandlerActivity
- 매니페스트에 맞는 액티비티를 생성한다. > AuthCodeHandlerActivity 생성하고 코드 작성 해준다.
//AuthCodeHandlerActivity.kt
class AuthCodeHandlerActivity : AppCompatActivity() {
private val mCallback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
Log.e(TAG, "로그인 실패 $error")
} else if (token != null) {
Log.e(TAG, "로그인 성공 ${token.accessToken}")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 카카오톡 설치 확인
if (UserApiClient.instance.isKakaoTalkLoginAvailable(this)) {
// 카카오톡 로그인
UserApiClient.instance.loginWithKakaoTalk(this) { token, error ->
// 로그인 실패 부분
if (error != null) {
Log.e(TAG, "로그인 실패 $error")
// 사용자가 취소
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
return@loginWithKakaoTalk
}
// 다른 오류
else {
UserApiClient.instance.loginWithKakaoAccount(
this,
callback = mCallback
) // 카카오 이메일 로그인
}
}
// 로그인 성공 부분
else if (token != null) {
Log.e(TAG, "로그인 성공 ${token.accessToken}")
}
}
} else {
UserApiClient.instance.loginWithKakaoAccount(this, callback = mCallback) // 카카오 이메일 로그인
}
}
}
6️⃣이제 로그인을 구현하고자 하는 프래그먼트에 들어가서 코드를 작성해준다.
아래의 코드 참고해주세요! (액티비티에 작성해도 되지만, 지금은 프래그먼트에 작성했다.)
//LoginFragment.kt
class LoginFragment : BaseFragment<FragmentLoginBinding>() {
companion object {
fun newInstance() = LoginFragment()
}
// 카카오 로그인
// 카카오계정으로 로그인 공통 callback 구성
// 카카오톡으로 로그인 할 수 없어 카카오계정으로 로그인할 경우 사용됨
val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
Log.e(TAG, "카카오계정으로 로그인 실패", error)
} else if (token != null) {
Log.i(TAG, "카카오계정으로 로그인 성공 ${token.accessToken}")
GoMain()
}
}
override fun initView() {
val context : Context = requireContext()
// 버튼 클릭했을 때 로그인
with(binding) {
KakaoLoginBtn.setOnClickListener {
// 카카오톡이 설치되어 있으면 카카오톡으로 로그인, 아니면 카카오계정으로 로그인
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
if (error != null) {
Log.e(TAG, "카카오톡으로 로그인 실패", error)
// 사용자가 카카오톡 설치 후 디바이스 권한 요청 화면에서 로그인을 취소한 경우,
// 의도적인 로그인 취소로 보고 카카오계정으로 로그인 시도 없이 로그인 취소로 처리 (예: 뒤로 가기)
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
return@loginWithKakaoTalk
}
// 카카오톡에 연결된 카카오계정이 없는 경우, 카카오계정으로 로그인 시도
UserApiClient.instance.loginWithKakaoAccount(context, callback = callback)
} else if (token != null) {
Log.i(TAG, "카카오톡으로 로그인 성공 ${token.accessToken}")
GoMain()
}
}
} else {
UserApiClient.instance.loginWithKakaoAccount(context, callback = callback)
}
}
}
}
private fun navigateToNotesScreen() {
findNavController().navigate(R.id.action_loginFragment_to_mainFragment)
}
override fun getViewBinding(
inflater: LayoutInflater,
container: ViewGroup?
) = FragmentLoginBinding.inflate(inflater, container, false)
fun GoMain(){
// 로그인 -> 메인
Navigation.findNavController(binding.root).navigate(R.id.action_loginFragment_to_mainFragment)
}
}
```
**BaseFragment.kt**
```kotlin
abstract class BaseFragment<VB : ViewBinding> : // 추상화 클래스
Fragment() {
private var _binding: VB by autoCleaned()
val binding: VB get() = _binding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = getViewBinding(inflater, container)
return binding.root
}
abstract fun initView()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView()
}
protected abstract fun getViewBinding(inflater: LayoutInflater, container: ViewGroup?): VB
}
7️⃣ API Key 숨기기
깃허브에 올리거나 할 때, 중요한 네이티브 앱 키를 숨겨야한다.
외부로부터 노출이 되지 말아야할 키값들은 local.properties에 저장해야하고 깃허브에는 올라가면 안된다.
Project 단위에 존재하는 .gitignore에 다음과 같이 local.properties를 추가해서 깃허브에는 올라가지 않도록 한다.
- local.properties 파일에 카카오에서 제공하는 네이티브 앱 키값을 작성한다.
- Module 단위의 build.gradle 파일에 localProperties를 선언한다.
AndroidManifest 파일에 들어갈 키는 manifestPlaceholders라는 프로퍼티를 통해서 정의하고
Application에서 카카오 SDK를 선언할 때 사용할 키값은 buildConfigField를 통해서 정의한다.
val localProperties = Properties()
localProperties.load(project.rootProject.file("local.properties").inputStream())
val kakaoApiKey = localProperties.getProperty("kakao_NATIVE_APP_KEY") ?: ""
val nativeAppKey = localProperties.getProperty("kakao_NATIVE_APP_KEY_MANIFEST") ?: ""
android {
defaultConfig {
...
// 코드에서 사용 가능하도록 빌드 설정에 추가
buildConfigField("String", "kakao_NATIVE_APP_KEY", "\"$kakaoApiKey\"")
// AndroidManifest.xml에서 사용할 수 있도록 설정
manifestPlaceholders["NATIVE_APP_KEY"] = nativeAppKey
}
}
...
- 처음 코드를 작성할 때, 네이티브 앱키를 작성한 GlobalApplication.kt, AndroidManifest.xml 코드를 수정한다.
실제로 아래와 같이 사용된다.

그럼 끝-!