카카오 Developers 세팅
안드로이드 스튜디오 맨하단 Terminal 클릭 후 아래 코드를 입력하면 된다
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -storepass android -keypass android | openssl sha1 -binary | openssl base64
위 웹사이트 설정 과정은 다른 분들이 자세하게 잘 설명해주셔서 문제가 없었는데,
카카오SDK 가 업데이트된 이후 안드로이드 스튜디오 셋팅글은 잘 안보여서 작성하게 되었다.
다른 글을 참고했을 때는 코드가 진짜 복잡했는데 SDK도 점점 업데이트 되면서 내가 구현해야 할 ? 복붙해야할 ..? ㅎㅎ.. 코드들도 상당히 줄어들었다. 감사합니다!
안드로이드 스튜디오 설정 방법
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' } 코드 추가
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' } // 카카오 로그인
}
}
dependencies 부분에 추가
dependencies {
...
implementation "com.kakao.sdk:v2-user:2.12.1" // 카카오 로그인
}
Application 을 상속한 GlobalApplication 라는 클래스 하나 생성
아래와 같이 생성되는데, 여기에 SDK 초기화 코드를 넣어주어야 한다.
class GlobalApplication : Application() {
}
초기화 코드를 넣어준다.
class GlobalApplication : Application() {
override fun onCreate() {
super.onCreate()
// Kakao Sdk 초기화
KakaoSdk.init(this, "네이티브 앱 키 넣으시면 됩니당")
}
}
AndroidManifest.xml 에 들어가서
android:name = ".GlobalApplication" 코드와
meta-data 코드를 추가해준다.
name 은 그대로 적으면 되고, value 값은 네이티브앱 키 값이다.
예시) 네이티브앱 키 값 : akdfadfladflka
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="akdfadfladflka"/>
그럼 아래와 같이 완성된다.
카카오 로그인을 구현하기 위해서 카카오 인증 서버에서 전달해주는 인가 코드(Authorization Code)를 발급해 서비스 앱에 등록된 Redirect URI을 전달받아야 한다.
자세한 사항은 그림을 읽어보면 이해가 쉽다.
사용자가 카카오 계정 인증을 성공하고, 필수 동의 항목을 선택한 후에 로그인을 요청하면
서비스는 전달받은 인가 코드로 토큰을 요청하여 받는다.
그래서 하고 싶은 말이 무엇이냐, 인가 코드를 받기 위해서 새로운 액티비티를 생성하고, manifest 파일도 수정해주어야 한다.
아래 부분을 참고하면 되고,4,5 를 모두 적용한 매니페스트 이다.
완성된 매니패스트
<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
android:name=".GlobalApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.RecordWOD"
tools:targetApi="31">
<meta-data
android:name="com.kakao.sdk.AppKey"
android:value="@string/kakao_app_key"/>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 카카오 로그인, 인가코드를 받기 위한 액티비티 -->
<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네이티브앱키" />
</intent-filter>
</activity>
</application>
</manifest>
네이티브 앱 키를 asdfasdfadf 라고 가정하겠습니다.
나같은 경우, AuthCodeHandlerActivity 매니페스트 내부를 이렇게 설정하여서 에러가 났다.
<data android:host="oauth"
android:scheme="asdfasdfadf" />
네이티브 앱 키 앞에 kakao 를 붙여주어야 오류가 안난다.
<data android:host="oauth"
android:scheme="kakaoasdfasdfadf" />
그럼 매니페스트에 액티비티라고 적어줬으므로, 그에 맞는 액티비티를 생성한다.
AuthCodeHandlerActivity 액티비티 생성
코드
import android.content.ContentValues.TAG
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
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
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) // 카카오 이메일 로그인
}
}
}
그럼 초기 셋팅 끝 !
나는 프래그먼트에 구현하였다!
먼저 callback 선언
// 카카오 로그인
// 카카오계정으로 로그인 공통 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()
}
}
GoMain() 은 로그인이 성공했을 때 어느 액티비티로 갈 지 적어준 메소드이다.
액티비티라면 Intent 코드,
프래그먼트라면 아래와 비슷한 코드를 적어주면 된당.
Navigation.findNavController(binding.root).navigate(R.id.action_loginFragment_to_mainFragment)
그리고 KakaoLoginBtn 이라는 버튼을 눌렀을 때, 실행되게 했다.
나는 BaseFragment 를 상속받아 중복되는 코드를 생략하였는데 그 과정에서 binding 코드도 생략되어서 아래에 같이 넣어두겠다.
여기서 액티비티라면 context 등의 코드들이 약간씩 수정될 것이당.
loginFragment 코드
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 코드
// 추상화 클래스
// 클래스의 틀을 복제
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
}
실행하면 로그인이 잘 되는 화면을 볼 수 있다.
끝! 수고하셨습니다.
사실
https://developers.kakao.com/docs/latest/ko/kakaologin/common#intro-kakaologin
여기 정리가 너무 잘 되어있어서 내 포스팅이 허접해지는 순간이지만
은근 또 삽질은 했기에 어떻게 구현했는 지 정리해봤다 ㅎㅎ
나와 비슷한 삽질을 하고 계신분들께 도움이 되었으면 하는 마음을 담아 .. ~~