페이지 이동경로
  • 문서>
  • 카카오 로그인>
  • Android

카카오 로그인

Android

이 문서는 Kakao SDK for Android(이하 Android SDK)를 사용한 카카오 로그인 구현 방법을 안내합니다.

카카오 로그인 구현에 필요한 로그인 버튼 이미지는 [도구] > [리소스 다운로드]에서 제공합니다. 해당 로그인 버튼은 디자인 가이드를 참고하여 서비스 UI에 적합한 크기로 수정하여 사용할 수 있습니다.

시작하기 전에

구현 방식 선택

사용자의 카카오계정을 인증하는 방식에 따라, Android SDK를 사용한 카카오 로그인 구현 방법은 두 가지로 나뉩니다.

구현 방법 메서드 설명
카카오톡으로 로그인(권장) loginWithKakaoTalk() 카카오톡에 연결된 카카오계정 및 인증 정보를 사용
사용자가 카카오계정 정보를 직접 입력하지 않아도 간편하게 로그인 가능
카카오계정으로 로그인 loginWithKakaoAccount() 기본 웹 브라우저(Default Browser)를 통해 카카오계정 정보를 입력하고 로그인
사용자가 카카오계정 정보를 직접 입력하는 단계를 거침
사용자가 여러 개의 카카오계정을 사용하는 서비스, 카카오톡 미설치 또는 미지원 디바이스에서 사용

각 인증 방법의 특징과 서비스의 사용자 로그인 동선을 고려하여 어느 인증 방법이 적합한지 판단합니다. 두 가지 인증 방법을 함께 사용할 수도 있습니다. 인증 방법에 따라 필요한 설정이나 예외 처리에 차이가 있으므로, 인증 방법별 개발 가이드를 참고합니다.

모듈 설정

카카오 로그인 API를 사용하려면 모듈 설정을 참고하여 build.gradle(Module) 파일에 카카오 로그인 모듈인 v2-user를 추가합니다.

주의: 카카오 로그인 모듈 개선에 따른 변경사항

기존에는 카카오 로그인 API를 v2-auth 모듈의 AuthApiClient와 v2-user 모듈의 UserApiClient를 통해 호출해야 했으나, Android SDK 2.4.0 버전부터는 UserApiClient 하나로 호출할 수 있도록 개선하였습니다. 단, 사용자 인증 관련 API인 토큰 존재 여부 확인하기 API는 AuthApiClient를 통해 호출합니다. 문서의 예제 또한 최신 버전에 맞게 업데이트되었습니다.

Redirect URI 설정

카카오 로그인 기능을 구현하기 위해서는 리다이렉션(Redirection)을 통해 인가 코드를 받아야 합니다. 이를 위해 AndroidManifest.xml에 액티비티(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" />
        
        <!-- Redirect URI: "kakao${NATIVE_APP_KEY}://oauth" -->
        <data android:host="oauth"
                android:scheme="kakao${NATIVE_APP_KEY}" />
    </intent-filter>
</activity>

새로운 액티비티를 추가하고, name 요소의 값은 "com.kakao.sdk.auth.AuthCodeHandlerActivity"로 입력합니다. Android 12(API 31) 이상을 타깃으로 하는 앱인 경우, exported 요소를 반드시 "true"로 선언해야 합니다.

해당 액티비티 하위에 <intent-filter> 요소를 추가하고, hostscheme 요소 값으로 카카오 로그인을 위한 Redirect URI를 설정합니다. scheme 속성의 값은 "kakao${NATIVE_APP_KEY}" 형식으로 입력합니다. 예를 들어 네이티브 앱 키가 "123456789"라면 "kakao123456789"를 입력합니다.

카카오 인증 서버가 지정된 Redirect URI로 인가 코드를 보내면, Android SDK가 인가 코드를 받아 토큰 받기를 요청합니다. 자세한 과정은 이해하기를 참고합니다.

카카오 로그인

카카오톡으로 로그인

기본 정보
사전 설정 사용자 동의 레퍼런스
플랫폼 등록
카카오 로그인 활성화
동의 항목
OpenID Connect 활성화(선택)
필요:
필수 동의 항목
공통
isKakaoTalkLoginAvailable()
Android SDK
loginWithKakaoTalk()
ReactiveX Android SDK
loginWithKakaoTalk()

사전 설정 후, UserApiClientloginWithKakaoTalk()을 호출합니다. 먼저 isKakaoTalkLoginAvailable()로 카카오톡 실행 가능 여부를 확인할 것을 권장합니다.

loginWithKakaoTalk()이 호출되면 Android SDK가 카카오톡을 실행하고 사용자에게 앱 이용 관련 동의를 구하는 동의 화면을 출력합니다. 호출 시 context와 결과 처리를 위한 콜백(Callback) 함수를 전달해야 합니다.

콜백 함수에는 다음 예제와 같이 로그인 결과에 따라 필요한 동작과 예외 처리를 정의해 두어야 합니다. 발생 가능한 에러의 종류는 문제 해결에서 확인할 수 있습니다. 카카오 로그인 구현 예제를 함께 참고합니다.

Kotlin
RxKotlin
// 카카오톡으로 로그인
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
    if (error != null) {
        Log.e(TAG, "로그인 실패", error)
    }
    else if (token != null) {
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }
}
var disposables = CompositeDisposable()

// 카카오톡으로 로그인
UserApiClient.rx.loginWithKakaoTalk(context)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ token ->
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }, { error ->
        Log.e(TAG, "로그인 실패", error)
    })
    .addTo(disposables)

loginWithKakaoTalk() API가 성공적으로 동작하면 Android SDK는 기기의 카카오톡 앱을 실행해 사용자를 인증합니다. 사용자 인증에 성공하면 사용자에게 앱 이용 관련 동의를 요청하는 동의 화면을 출력합니다.

