Kakao登录
kakao 介绍
Kakao 为韩国最大通讯公司
Kakao Login Android集成
Android 集成文档:
https://developers.kakao.com/docs/latest/en/kakaologin/android
MyApplication 设置
App Key 获取
https://developers.kakao.com/console/app[My Application] > [App Keys] or [My Application] > [Summary]
APP 关注 Native app key
Platform 设置
以 Android 为例:
- Packagename :应用的包名,即 applicationId,必选
- Market URL:应用市场链接,填上包名自动填写
- key hash:应用签名,需要用命令生成:
keytool -exportcert -alias <RELEASE_KEY_ALIAS> -keystore <RELEASE_KEY_PATH> | openssl sha1 -binary | openssl base64


Kakao Login
Kakao Login Activation
需要开启 Kakao Login Activation,否则获取不到 AccessToken
OpenID Connect Activation

Consent Items

右上角可以 preview:
初始化
class GlobalApplication : Application() {
override fun onCreate() {
super.onCreate()
// Other codes for initialization
// Initialize Android SDK
KakaoSdk.init(this, "${YOUR_NATIVE_APP_KEY}")
}
}
Before you begin login
Before using Kakao Login APIs with the Android SDK,
Register the Android platform
KaKao 注册平台登记后才能使用:[My Application] > [Platform] > Android/iOS/Web
- Package Name 应用的 applicationId
- Market URL 自动会生成
- Key hash
keytool -exportcert -alias <RELEASE_KEY_ALIAS> -keystore <RELEASE_KEY_PATH> | openssl sha1 -binary | openssl base64
类似:8tG0AIdXBAyX5aN8w83ECrKYMxxx
示例:
add modules
Gradle Install
// app build.gradle
// Allprojects not available in the latest Android Studio
allprojects {
repositories {
google()
jcenter()
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/'}
}
}
// settings.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
}
}
// modules to the build.gradle(module-level) file.
dependencies {
implementation "com.kakao.sdk:v2-all:2.18.0" // Add all modules (Available in 2.11.0 or higher)
implementation "com.kakao.sdk:v2-user:2.18.0" // Kakao Login
implementation "com.kakao.sdk:v2-talk:2.18.0" // Kakao Talk Social, Kakao Talk Messaging
implementation "com.kakao.sdk:v2-friend:2.18.0" // Friend picker
implementation "com.kakao.sdk:v2-share:2.18.0" // Kakao Talk Sharing
implementation "com.kakao.sdk:v2-navi:2.18.0" // Kakao Navi
implementation "com.kakao.sdk:v2-cert:2.18.0" // Kakao Certificate
}
ProGuard rules
# kakao https://developers.kakao.com/docs/latest/en/android/getting-started#project-pro-guard
-keep class com.kakao.sdk.**.model.* { <fields>; }
-keep class * extends com.google.gson.TypeAdapter
# https://github.com/square/okhttp/pull/6792
-dontwarn org.bouncycastle.jsse.**
-dontwarn org.conscrypt.*
-dontwarn org.openjsse.**
Set Redirect URI
refscheme 填 kakao${YOUR_NATIVE_APP_KEY}
<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${YOUR_NATIVE_APP_KEY}://oauth" -->
<data
android:host="oauth"
android:scheme="kakaob70bd3c3f3cdab01ccfe4cdd7f80542b" />
</intent-filter>
</activity>
Login
代码:
object KaKaoLoginHelper {
private const val TAG = "KaKaoLogin"
// 测试的app key
private const val APP_KEY = "b70bd3c3f3cdab01ccfe4cdd7f80542b"
fun init(context: Context) {
KakaoSdk.init(context, APP_KEY)
}
/**
* Check if KakaoTalk is installed on user's device
*
* @return true if KakaoTalk is installed on user's device, false otherwise
*/
fun isKakaoTalkLoginAvailable(context: Context): Boolean {
return UserApiClient.instance.isKakaoTalkLoginAvailable(context = context)
}
/**
* Login with Kakao Account/KakaoTalk
*/
fun login(context: Context, callback: (User?, Throwable?) -> Unit) {
// Login common callback
val internalCallback: (OAuthToken?, Throwable?) -> Unit = { token, error ->
if (error != null) {
// 登录过程中发生错误
loge("login 登录过程中发生错误:${error.message}", error)
error.printStackTrace()
callback.invoke(null, error)
} else if (token != null) {
// 登录成功,token 包含了访问令牌
Log.i(TAG, "login 登录成功,开始检索用户信息,token 包含了访问令牌:$token")
// 检索用户信息
getUserInfo { user: User?, throwable: Throwable? ->
if (throwable != null) {
// loge("login 登录成功,获取用户信息失败:${throwable.message}", throwable)
throwable.printStackTrace()
callback.invoke(null, throwable)
} else if (user != null) {
// logi("login 登录成功,检索用户信息成功,user(${user.id}):$user")
callback.invoke(user, null)
}
}
}
}
// If Kakao Talk is installed on user's device, proceed to log in with Kakao Talk. Otherwise, implement to log in with Kakao Account.
if (isKakaoTalkLoginAvailable(context)) {
logd("login with KakaoTalk")
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
if (error != null) {
// After installing Kakao Talk, if a user does not complete app permission and cancels Login with Kakao Talk, skip to log in with Kakao Account, considering that the user does not want to log in.
// You could implement other actions such as going back to the previous page.
if (error is ClientError && error.reason == ClientErrorCause.Cancelled) {
loge("login with KakaoTalk failed cancelled: ${error.message}", error)
return@loginWithKakaoTalk
}
loge(
"login with KakaoTalk failed, attempt loginWithKakaoAccount, error: ${error.message}",
error
)
// If a user is not logged into Kakao Talk after installing Kakao Talk and allowing app permission, make the user log in with Kakao Account.
UserApiClient.instance.loginWithKakaoAccount(
context,
callback = internalCallback,
)
} else if (token != null) {
logd("login with KakaoTalk succeeded, accessToken=${token.accessToken}")
internalCallback.invoke(token, null)
}
}
} else {
logd("login with KakaoAccount")
UserApiClient.instance.loginWithKakaoAccount(context, callback = internalCallback)
}
}
fun loginWithKakaoTalk(context: Context, callback: (User?, Throwable?) -> Unit) {
// Login with Kakao Talk
UserApiClient.instance.loginWithKakaoTalk(context) { token, error ->
if (error != null) {
loge("loginWithKakaoTalk failed.", error)
callback.invoke(null, error)
} else if (token != null) {
logi("loginWithKakaoTalk succeeded.${token.accessToken}")
// 检索用户信息
getUserInfo { user: User?, throwable: Throwable? ->
if (throwable != null) {
// 获取用户信息失败
// loge("loginWithKakaoTalk 登录成功,获取用户信息失败:${throwable.message}", throwable)
throwable.printStackTrace()
callback.invoke(null, throwable)
} else if (user != null) {
// logi("loginWithKakaoTalk 登录成功,检索用户信息成功,user(${user.id}):$user")
callback.invoke(user, null)
}
}
}
}
}
fun loginWithKakao(context: Context, callback: (User?, Throwable?) -> Unit) {
UserApiClient.instance.loginWithKakaoAccount(context) { token, error ->
if (error != null) {
// 登录过程中发生错误
loge("loginWithKakao 登录过程中发生错误:${error.message}", error)
error.printStackTrace()
callback.invoke(null, error)
} else if (token != null) {
// 登录成功,token 包含了访问令牌
// logi("loginWithKakao 登录成功,开始检索用户信息,token 包含了访问令牌:$token")
// 检索用户信息
getUserInfo { user: User?, throwable: Throwable? ->
if (throwable != null) {
// loge("loginWithKakao 登录成功,获取用户信息失败:${throwable.message}", throwable)
throwable.printStackTrace()
callback.invoke(null, throwable)
} else if (user != null) {
// logi("loginWithKakao 登录成功,检索用户信息成功,user(${user.id}):$user")
callback.invoke(user, null)
}
}
}
}
}
/**
* Retrieve user information
*
* https://developers.kakao.com/docs/latest/en/kakaologin/android#req-user-info
*/
fun getUserInfo(callback: (User?, Throwable?) -> Unit = { _, _ -> }) {
UserApiClient.instance.me { user: User?, throwable: Throwable? ->
if (throwable != null) {
// 获取用户信息失败
loge("getUserInfo 登录成功,获取用户信息失败:${throwable.message}", throwable)
throwable.printStackTrace()
callback.invoke(null, throwable)
} else if (user != null) {
// 获取用户信息成功,这里可以处理用户信息
logi("getUserInfo 登录成功,检索用户信息成功,user(${user.id}):$user")
callback.invoke(user, null)
}
}
}
/**
* Retrieve token information
*
* https://developers.kakao.com/docs/latest/en/kakaologin/android#get-token-info
*/
fun accessTokenInfo(callback: (tokenInfo: AccessTokenInfo?, error: Throwable?) -> Unit) {
// However, note that the return value true does not guarantee that the user is in a logged-in state.
if (AuthApiClient.instance.hasToken()) {
UserApiClient.instance.accessTokenInfo { tokenInfo, error ->
if (error != null) {
loge("accessTokenInfo Failed to retrieve token information.", error)
} else if (tokenInfo != null) {
logi(
"accessTokenInfo Retrieving token information success" +
"\n App ID: ${tokenInfo.appId}" +
"\nService user ID: ${tokenInfo.id}" +
"\nValidity period: ${tokenInfo.expiresIn} seconds"
)
}
callback.invoke(tokenInfo, error)
}
} else {
loge("accessTokenInfo Failed to retrieve token information. No token.")
callback.invoke(null, null)
}
}
/**
* Logout, Regardless of the result of the logout request, the Android SDK deletes the access and refresh tokens and has the login session end.
*
* deletes the access and refresh tokens issued to the user.
*
* https://developers.kakao.com/docs/latest/en/kakaologin/android#logout
*/
fun logout(callback: (Throwable?) -> Unit) {
UserApiClient.instance.logout { error ->
if (error != null) {
loge("Logout failed: ${error.message}", error)
callback.invoke(error)
} else {
logi("Logout succeeded")
callback.invoke(null)
}
}
}
/**
* Unlink
*
* If the request is successful, the Android SDK deletes the access and refresh tokens. As the issued tokens are deleted, the session between an app and a user is disconnected, and the user is logged out and unlinked from your app.
*
* https://developers.kakao.com/docs/latest/en/kakaologin/android#unlink
*/
fun unlink(callback: (error: Throwable?) -> Unit) {
UserApiClient.instance.unlink { error ->
callback.invoke(error)
if (error != null) {
loge("Unlink fail", error)
} else {
logi("Unlink success. Tokens are deleted from SDK.")
}
}
}
fun loge(msg: String, e: Throwable? = null) {
Log.e(TAG, msg, e)
}
fun logi(msg: String) {
Log.i(TAG, msg)
}
fun logd(msg: String) {
Log.d(TAG, msg)
}
}
kakao 登录授权弹窗
- 拿到 access_token 会拿到 userid
- 拿 userid 给中间层登录
遇到的问题
管理员设置问题导致授权不了
没有开启 kakao 登录
解决:kakao 应用后台开启
Error due to incorrect platform information:invalid android_key_hash or ios_bundle_id or web_site_url
解决:错误:invalid android_key_hash or ios_bundle_id or web_site_url
应用设置后台看看有没有注册对应的登录平台
Kakao SDK 评估
背景
亚洲站点、韩国市场,添加三方登录 Kakao
版本分析
新接入的 sdk,没有历史接入版本
影响范围
新功能,功能异常情况下会影响到 Kakao 用户的三方登录,需要做 abt 降级
价值评估
提升亚洲站点、韩国市场用户登录转化率
影响评估
App 质量
- github 没有相关仓库
- 最新版本的 SDK,App 质量暂时没办法验证,接入到测试的 Monkey 流程来测试稳定性,上线需观察, 发现有不可控的 Crash 问题需要 abt 降级
性能
待测试
包大小
aar 大小 (com.kakao.sdk:v2-user:2.18.0):342K
- user 103K
- network 22K
- common 90K
- auth 127K
兼容性
- Kakao 的 sdk 最低版本:Android6.0 及以上;而 shein/romwe app 最低兼容版本是 Android5.0
- 其他兼容问题待测试
业务功能影响
新功能,功能异常情况下会影响到 Kakao 用户的三方登录,需要做 abt 降级
技术方案评估
UI、UE
无影响
接口
无影响
效果监控
不实施
风险评估
电子应用市场审核规则风险评估
待评估
安全评估
- 获取用户的 email, phone,隐私协议是否需要更新?
降级方案
隐藏 Kakao 登录方式