카카오 로그인 연동하기 with Kotlin
안녕하세요. 휴몬랩에서 개발하고 있는 오지(OG)입니다.
오늘은 제가 안드로이드 앱을 개발하면서 개발 가이드에서도 설명이나 코드가 부족해 힘들었던ㅠㅠ 부분을 공유해보려 합니다.
TL;DR?
- 안드로이드 앱에 카카오 로그인을 연결할 때는 네이티브로 개발하는 것을 권장합니다. 네이티브로 개발한다는 것은 앱 자체에서 로그인 요청을 실행한 뒤 사용자 정보를 받아온다는 말인데요. 일단 앱에서 연결을 완료한 뒤에 이를 API와 연결하든, 앱 자체에서 그냥 활용하든 알아서 하면 됩니다!
- 카카오 로그인 관련해선 엄청나게 많은 블로그 글을 쉽게 찾아볼 수 있지만 최신 버전(?)의 코드 그리고 코틀린(kotlin) 코드가 없어서 고생을 좀 했습니다..
- 공식 카카오 개발 가이드도 있지만
사실 완전히 친절하진 않습니다. 알고 보면 쉽고 모르고 보면 어렵더라구요. 그래도 공식이니 읽어보길 권장합니다. 카카오 개발 가이드에도 코틀린 코드는 없습니다 ㅠㅠ
카카오 개발 가이드 중 카카오 계정 로그인을 사용합니다.
시작
안드로이드 앱에 카카오 로그인 기능을 추가해야 했습니다. API 서버(node.js)가 따로 있어서 그 쪽에서 처리해야 하나 고민을 했는데, 카카오 개발팀에서는 안드로이드 네이티브에서 구현하는 것을 권장하는 글을 읽고 '네 따르겠습니다.' 했습니다.
그래서 안드로이드 네이티브에서 구현해 프로필까지 받아오고, 성공 또는 실패 시 콜백 처리까지 하는 방법을 테스트해보았습니다. 앞서 적은 것처럼 코틀린 코드가 아직 없고 공식 가이드에도 deprecated 된 코드로 적혀 있는 등 어려움이 있었습니다.
준비하기
1. gradle(project 단위)에 kakao repository를 추가합니다.
allprojects {
...
}
subprojects {
repositories {
mavenCentral()
maven { url 'http://devrepo.kakao.com:8088/nexus/content/groups/public/'
}
}
}
2. gradle(app 단위)에 dependencies를 추가한다.
- 로그인 sdk만 추가하였습니다.
dependencies {
// 카카오 로그인 sdk를 사용하기 위해 필요.
implementation group: 'com.kakao.sdk', name: 'usermgmt', version: project.KAKAO_SDK_VERSION
}
3. gradle(project 단위)에 KAKAO_SDK_VERSION을 최신버전으로 추가한다.
- 최신버전 확인하기 - Android SDK / Full SDK Source 기준
ext.kotlin_version='xxx'
ext.KAKAO_SDK_VERESION='1.23.0'
4. Kakao Developer에 가입 또는 로그인한다.
5. 앱을 생성합니다. 아이콘, 앱 이름, 회사명은 나중에 수정할 수 있습니다.
6. 앱 키 중에서 네이티브 앱 키를 복사해둡니다.
7. 안드로이드 res > values 폴더 안에 kakao_string.xml 파일을 만들고 아래와 같이 앱 키를 저장합니다.
<resources>
<string name="kakao_app_key">AAAAAAAAAAAAAAAAAAAAAA</string>
</resources>
8. AndroidManifest.xml 코드에 인터넷 사용 permission을 위한 코드와, 카카오 앱 키 등록을 위한 코드를 작성합니다.
<activity ... >
<!-- 인터넷 사용 permission -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 카카오 앱 키 사용 -->
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="@string/kakao_app_key" />
<!-- 카카오 로그인 시 웹 뷰를 띄우기 위한 코드 -->
<activity
android:name="com.kakao.auth.authorization.authcode.KakaoWebViewActivity"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
9. 키 해시를 구합니다.
키 해시는 1) cmd 혹은 2) 코드를 활용하여 구할 수 있습니다. 릴리즈 때는 또 바꾸어주어야 합니다.
저는 로그인 용 activity 안에서 키 해시를 구해 출력하도록 하엿씁니다.
-
카카오 개발가이드를 보면 PackageManager.GET_SIGNATURES와 packageInfo!!.signatures라는 코드가 있는데 막상 적어보니 deprecated 됐다고 하더라구요. 그래서 stackoverflow의 도움을 받아 GET_SIGNING_CERTIFICATES(API 28 이상)을 이용하였습니다.
fun getHashKey(context: Context): String? {
try {
if (Build.VERSION.SDK_INT >= 28) {
val packageInfo = getPackageInfo(context, PackageManager.GET_SIGNING_CERTIFICATES)
val signatures = packageInfo.signingInfo.apkContentsSigners
val md = MessageDigest.getInstance("SHA")
for (signature in signatures) {
md.update(signature.toByteArray())
return String(Base64.encode(md.digest(), NO_WRAP))
}
} else {
val packageInfo =
getPackageInfo(context, PackageManager.GET_SIGNATURES) ?: return null
for (signature in packageInfo!!.signatures) {
try {
val md = MessageDigest.getInstance("SHA")
md.update(signature.toByteArray())
return Base64.encodeToString(md.digest(), Base64.NO_WRAP)
} catch (e: NoSuchAlgorithmException) {
// ERROR LOG
}
}
}
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
return null
}
Global Application, Kakao SDK Adapter
1. 안드로이드 앱 전역에서 공유할 수 있는 Global Application을 만듭니다.
만약 기존에 Application을 상속한 클래스가 있다면 거기에 추가해야 합니다.
class GlobalApplication : Application() {
override fun onCreate() {
super.onCreate()
instance = this
KakaoSDK.init(KakaoSDKAdapter())
}
override fun onTerminate() {
super.onTerminate()
instance = null
}
fun getGlobalApplicationContext(): GlobalApplication {
checkNotNull(instance) { "this application does not inherit com.kakao.GlobalApplication" }
return instance!!
}
companion object {
var instance: GlobalApplication? = null
}
}
2. 카카오 로그인 sdk에서 제공하는 KakaoAdapter를 상속하는 KakaoSDKAdapter를 만듭니다.
블로그로 찾아보면 isSecureMode가 빠져있는 경우가 많아 그대로 가져왔을 때 오류가 나더라구요. 공식 개발 가이드를 찾아보면 override 해야 하는 함수와 그에 대한 설명이 잘 나와있습니다.
class KakaoSDKAdapter : KakaoAdapter() {
override fun getSessionConfig(): ISessionConfig {
return object : ISessionConfig {
override fun getAuthTypes(): Array<AuthType> {
return arrayOf(AuthType.KAKAO_ACCOUNT)
}
override fun isUsingWebviewTimer(): Boolean {
return false
}
override fun getApprovalType(): ApprovalType? {
return ApprovalType.INDIVIDUAL
}
override fun isSaveFormData(): Boolean {
return true
}
override fun isSecureMode(): Boolean {
return true
}
}
}
override fun getApplicationConfig(): IApplicationConfig {
return IApplicationConfig {
GlobalApplication.instance?.getGlobalApplicationContext()
}
}
}
3. Manifest.xml에 Global Application을 추가합니다.
<application
android:name=".GlobalApplication"
...
>
...
로그인 버튼에 카카오 로그인 연동
1. 버튼을 추가합니다. 버튼은 카카오에서 제공하는 버튼(카카오 로고와 카카오 계정으로 로그인 문구가 있는 것)을 이용하거나 직접 커스텀해서 만들 수도 있습니다.
1) 카카오에서 제공하는 버튼 추가하기
xml 코드와 콜백만 추가하면 됩니다. 자동으로 카카오 로그인 페이지로 연결되도록 이미 설정되어 있습니다.
2) 커스텀 버튼 추가하기
버튼에 직접 카카오 로그인 세션을 여는 코드를 추가해야 합니다.
button.onClick { // anko 사용
session.addCallback(callback);
session.open(AuthType.KAKAO_LOGIN_ALL, this);
}
2. 콜백 처리를 추가합니다. 콜백에서 유저 프로필을 받아올 수 있습니다.
만약 API로 유저 프로필 정보를 보내야 한다면 onSuccess에서 받아오는 정보를 그대로 보내면 됩니다.
class LoginActivity: AppCompatActivity() {
private var callback: SessionCallback = SessionCallback()
override fun onCreate(savedInstanceState: Bundle?){
...
// Get hash key and print
...
// 카카오 제공 버튼일 경우
Session.getCurrentSession.addCallback(callback);
}
override fun onDestroy() {
...
Session.getCurrentSession().removeCallback(callback);
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (Session.getCurrentSession().handleActivityResult(requestCode, resultCode, data)) {
Dlog.d("session get current session")
return
}
super.onActivityResult(requestCode, resultCode, data)
}
private class SessionCallback : ISessionCallback {
override fun onSessionOpenFailed(exception: KakaoException?) {
Dlog.e("Session Call back :: onSessionOpenFailed: ${exception?.message}")
}
override fun onSessionOpened() {
UserManagement.getInstance().me(object : MeV2ResponseCallback() {
override fun onFailure(errorResult: ErrorResult?) {
Dlog.d("Session Call back :: on failed ${errorResult?.errorMessage}")
}
override fun onSessionClosed(errorResult: ErrorResult?) {
Dlog.e("Session Call back :: onSessionClosed ${errorResult?.errorMessage}")
}
override fun onSuccess(result: MeV2Response?) {
checkNotNull(result) { "session response null" }
// register or login
}
})
}
}
코틀린(kotlin)으로 카카오 로그인을 연동하려는 분들께 조금이나마 도움이 되었으면 좋겠습니다.^^
[references]
- 카카오 공식 개발 블로그