동의 화면에서 사용자는 필수 항목에 모두 동의해야 로그인할 수 있으며, 동의하지 않고 로그인을 취소할 수도 있습니다. 예외 처리를 위해 사용자의 로그인 취소 등 주요 에러 ClientErrorCauseAuthErrorCause에 정의되어 있습니다.

동의 화면에서 사용자가 모든 필수 항목에 동의하고 [동의하고 계속하기]를 선택하면, Android SDK는 카카오톡에서 서비스 앱으로 돌아와 인가 코드 및 토큰 발급을 처리하고 카카오 로그인을 완료합니다. OpenID Connect를 사용하는 앱인 경우, ID 토큰을 함께 발급받습니다.

카카오계정으로 로그인

기본 정보
사전 설정 사용자 동의 레퍼런스
플랫폼 등록
카카오 로그인 활성화
동의 항목
OpenID Connect 활성화(선택)
필요:
필수 동의 항목
Android SDK
loginWithKakaoAccount()
ReactiveX Android SDK
loginWithKakaoAccount()

사전 설정 후, UserApiClientloginWithKakaoAccount()를 호출합니다. loginWithKakaoAccount() 호출 시 Android SDK가 웹 브라우저를 실행하고 카카오 로그인 화면을 띄웁니다. 카카오톡으로 로그인 API인 loginWithKakaoTalk()과 마찬가지로 context와 콜백 함수를 호출 시 전달하여야 합니다.

카카오계정으로 로그인 요청 시, Android SDK는 OS 기본 웹 브라우저를 통해 사용자로부터 카카오계정 정보를 받아 인증을 완료한 뒤, 사용자에게 앱 이용 관련 동의를 요청하는 동의 화면을 출력합니다.

동의 화면에서 사용자가 모든 필수 항목에 동의하고 [동의하고 계속하기]를 선택하면 Android SDK는 인가 코드 및 토큰 발급을 처리하고 카카오 로그인을 완료합니다.

OpenID Connect를 사용하는 앱인 경우, ID 토큰을 함께 발급받습니다.

카카오계정 로그인 시 발생 가능한 에러의 종류는 문제 해결에서 확인할 수 있습니다. 카카오 로그인 구현 예제를 함께 참고합니다.

Kotlin
RxKotlin
// 카카오계정으로 로그인
UserApiClient.instance.loginWithKakaoAccount(context) { token, error ->
    if (error != null) {
        Log.e(TAG, "로그인 실패", error)
    }
    else if (token != null) {
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }
}
var disposables = CompositeDisposable()

// 카카오계정으로 로그인
UserApiClient.rx.loginWithKakaoAccount(context)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ token ->
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }, { error ->
        Log.e(TAG, "로그인 실패", error)
    })
    .addTo(disposables)

카카오 로그인 구현 예제

카카오 로그인 시 필요한 기본적인 예외 처리를 포함한 구현 예제입니다. 아래 구현 예제는 Android 기기에서 카카오톡으로 로그인 시 발생할 수 있는 예외 상황에 대한 예외 처리를 포함합니다. 주요 에러에 대한 정보는 레퍼런스문제 해결을 함께 참고합니다.

Kotlin
RxKotlin
// 로그인 조합 예제

// 카카오계정으로 로그인 공통 callback 구성
// 카카오톡으로 로그인 할 수 없어 카카오계정으로 로그인할 경우 사용됨
val callback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
    if (error != null) {
        Log.e(TAG, "카카오계정으로 로그인 실패", error)
    } else if (token != null) {
        Log.i(TAG, "카카오계정으로 로그인 성공 ${token.accessToken}")
    }
}

// 카카오톡이 설치되어 있으면 카카오톡으로 로그인, 아니면 카카오계정으로 로그인
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}")
        }
    }
} else {
    UserApiClient.instance.loginWithKakaoAccount(context, callback = callback)
}
// 로그인 조합 예제

// 카카오톡이 설치되어 있으면 카카오톡으로 로그인, 아니면 카카오계정으로 로그인
if (UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
    UserApiClient.rx.loginWithKakaoTalk(context)
        .observeOn(AndroidSchedulers.mainThread())
        .onErrorResumeNext { error ->
            // 사용자가 카카오톡 설치 후 디바이스 권한 요청 화면에서 로그인을 취소한 경우,
            // 의도적인 로그인 취소로 보고 카카오계정으로 로그인 시도 없이 로그인 취소로 처리 (예: 뒤로 가기)
            if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
                Single.error(error)
            } else {
                // 카카오톡에 연결된 카카오계정이 없는 경우, 카카오계정으로 로그인 시도
                UserApiClient.rx.loginWithKakaoAccount(context)
            }
        }.observeOn(AndroidSchedulers.mainThread())
        .subscribe({ token ->
            Log.i(TAG, "로그인 성공 ${token.accessToken}")
        }, { error ->
            Log.e(TAG, "로그인 실패", error)
        }).addTo(disposables)
} else {
    UserApiClient.rx.loginWithKakaoAccount(context)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe({ token ->
            Log.i(TAG, "로그인 성공 ${token.accessToken}")
        }, { error ->
            Log.e(TAG, "로그인 실패", error)
        }).addTo(disposables)
}
참고: 카카오톡으로 로그인 시 발생 가능한 예외 상황

Android의 경우, 사용자 디바이스의 카카오톡 상태에 따라 카카오톡으로 로그인 시 에러가 발생할 수 있습니다. 아래 이미지의 주요 에러 발생 케이스를 참고합니다.

Android 카카오톡으로 로그인 시 발생 가능한 예외 상황

추가 기능

카카오 로그인 요청 시 사용할 수 있는 추가 기능은 다음과 같습니다.

추가 항목 동의 받기

