๐์๋๋ก์ด๋ ๊ฐ๋ฐํ๋ฉด์ ์ฌ์ฉ์ ์ธ์ฆ์ด ํ์ํ ๊ฒฝ์ฐ, ์ฌ์ฉ์ ์ ๋ณด๊ฐ ํ์ํ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ๊ทธ ๊ฒฝ์ฐ์ ์ ํฉํ ๊ธฐ์ ์ค ํ๋์ธ ์นด์นด์ค ๋ก๊ทธ์ธ์ ์์๋ณด๊ฒ ์ต๋๋ค.
Kakao Developer์ ์ ์ ํ ๋ก๊ทธ์ธํฉ๋๋ค.
์๋๋ก์ด๋ ํด์ ํค๋ ์์ ํ ํต์ ์ ๋ณด์ฅํ๊ณ ์ฑ์ ๋ฌด๋จ ์ฌ์ฉ์ ๋ฐฉ์งํ๋ฉฐ ์ฌ์ฉ์ ๋ฐ์ดํฐ์ ๋ณด์์ ์ ์งํ๋๋ฐ ๋์์ด ๋ฉ๋๋ค. ๋ํ ๊ฐ ์ฑ์ ๊ณ ์ ํ ์๋ช ํค๋ฅผ ๊ฐ์ง๋ฉฐ, ํน์ ์๋๋ก์ด๋ ์ฑ์ ๊ณ ์ ํ๊ฒ ์๋ณํฉ๋๋ค. ์ด๋ก ์ธํด ์นด์นด์ค๋ ๊ฐ ์ฑ์ ์๋ณํ๊ณ ํน์ ์ฑ์ ๋ํ ๋ณด์ ๋ฐ ๊ถํ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
private fun getAppKeyHash() {
try {
val info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
for (signature in info.signatures) {
val md: MessageDigest = MessageDigest.getInstance("SHA")
md.update(signature.toByteArray())
val hashKey = String(Base64.encode(md.digest(), 0))
Log.e(TAG, "ํด์ํค : $hashKey")
}
} catch (e: Exception) {
Log.e(TAG, "ํด์ํค๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค : $e")
}
}
์ด ๋ฉ์๋๋ฅผ onCreate()์์ ํธ์ถํด์ logcat์ ํ์ธํ์๋ฉด ๋ฉ๋๋ค.
<uses-permission android:name="android.permission.INTERNET"/>
<activity
android:name="com.kakao.sdk.auth.AuthCodeHandlerActivity"
android:exported="true">
<activity
android:name=".MainActivity"
android:exported="false">
</activity>
<activity android:name=".LoginActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<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="@string/kakao_redirection_scheme" />
</intent-filter>
</activity>
๋งค๋ํ์คํธ์ ํด๋น ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ด ์ฝ๋๋ ์นด์นด์ค ๋ก๊ทธ์ธ์ ์ํด ํ์ํ ์กํฐ๋นํฐ๋ฅผ ์ ์ํ๊ณ , ํด๋น ์กํฐ๋นํฐ๊ฐ ์ด๋ค ์ธํ ํธ๋ฅผ ์์ ํ ์ ์๋์ง๋ฅผ ์ง์ ํฉ๋๋ค.
implementation "com.kakao.sdk:v2-all:2.17.0"
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/'}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/userName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:textColor="@color/black"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/userThumbnail"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/userName" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/kakaoLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="@drawable/kakao_login_medium_wide"
android:layout_margin="20dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
์ฌ๊ธฐ์ ์นด์นด์ค ๋ก๊ทธ์ธ ๋ฒํผ ๋์์ธ์ ๋์์ธ ๊ฐ์ด๋๋ฅผ ๋ฐ๋ผ์ 'kakao_login_medium_wide'๋ฅผ ๋ค์ด ๋ฐ์์ ์ฌ์ฉํฉ๋๋ค.
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.kakaologin.databinding.ActivityLoginBinding
import com.kakao.sdk.auth.model.OAuthToken
import com.kakao.sdk.common.KakaoSdk
import com.kakao.sdk.user.UserApiClient
class LoginActivity: AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
KakaoSdk.init(this, getString(R.string.kakao_native_app_key))
binding.kakaoLogin.setOnClickListener {
login()
}
}
private fun login(){
if (UserApiClient.instance.isKakaoTalkLoginAvailable(this)) loginWithKakaoTalk()
else loginWithKakaoAccount()
}
private fun loginWithKakaoTalk(){
UserApiClient.instance.loginWithKakaoTalk(this){ token, error ->
handleLoginResult(token, error)
}
}
private fun loginWithKakaoAccount(){
UserApiClient.instance.loginWithKakaoAccount(this) { token, error ->
handleLoginResult(token, error)
}
}
private fun handleLoginResult(token: OAuthToken?, error: Throwable?){
if (error != null){
Toast.makeText(this, "๋ก๊ทธ์ธ ์คํจ!", Toast.LENGTH_SHORT).show()
} else if (token != null){
fetchUserInfo()
}
}
private fun fetchUserInfo(){
UserApiClient.instance.me { user, error ->
if (error != null){
Toast.makeText(this, "์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ ์คํจ!", Toast.LENGTH_SHORT).show()
} else if (user != null){
val userId = user.id
val userName = user.kakaoAccount?.profile?.nickname
val userThumbnail = user.kakaoAccount?.profile?.thumbnailImageUrl
val intent = Intent(this@LoginActivity, MainActivity::class.java)
intent.putExtra("userId", userId)
intent.putExtra("userName", userName)
intent.putExtra("userThumbnail", userThumbnail)
startActivity(intent)
}
}
}
}
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val userId = intent.getStringExtra("userId")
val userName = intent.getStringExtra("userName")
val userThumbnail = intent.getStringExtra("userThumbnail")
binding.userName.text = userName
Glide.with(binding.userThumbnail)
.load(userThumbnail)
.into(binding.userThumbnail)
}
}
์ฌ์ฉ์ ์ด๋ฆ๊ณผ ์ธ๋ค์ผ์ intent๋ก ๊ฐ์ ธ์จ ๊ฐ์ผ๋ก ์ค์ ํฉ๋๋ค. ์ธ๋ค์ผ์ค์ ์ Glide๋ฅผ ์ฌ์ฉํฉ๋๋ค.
plugins {
id 'kotlin-kapt'
}
dependencies {
// Glide
implementation 'com.github.bumptech.glide:glide:4.15.1'
kapt 'com.github.bumptech.glide:compiler:4.15.1'
}
๋ค์๊ณผ ๊ฐ์ด ์์กด์ฑ์ ์ถ๊ฐํ๋ฉด ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.