추가 항목 동의 받기는 사용자가 동의하지 않은 동의 항목에 대한 추가 동의를 요청할 때 사용하는 추가 기능입니다. UserApiClientloginWithNewScopes()를 호출합니다. scope 파라미터로 추가 동의받을 항목의 ID 목록을 문자열 리스트(List of Strings)로 전달합니다. 아래는 사용자가 서비스 이용 시 필요한 특정 사용자 정보 제공에 동의하지 않은 상태라면 loginWithNewScopes() 메서드로 추가 항목 동의 받기를 요청하는 예제입니다.

Kotlin
RxKotlin
// 사용자 정보 요청 (추가 동의)

// 사용자가 로그인 시 제3자 정보제공에 동의하지 않은 개인정보 항목 중 어떤 정보가 반드시 필요한 시나리오에 진입한다면
// 다음과 같이 추가 동의를 받고 해당 정보를 획득할 수 있습니다.

//  * 주의: 선택 동의항목은 사용자가 거부하더라도 서비스 이용에 지장이 없어야 합니다.

// 사용 가능한 모든 동의 항목을 대상으로 추가 동의 필요 여부 확인 및 추가 동의를 요청하는 예제입니다.
UserApiClient.instance.me { user, error ->
    if (error != null) {
        Log.e(TAG, "사용자 정보 요청 실패", error)
    }
    else if (user != null) {
        var scopes = mutableListOf<String>()

        if (user.kakaoAccount?.emailNeedsAgreement == true) { scopes.add("account_email") }
        if (user.kakaoAccount?.birthdayNeedsAgreement == true) { scopes.add("birthday") }
        if (user.kakaoAccount?.birthyearNeedsAgreement == true) { scopes.add("birthyear") }
        if (user.kakaoAccount?.genderNeedsAgreement == true) { scopes.add("gender") }
        if (user.kakaoAccount?.phoneNumberNeedsAgreement == true) { scopes.add("phone_number") }
        if (user.kakaoAccount?.profileNeedsAgreement == true) { scopes.add("profile") }
        if (user.kakaoAccount?.ageRangeNeedsAgreement == true) { scopes.add("age_range") }
        if (user.kakaoAccount?.ciNeedsAgreement == true) { scopes.add("account_ci") }

        if (scopes.count() > 0) {
            Log.d(TAG, "사용자에게 추가 동의를 받아야 합니다.")

            // OpenID Connect 사용 시
            // scope 목록에 "openid" 문자열을 추가하고 요청해야 함
            // 해당 문자열을 포함하지 않은 경우, ID 토큰이 재발급되지 않음
            // scopes.add("openid")

            //scope 목록을 전달하여 카카오 로그인 요청
            UserApiClient.instance.loginWithNewScopes(context, scopes) { token, error ->
                if (error != null) {
                    Log.e(TAG, "사용자 추가 동의 실패", error)
                } else {
                    Log.d(TAG, "allowed scopes: ${token!!.scopes}")

                    // 사용자 정보 재요청
                    UserApiClient.instance.me { user, error ->
                        if (error != null) {
                            Log.e(TAG, "사용자 정보 요청 실패", error)
                        }
                        else if (user != null) {
                            Log.i(TAG, "사용자 정보 요청 성공")
                        }
                    }
                }
            }
        }
    }
}
var disposables = CompositeDisposable()

// 사용자 정보 요청 (추가 동의)

// 사용자가 로그인 시 제3자 정보제공에 동의하지 않은 개인정보 항목 중 어떤 정보가 반드시 필요한 시나리오에 진입한다면
// 다음과 같이 추가 동의를 받고 해당 정보를 획득할 수 있습니다.

//  * 주의: 선택 동의항목은 사용자가 거부하더라도 서비스 이용에 지장이 없어야 합니다.

// 사용 가능한 모든 동의 항목을 대상으로 추가 동의 필요 여부 확인 및 추가 동의를 요청하는 예제입니다.
UserApiClient.rx.me()
    .flatMap { user ->

        var scopes = mutableListOf<String>()

        if (user.kakaoAccount?.emailNeedsAgreement == true) { scopes.add("account_email") }
        if (user.kakaoAccount?.birthdayNeedsAgreement == true) { scopes.add("birthday") }
        if (user.kakaoAccount?.birthyearNeedsAgreement == true) { scopes.add("birthyear") }
        if (user.kakaoAccount?.genderNeedsAgreement == true) { scopes.add("gender") }
        if (user.kakaoAccount?.phoneNumberNeedsAgreement == true) { scopes.add("phone_number") }
        if (user.kakaoAccount?.profileNeedsAgreement == true) { scopes.add("profile") }
        if (user.kakaoAccount?.ageRangeNeedsAgreement == true) { scopes.add("age_range") }
        if (user.kakaoAccount?.ciNeedsAgreement == true) { scopes.add("account_ci") }

        if (scopes.count() > 0) {
            Log.d(TAG, "사용자에게 추가 동의를 받아야 합니다.")

            // OpenID Connect 사용 시
            // scope 목록에 "openid" 문자열을 추가하고 요청해야 함
            // 해당 문자열을 포함하지 않은 경우, ID 토큰이 재발급되지 않음
            // scopes.add("openid")

            // scope 목록을 전달하여 InsufficientScope 에러 생성
            Single.error(ApiError.fromScopes(scopes))
        }
        else {
            Single.just(user)
        }
    }
    .retryWhen(
        // InsufficientScope 에러에 대해 추가 동의 후 재요청
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ user ->
        Log.i(TAG, "사용자 정보 요청 성공")
    }, { error ->
        Log.e(TAG, "사용자 정보 요청 실패", error)
    })
    .addTo(disposables)
주의: OpenID Connect

OpenID Connect를 사용하는 앱의 경우, 추가 항목 동의 받기 요청 시 동의 항목 키를 전달하는 scope 파라미터 값에 openid를 반드시 포함해야 합니다. 해당 파라미터 값을 포함하지 않을 경우, ID 토큰이 재발급되지 않습니다. (참고: scope 파라미터)


약관 선택해 동의 받기
카카오싱크 전용

카카오싱크를 도입한 서비스만 사용할 수 있는 기능입니다.

약관 선택해 동의 받기는 카카오 로그인 동의 화면에 포함할 서비스 약관을 지정하는 추가 기능입니다. 사용자의 서비스 가입 시나리오에 따라 앱에 등록된 서비스 약관 중 특정 서비스 약관을 지정해 동의받고자 할 때 사용합니다. 카카오 로그인 요청 시 serviceTerms 파라미터로 동의 화면에 포함할 서비스 약관 태그 목록을 지정합니다.

Kotlin
RxKotlin
// 약관 선택해 동의 받기

// 개발자사이트 간편가입 설정에 등록한 약관 목록 중, 동의 받기를 원하는 약관의 태그 값을 지정합니다.
val serviceTerms = listOf("service")

// serviceTerms 파라미터와 함께 카카오톡으로 로그인 요청 (카카오계정으로 로그인도 사용법 동일)
UserApiClient.instance.loginWithKakaoTalk(
    context = context,
    serviceTerms = serviceTerms
) { token, error ->
    if (error != null) {
        Log.e(TAG, "로그인 실패", error)
    }
    else if (token != null) {
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }
}
var disposables = CompositeDisposable()

// 약관 선택해 동의 받기

// 개발자사이트 간편가입 설정에 등록한 약관 목록 중, 동의 받기를 원하는 약관의 태그 값을 지정합니다.
val serviceTerms = listOf("service")

// serviceTerms 파라미터와 함께 카카오톡으로 로그인 요청 (카카오계정으로 로그인도 사용법 동일)
UserApiClient.rx.loginWithKakaoTalk(
    context = context,
    serviceTerms = serviceTerms
)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ token ->
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }, { error ->
        Log.e(TAG, "로그인 실패", error)
    })
    .addTo(disposables)
OpenID Connect ID 토큰 발급하기

OpenID Connect 사용 서비스인 경우, OpenID Connect 활성화 설정이 되어 있다면 별도 파라미터 없이도 ID 토큰을 함께 발급받을 수 있습니다. OpenID Connect 사용 시 ID 토큰 재생 공격을 방지하기 위해 nonce 파라미터 사용을 권장합니다. 단, 추가 항목 동의 받기 요청 시에는 scope 파라미터에 openid를 포함해야 ID 토큰 재발급이 가능합니다. (참고: scope 파라미터)

기존 로그인 여부와 상관없이 로그인하기

기존 로그인 여부와 상관없이 로그인하기는 서비스의 필요에 따라 사용자 인증을 다시 수행하고자 할 때 사용하는 추가 기능입니다. 이 기능을 사용하면 사용자가 브라우저에 카카오계정으로 로그인되어 있는 상태라도 다시 카카오계정으로 로그인하는 과정을 거쳐 서비스에 카카오 로그인하도록 할 수 있습니다. 카카오 로그인 요청 시 prompts 파라미터 값을 Prompt.LOGIN으로 지정하여 전달합니다.

Kotlin
RxKotlin
UserApiClient.instance.loginWithKakaoAccount(context, prompts = listOf(Prompt.LOGIN)) { token, error ->
    if (error != null) {
        Log.e(TAG, "로그인 실패", error)
    }
    else if (token != null) {
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }
}
var disposables = CompositeDisposable()

UserApiClient.rx.loginWithKakaoAccount(context, prompts = listOf(Prompt.LOGIN))
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ token ->
        Log.i(TAG, "로그인 성공 ${token.accessToken}")
    }, { error ->
        Log.e(TAG, "로그인 실패", error)
    })
    .addTo(disposables)

토큰 존재 여부 확인하기

기본 정보

사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
필요 공통
hasToken()

앱 실행 시 사용자가 앞서 로그인을 통해 발급 받은 토큰이 있는지 확인하려면 AuthApiClienthasToken()을 호출합니다. 호출 결과는 기존에 발급 받은 액세스 토큰 또는 리프레시 토큰의 존재 여부를 Boolean 값으로 알려줍니다. 단, hasToken()의 결과가 true라도 현재 사용자가 로그인 상태임을 보장하지 않습니다.

Kotlin
RxKotlin
if (AuthApiClient.instance.hasToken()) {
    UserApiClient.instance.accessTokenInfo { _, error ->
        if (error != null) {
            if (error is KakaoSdkError && error.isInvalidTokenError() == true) {
                //로그인 필요
            }
            else {
                //기타 에러
            }
        }
        else {
            //토큰 유효성 체크 성공(필요 시 토큰 갱신됨)
        }
    }
}
else {
    //로그인 필요
}
var disposables = CompositeDisposable()

if (AuthApiClient.instance.hasToken()) {
    UserApiClient.rx.accessTokenInfo()
            .subscribe({ tokenInfo ->
                //토큰 유효성 체크 성공(필요 시 토큰 갱신됨)

            }, { error ->
                if (error != null) {
                    if (error is KakaoSdkError && error.isInvalidTokenError() == true) {
                        //로그인 필요
                    }
                    else {
                        //기타 에러
                    }
                }
                else {
                    //토큰 유효성 체크 성공(필요 시 토큰 갱신됨)
                }

            })
            .addTo(disposables)
}
else {
    //로그인 필요
}

hasToken() API의 결과가 false라면 토큰이 없는 상태이므로 사용자가 로그인할 수 있도록 처리합니다. 반면 결과가 true라면 UserApiClientaccessTokenInfo() API를 통해 액세스 토큰의 유효성을 확인할 수 있으며, 요청 결과에 따라 다음과 같이 처리합니다.

  • 요청 성공, 액세스 토큰 정보 반환
    • 액세스 토큰이 유효한 상태이므로 사용자 로그인 불필요
    • 해당 액세스 토큰으로 카카오 API 호출 가능
  • 에러 발생
    • 액세스 토큰 및 리프레시 토큰이 유효하지 않아 사용자 로그인 필요
    • 각 에러에 맞는 처리 필요, 레퍼런스 참고

토큰 정보 보기

기본 정보

사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
필요 공통
AccessTokenInfo
Android SDK
accessTokenInfo()
ReactiveX Android SDK
accessTokenInfo()

UserApiClientaccessTokenInfo()로 토큰 정보를 조회할 수 있습니다. 다음은 현재 캐시에 저장하여 사용 중인 토큰 정보를 출력하는 예제입니다.

Kotlin
RxKotlin
// 토큰 정보 보기
UserApiClient.instance.accessTokenInfo { tokenInfo, error ->
    if (error != null) {
        Log.e(TAG, "토큰 정보 보기 실패", error)
    }
    else if (tokenInfo != null) {
        Log.i(TAG, "토큰 정보 보기 성공" +
                "\n회원번호: ${tokenInfo.id}" +
                "\n만료시간: ${tokenInfo.expiresIn} 초")
    }
}
var disposables = CompositeDisposable()

// 토큰 정보 보기
UserApiClient.rx.accessTokenInfo()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ tokenInfo ->
        Log.i(TAG, "토큰 정보 보기 성공" +
                "\n회원번호: ${tokenInfo.id}" +
                "\n만료시간: ${tokenInfo.expiresIn} 초")
    }, { error ->
        Log.e(TAG, "토큰 정보 보기 실패", error)
    })
    .addTo(disposables)

로그아웃

기본 정보

사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
필요 Android SDK
logout()
ReactiveX Android SDK
logout()

사용자 액세스 토큰과 리프레시 토큰을 모두 만료시켜, 더 이상 해당 사용자 정보로 카카오 API를 호출할 수 없도록 합니다. UserApiClientlogout()을 호출해 로그아웃을 요청할 수 있습니다.

로그아웃은 요청 성공 여부와 관계없이 토큰을 삭제 처리한다는 점에 유의합니다.

다음은 로그아웃 요청 예제입니다.

Kotlin
RxKotlin
// 로그아웃
UserApiClient.instance.logout { error ->
    if (error != null) {
        Log.e(TAG, "로그아웃 실패. SDK에서 토큰 삭제됨", error)
    }
    else {
        Log.i(TAG, "로그아웃 성공. SDK에서 토큰 삭제됨")
    }
}
var disposables = CompositeDisposable()

// 로그아웃
UserApiClient.rx.logout()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({
        Log.i(TAG, "로그아웃 성공. SDK에서 토큰 삭제 됨")
    }, { error ->
        Log.e(TAG, "로그아웃 실패. SDK에서 토큰 삭제 됨", error)
    }).addTo(disposables)

연결 끊기

기본 정보

사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
필요 Android SDK
unlink()
ReactiveX Android SDK
unlink()

카카오 플랫폼 안에서 앱과 사용자 카카오계정의 연결 상태를 해제합니다. UserApiClientunlink()를 호출합니다.

연결이 끊어지면 기존의 토큰은 더 이상 사용할 수 없으므로, 연결 끊기 요청 성공 시 로그아웃 처리가 함께 이뤄져 토큰이 삭제됩니다.

다음은 연결 끊기 요청 예제입니다.

Kotlin
RxKotlin
// 연결 끊기
UserApiClient.instance.unlink { error ->
    if (error != null) {
        Log.e(TAG, "연결 끊기 실패", error)
    }
    else {
        Log.i(TAG, "연결 끊기 성공. SDK에서 토큰 삭제 됨")
    }
}
var disposables = CompositeDisposable()

// 연결 끊기
UserApiClient.rx.unlink()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({
        Log.i(TAG, "연결 끊기 성공. SDK에서 토큰 삭제 됨")
    }, { error ->
        Log.e(TAG, "연결 끊기 실패", error)
    }).addTo(disposables)

연결 끊기를 직접 호출한 경우가 아닌, 사용자가 서비스와의 연결을 직접 끊었을 때 알림을 받으려면 연결 끊기 알림 받기 기능을 사용합니다. 자세한 구현 방법 및 콜백 요청 정보는 연결 끊기 알림을 참고합니다.

사용자 정보 가져오기

기본 정보

사전 설정 카카오 로그인 사용자 동의 레퍼런스
플랫폼 등록
카카오 로그인 활성화
동의 항목
필요 필요:
사용자 정보를 요청할 모든 동의 항목
공통
User
Android SDK
me()
ReactiveX Android SDK
me()

현재 로그인한 사용자의 정보를 불러옵니다. UserApiClientme()를 호출합니다.

다음은 사용자 정보 요청 후 카카오계정의 회원번호, 이메일 주소, 닉네임을 출력해보는 예제입니다.

Kotlin
RxKotlin
// 사용자 정보 요청 (기본)
UserApiClient.instance.me { user, error ->
    if (error != null) {
        Log.e(TAG, "사용자 정보 요청 실패", error)
    }
    else if (user != null) {
        Log.i(TAG, "사용자 정보 요청 성공" +
                "\n회원번호: ${user.id}" +
                "\n이메일: ${user.kakaoAccount?.email}" +
                "\n닉네임: ${user.kakaoAccount?.profile?.nickname}" +
                "\n프로필사진: ${user.kakaoAccount?.profile?.thumbnailImageUrl}")
    }
}
var disposables = CompositeDisposable()

// 사용자 정보 요청 (기본)
UserApiClient.rx.me()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ user ->
        Log.i(TAG, "사용자 정보 요청 성공" +
                "\n회원번호: ${user.id}" +
                "\n이메일: ${user.kakaoAccount?.email}" +
                "\n닉네임: ${user.kakaoAccount?.profile?.nickname}" +
                "\n프로필사진: ${user.kakaoAccount?.profile?.thumbnailImageUrl}")
    }, { error ->
        Log.e(TAG, "사용자 정보 요청 실패", error)
    })
    .addTo(disposables)

사용자 정보 응답은 com.kakao.sdk.user.model에 정의되어 있는 User 클래스 객체로 전달됩니다. 예를 들어 회원 번호 값을 조회하려면 user.id, 카카오계정 프로필 정보들은 user.kakaoAccount.profile, 이메일은 user.kakaoAccount.email과 같이 접근할 수 있습니다.

하지만 사용자 정보 중 동의 항목으로 설정되지 않았거나, 사용자가 정보 제공에 동의하지 않았거나, 사용자가 해당 정보를 카카오에 제공한 적 없는 경우에는 값이 존재하지 않을 수 있으므로 예외 처리에 유의해야 합니다.

사용자 정보 종류는 사용자 정보를, 각 항목의 자료형 등 자세한 정보는 레퍼런스를 참고합니다.

사용자 정보 저장하기

기본 정보

사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
사용자 프로퍼티
필요 Android SDK
updateProfile()
ReactiveX Android SDK
updateProfile()

사용자 프로퍼티properties 필드 하위 정보의 값을 저장합니다. 키 값은 [내 애플리케이션] > [사용자 프로퍼티]에 정의한 값을 사용해야 합니다.

UserApiClientupdateProfile()을 호출합니다. 업데이트할 사용자 프로퍼티의 키와 값 목록을 Map으로 구성하여 전달해야 합니다. 다음 예제와 같이 요청합니다.

Kotlin
RxKotlin
// 사용자 정보 저장

// 변경할 내용
val properties = mapOf("${CUSTOM_PROPERTY_KEY}" to "${CUSTOM_PROPERTY_VALUE}")

UserApiClient.instance.updateProfile(properties) { error ->
    if (error != null) {
        Log.e(TAG, "사용자 정보 저장 실패", error)
    }
    else {
        Log.i(TAG, "사용자 정보 저장 성공")
    }
}
var disposables = CompositeDisposable()

// 사용자 정보 저장

// 변경할 내용
val properties = mapOf("${CUSTOM_PROPERTY_KEY}" to "${CUSTOM_PROPERTY_VALUE}")

UserApiClient.rx.updateProfile(properties)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({
        Log.i(TAG, "사용자 정보 저장 성공")
    }, { error ->
        Log.e(TAG, "사용자 정보 저장 실패", error)
    })

배송지 가져오기

기본 정보

사전 설정 카카오 로그인 사용자 동의 레퍼런스
플랫폼 등록
카카오 로그인 활성화
동의 항목
필요 필요:
배송지 정보(shipping_address)
공통
UserShippingAddresses
Android SDK
shippingAddresses()
ReactiveX Android SDK
shippingAddresses()

현재 로그인한 배송지 정보를 가져옵니다. UserClientshippingAddresses()를 호출합니다. 필요에 따라 다음 파라미터를 사용할 수 있습니다.

Name Type Description Required
fromUpdatedAt Date 여러 페이지에 걸쳐 응답이 제공될 때, 기준이 되는 배송지 updated_at 시각
해당 시각(미포함) 이전에 수정된 배송지부터 조회
이전 페이지의 마지막 배송지의 updated_at을 다음 페이지 input으로 사용
값을 0으로 전달하면 처음부터 조회
X
pageSize Int 2 이상, 한 페이지에 포함할 배송지 개수
기본 값 10
X

다음은 사용자가 배송지 정보 제공에 동의했는지 확인한 후, 사용자가 동의한 경우 배송지 정보를 요청하는 예제입니다.

Kotlin
RxKotlin
// 배송지 조회 (추가 동의)
UserApiClient.instance.shippingAddresses { userShippingAddresses, error ->
    if (error != null) {
        Log.e(TAG, "배송지 조회 실패", error)
    }
    else if (userShippingAddresses != null) {
        if (userShippingAddresses.shippingAddresses != null) {
            Log.i(TAG, "배송지 조회 성공" +
                    "\n회원번호: ${userShippingAddresses.userId}" +
                    "\n배송지: \n${userShippingAddresses.shippingAddresses?.joinToString("\n")}")
        }
        else if (userShippingAddresses.needsAgreement == false) {
            Log.e(TAG, "사용자 계정에 배송지 없음. 꼭 필요하다면 동의항목 설정에서 수집 기능을 활성화 해보세요.")
        }
        else if (userShippingAddresses.needsAgreement == true) {
            Log.d(TAG, "사용자에게 배송지 제공 동의를 받아야 합니다.")

            val scopes = listOf("shipping_address")

            // 사용자에게 배송지 제공 동의 요청
            UserApiClient.instance.loginWithNewScopes(context, scopes) { token, error ->
                if (error != null) {
                    Log.e(TAG, "배송지 제공 동의 실패", error)
                }
                else if (token != null) {
                    Log.d(TAG, "allowed scopes: ${token.scopes}")

                    // 배송지 조회 재요청
                    UserApiClient.instance.shippingAddresses { userShippingAddresses, error ->
                        if (error != null) {
                            Log.e(TAG, "배송지 조회 실패", error)
                        }
                        else if (userShippingAddresses != null) {
                            Log.i(TAG, "배송지 조회 성공" +
                                    "\n회원번호: ${userShippingAddresses.userId}" +
                                    "\n배송지: \n${userShippingAddresses.shippingAddresses?.joinToString("\n")}")
                        }
                    }
                }
            }
        }
    }
}
var disposables = CompositeDisposable()

// 배송지 조회 (추가 동의)
UserApiClient.rx.shippingAddresses()
    .flatMap { userShippingAddresses ->
        if (userShippingAddresses.needsAgreement == true) {
            Log.d(TAG, "사용자에게 배송지 제공 동의를 받아야 합니다.")

            // InsufficientScope 에러 생성
            Single.error(ApiError.fromScopes(listOf("shipping_address")))
        }
        else {
            Single.just(userShippingAddresses)
        }
    }
    .retryWhen(
        // InsufficientScope 에러에 대해 추가 동의 후 재요청
        RxAuthOperations.instance.incrementalAuthorizationRequired(context)
    )
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ userShippingAddresses ->
        if (userShippingAddresses.shippingAddresses != null) {
            Log.i(TAG, "배송지 조회 성공" +
                    "\n회원번호: ${userShippingAddresses.userId}" +
                    "\n배송지: \n${userShippingAddresses.shippingAddresses?.joinToString("\n")}")
        } else {
            Log.e(TAG, "사용자 계정에 배송지 없음. 꼭 필요하다면 동의항목 설정에서 수집 기능을 활성화 해보세요.")
        }
    }, { error ->
        Log.e(TAG, "배송지 조회 실패", error)
    })
    .addTo(disposables)

요청 성공 시 응답은 UserShippingAddresses 객체로 받습니다. UserShippingAddresses는 각각의 배송지 정보를 담은 ShippingAddress 객체의 리스트(List)를 포함합니다.

응답에 ShippingAddress 값이 없다면 needsAgreement 값을 참고해 사용자로부터 동의받아야 하는지 판단합니다. 해당 값이 true라면 사용자의 동의를 거쳐 배송지 정보를 받을 수 있으므로, 추가 항목 동의 받기 기능을 사용해 동의 및 배송지 정보를 받습니다. false라면 사용자의 동의 여부와 관계없이 배송지 정보를 받을 수 없는 상태이므로, 자체적으로 사용자로부터 배송지 정보를 수집해야 합니다. (참고: 사용자 동의 시 정보 제공 가능 여부)

동의 내역 확인하기

기본 정보

사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
동의 항목
필요 공통
ScopeInfo
Android SDK
scopes()
ReactiveX Android SDK
scopes()

사용자가 동의한 동의 항목의 상세 정보 목록을 조회합니다. [내 애플리케이션] > [카카오 로그인] > [동의 항목]에 설정된 동의 항목의 목록과 사용자가 동의한 동의 항목의 상세 정보를 반환합니다. 사용자가 기존에 동의했던 동의 항목이라면 현재 앱에 사용하도록 설정돼 있지 않아도 응답에 포함됩니다.

UserApiClientscopes()를 호출합니다. 요청 성공 시 응답은 scopeInfo 객체로 각 동의 항목의 상세 정보와 사용자 동의 여부를 포함합니다.

Kotlin
RxKotlin
UserApiClient.instance.scopes { scopeInfo, error->
    if (error != null) {
        Log.e(TAG, "동의 정보 확인 실패", error)
    }else if (scopeInfo != null) {
        Log.i(TAG, "동의 정보 확인 성공\n 현재 가지고 있는 동의 항목 $scopeInfo")
    }
}
var disposables = CompositeDisposable()

UserApiClient.rx.scopes()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ scopeInfo: ScopeInfo?->
        Log.i(TAG, "동의 정보 확인 성공\n 현재 가지고 있는 동의 항목 $scopeInfo")
    }, { error: Throwable? ->
        Log.e(TAG, "동의 정보 확인 실패", error)
    }).addTo(disposables)

특정 동의 항목의 동의 내역만 확인하려면 scopes 파라미터로 동의 항목의 ID를 지정하여 요청할 수 있으며, [내 애플리케이션] > [카카오 로그인] > [동의 항목]의 ID를 참고합니다. 동의 항목 ID를 지정한 경우, 성공 응답은 지정된 동의 항목의 정보만 포함합니다.

Kotlin
RxKotlin
// 동의 내역을 조회할 동의 항목 ID의 목록
val scopes = mutableListOf("account_email", "friends")

UserApiClient.instance.scopes(scopes) { scopeInfo, error->
    if (error != null) {
        Log.e(TAG, "동의 정보 확인 실패", error)
    }else if (scopeInfo != null) {
        Log.i(TAG, "동의 정보 확인 성공\n 현재 가지고 있는 동의 항목 $scopeInfo")
    }
}
var disposables = CompositeDisposable()

// 동의 내역을 조회할 동의 항목 ID의 목록
val scopes = mutableListOf("account_email", "friends")

UserApiClient.rx.scopes(scopes)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ scopeInfo: ScopeInfo?->
        Log.i(TAG, "동의 정보 확인 성공\n 현재 가지고 있는 동의 항목 $scopeInfo")
    }, { error: Throwable? ->
        Log.e(TAG, "동의 정보 확인 실패", error)
    }).addTo(disposables)

동의 철회하기

기본 정보

사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
동의 항목
필요 공통
ScopeInfo
Android SDK
revokeScopes()
ReactiveX Android SDK
revokeScopes()

사용자가 동의한 항목에 대해 동의를 철회합니다. 동의 내역 확인하기 API를 통해 조회한 동의 항목 정보 중 동의 철회 가능 여부(revocable) 값이 true인 동의 항목만 철회 가능합니다. 동의 철회가 불가능한 동의 항목을 대상으로 요청한 경우 에러 응답을 받습니다.

UserApiClientrevokeScopes()를 호출합니다. 철회할 동의 항목의 ID는 scopes 값으로 지정합니다. 요청 성공 시 응답은 scopeInfo 객체로, 동의 철회를 반영한 후의 각 동의 항목 상세 정보 및 사용자 동의 내역을 포함합니다.

Kotlin
RxKotlin
// 동의 철회할 동의 항목 ID의 목록
val scopes = mutableListOf("account_email", "legal_birth_date", "friends")

UserApiClient.instance.revokeScopes(scopes) { scopeInfo, error->
    if (error != null) {
        Log.e(TAG, "동의 철회 실패", error)
    }else if (scopeInfo != null) {
        Log.i(TAG, "동의 철회 성공\n 현재 가지고 있는 동의 항목 $scopeInfo")
    }
}
var disposables = CompositeDisposable()

// 동의 철회할 동의 항목 ID의 목록
val scopes = mutableListOf("account_email", "legal_birth_date", "friends")

UserApiClient.rx.revokeScopes(scopes)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ scopeInfo: ScopeInfo?->
        Log.i(TAG, "동의 철회 성공\n 현재 가지고 있는 동의 항목 $scopeInfo")
    }, {error: Throwable? ->
        Log.e(TAG, "동의 철회 실패", error)
    }).addTo(disposables)

동의한 약관 확인하기

카카오싱크 전용

카카오싱크를 도입한 서비스만 사용할 수 있는 기능입니다.

기본 정보
사전 설정 카카오 로그인 레퍼런스
플랫폼 등록
카카오 로그인 활성화
동의 항목
약관
필요 공통
UserServiceTerms
Android SDK
serviceTerms()
Reactive Android SDK
serviceTerms()

현재 로그인한 사용자가 동의한 약관 목록을 가져옵니다. UserApiClientserviceTerms() API를 호출합니다.

Kotlin
RxKotlin
// 동의한 약관 확인하기
UserApiClient.instance.serviceTerms { userServiceTerms, error ->
    if (error != null) {
        Log.e(TAG, "동의한 약관 확인하기 실패", error)
    }
    else if (userServiceTerms != null) {
        Log.i(TAG, "동의한 약관 확인하기 성공" +
                "\n회원번호: ${userServiceTerms.userId}" +
                "\n동의한 약관: \n${userServiceTerms.allowedServiceTerms?.joinToString("\n")}")
    }
}
var disposables = CompositeDisposable()
// 동의한 약관 확인하기
UserApiClient.rx.serviceTerms()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ userServiceTerms ->
        Log.i(TAG, "동의한 약관 확인하기 성공" +
                "\n회원번호: ${userServiceTerms.userId}" +
                "\n동의한 약관: \n${userServiceTerms.allowedServiceTerms?.joinToString("\n")}")
    }, { error ->
        Log.e(TAG, "동의한 약관 확인하기 실패", error)
    })
    .addTo(disposables)

요청 성공 시 응답은 UserServiceTerms 객체로 받습니다. UserServiceTerms는 사용자 회원번호와 동의한 약관 목록인 allowedServiceTerms를 포함합니다. allowedServiceTerms는 각 약관의 사용자 동의 시간과 태그(Tag) 정보를 제공하는 ServiceTerms 객체의 리스트(List)입니다.

ServiceTerms의 구성 요소 및 자료형은 REST API의 응답 및 레퍼런스를 참고합니다.

고급: 연결하기

기본 정보

사전 설정 카카오 로그인 권한 레퍼런스
플랫폼 등록
카카오 로그인 활성화
필요 필요:
수동 연결 설정 권한
Android SDK
signup()
ReactiveX Android SDK
signup()

주의: 자동 연결 사용 여부 확인

연결하기는 자동 연결을 사용하지 않는 앱에서만 사용하는 API입니다. 사용 전 REST API 개발 가이드를 통해 사용 여부와 주의사항을 확인해야 합니다.

연결하기는 자동 연결을 [사용 안함]으로 설정한 앱에서 앱과 사용자를 수동으로 연결하는 기능입니다. 현재 로그인한 사용자가 연결하기를 통해 앱과 연결되어야 하는지 확인하려면 사용자 정보 가져오기 응답의 hasSignedUp 값을 확인하여 다음과 같이 처리합니다.

  • true: 이미 사용자와 앱이 연결되어 있으므로 다시 연결하기를 호출하지 않습니다.
  • false: 사용자와 앱이 연결되지 않은 상태이므로 signup()을 호출해 사용자와 앱을 연결해야 합니다.
  • null: 자동 연결을 사용 중인 앱이므로 연결하기가 불필요합니다.
Kotlin
RxKotlin
UserApiClient.instance.me { user, error ->
    if (error != null) {
        Log.e(TAG, "사용자 정보 요청 실패", error)
    } else {
        Log.i(TAG, "사용자 정보 요청 성공" +
                "\n회원번호: ${user.id}" +
                "\n연결여부: ${user.hasSignedUp}")
    }
}
var disposables = CompositeDisposable()

UserApiClient.rx.me()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ user ->
        Log.i(TAG, "사용자 정보 요청 성공" +
                "\n회원번호: ${user.id}" +
                "\n연결여부: ${user.hasSignedUp}")
    }, { error ->
        Log.e(TAG, "사용자 정보 요청 실패", error)
    }).addTo(disposables)

사용자의 hasSignedUp 값이 false이고, 서비스에서의 가입 준비가 끝나 앱과 연결하려면 signup()을 호출합니다. properties 파라미터로 사용자 프로퍼티 저장을 함께 요청할 수 있습니다. properties 파라미터의 구성 방법은 사용자 정보 저장하기를 참고합니다.

Kotlin
RxKotlin
UserApiClient.instance.signup { error ->
    if (error != null) {
        Log.e(TAG, "signup 실패", error)
    } else {
        Log.i(TAG, "signup 성공")
    }
}
var disposables = CompositeDisposable()

UserApiClient.rx.signup()
        .subscribeOn(Schedulers.io())
        .subscribe(Action { showSnackbar("signup() 성공") }, onError).addTo(disposables)

요청 성공 시 별도의 사용자 정보가 제공되지 않으므로, 사용자 정보 가져오기 요청을 통해 다시 한 번 hasSignedUp 값을 확인해야 합니다.

Legacy

카카오 로그인의 Legacy Kakao SDK for Android 개발 가이드는 다음 링크에서 확인할 수 있습니다. 추후 Legacy Android SDK에 대한 지원이 중단될 수 있으므로, 가급적 빠른 시일 내에 최신 버전 Android SDK로 변경할 것을 권장합니다.

더보기