안녕하세요~ 오늘은 안드로이드 스튜디오에서 카카오 로그인 API를 사용해서 카카오 로그인 기능을 구현하는 방법을 정리해 보았습니다.
맨처음 Kakao Developers에 들어가서 로그인을 합니다.
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
일단 애플리케이션을 만들어야합니다.
"+애플리케이션 추가하기" 클릭 합니다.
앱 아이콘, 앱 이름, 사업자명, 카테고리를 작성 후 운영정책 동의하고 저장을 합니다.
짠~ "테스트" 라는 애플리케이션이 생겼습니다.
테스트 애플리케이션에 들어가기전에 안드로이드 스튜디오를 통해서 "키 해시" 정보를 알아야됩니다.
키 해시(Key Hash) 란?
키 해시(Key Hash)란 인증서(Certificate)의 인증서 지문 값(Certificate fingerprints)을 해시(hash)한 값으로, 악성 앱인지 판별하는 데 사용됩니다. 카카오 API를 호출하면 카카오 API 서버가 요청 헤더에 추가된 키 해시값과 카카오 플랫폼에 등록한 값이 일치하는지 확인합니다. 키 해시는 디버그 키 해시(Debug key hash)와 릴리즈 키 해시(Release key hash) 두 가지가 있습니다.
- 디버그 키 해시: 프로젝트를 처음 생성하거나 디버그할 때, 안드로이드 스튜디오에서 개발 환경에 맞게 자동으로 생성되는 디버그 인증서에서 해시(hash)한 값
- 릴리즈 키 해시: 앱 스토어에 앱을 배포하기 위해 생성한 릴리즈 인증서로부터 해시한 값
https://developers.kakao.com/docs/latest/ko/android/getting-started
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
안드로이드 스튜디오 실행합니다.
키 해시 추출할 때 사용하는 코드입니다.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("키 해쉬 정보", "" + getKeyHash(MainActivity.this));
}
public static String getKeyHash(final Context context) {
PackageManager pm = context.getPackageManager();
try {
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
if (packageInfo == null)
return null;
for (Signature signature : packageInfo.signatures) {
try {
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(signature.toByteArray());
return android.util.Base64.encodeToString(md.digest(), android.util.Base64.NO_WRAP);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
안드로이드 스튜디오 Run하면
"키 해시" 정보를 알 수 있습니다.
다시 Kakao Developers로 들어가서 "테스트" 애플리케이션 클릭합니다.
"플랫폼 설정하기" 클릭합니다.
"Android 플랫폼 등록" 클릭합니다.
안드로이드 패키지명, 키 해시 입력 후 저장하기
패키지명은 밑에 사진에 있는 패키지명은 복사해서 붙이면 됩니다.
"카카오 로그인"에 들어가서 상태 ON으로 활성화 설정합니다.
닉네임, 프로필 사진 정보를 받고 싶으면 설정에 들어갑니다.
동의 단계, 등의 목적 선택 및 작성 후 저장합니다.
닉네임, 프로필 사진 정보 동의가 되었습니다.
다시 "요약 정보"로 돌아가서 "네이티브 앱 키"를 복사합니다.
그리고 안드로이드 스튜디오로 돌아가서 "buildgradle"에 카카오 sdk를 선언합니다.
plugins {
id 'com.android.application'
}
android {
namespace 'com.sample.testapplication'
compileSdk 33
defaultConfig {
applicationId "com.sample.testapplication"
minSdk 23
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation "com.kakao.sdk:v2-user-rx:2.9.0" // 카카오 로그인
implementation "com.github.bumptech.glide:glide:4.13.0"
}
"settings.gradle"에도 명시합니다.
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
rootProject.name = "TestApplication"
include ':app'
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
}
}
그리고, 카카오 로그인을 사용하기 위해서 코드를 입력합니다.
package com.sample.testapplication;
import android.app.Application;
import com.kakao.sdk.common.KakaoSdk;
public class KakaoApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
KakaoSdk.init(this, "네이티브 앱 키 입력하기");
}
}
매니패스트에 카카오 로그인 api사용 시 필요한 정보 선언합니다.
<?xml version="1.0" encoding="utf-8"?>
<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=".KakaoApplication"
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:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TestApplication"
tools:targetApi="31">
<activity
android:name=".HomeActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<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>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</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>
MainActivity.java
package com.sample.testapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.kakao.sdk.auth.model.OAuthToken;
import com.kakao.sdk.user.UserApiClient;
import com.kakao.sdk.user.model.User;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import kotlin.Unit;
import kotlin.jvm.functions.Function2;
public class MainActivity extends AppCompatActivity {
private Button btn_login;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_login = findViewById(R.id.btn_login);
// 카카오톡 설치 확인
Function2<OAuthToken, Throwable, Unit> callback = new Function2<OAuthToken, Throwable, Unit>() {
@Override
public Unit invoke(OAuthToken oAuthToken, Throwable throwable) {
kakaoLoginProcess();
return null;
}
};
// 로그인 버튼
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(UserApiClient.getInstance().isKakaoTalkLoginAvailable(MainActivity.this)) {
UserApiClient.getInstance().loginWithKakaoTalk(MainActivity.this, callback);
}else {
UserApiClient.getInstance().loginWithKakaoAccount(MainActivity.this, callback);
}
}
});
}
private void kakaoLoginProcess() {
UserApiClient.getInstance().me(new Function2<User, Throwable, Unit>() {
@Override
public Unit invoke(User user, Throwable throwable) {
// 로그인이 되어있으면
if (user!=null){
// 유저의 닉네임
String userNick = user.getKakaoAccount().getProfile().getNickname();
// 유저의 이미지
String profileImageUrl = user.getKakaoAccount().getProfile().getThumbnailImageUrl();
Intent intent = new Intent(MainActivity.this, HomeActivity.class);
intent.putExtra("nick", userNick);
intent.putExtra("img", profileImageUrl);
startActivity(intent);
}
return null;
}
});
}
}
activity_main.xml
<?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">
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="로그인"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
HomeActivity.java
package com.sample.testapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.kakao.sdk.user.UserApiClient;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
public class HomeActivity extends AppCompatActivity {
private Button logoutButton, deleteButton;
private TextView nickName;
private ImageView profileImage;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
logoutButton = findViewById(R.id.btn_logout);
deleteButton = findViewById(R.id.btn_delete);
nickName = findViewById(R.id.tv_nickname);
profileImage = findViewById(R.id.iv_profile);
Intent getIntentData = getIntent();
String nick = getIntentData.getStringExtra("nick");
String img = getIntentData.getStringExtra("img");
nickName.setText(nick);
Glide.with(profileImage).load(img).circleCrop().into(profileImage);
// 로그 아웃 버튼
logoutButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
UserApiClient.getInstance().logout(new Function1<Throwable, Unit>() {
@Override
public Unit invoke(Throwable throwable) {
finish();
return null;
}
});
}
});
// 회원탈퇴 버튼
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
UserApiClient.getInstance().unlink(new Function1<Throwable, Unit>() {
@Override
public Unit invoke(Throwable throwable) {
finish();
return null;
}
});
}
});
}
}
activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".HomeActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="200dp"
android:layout_height="200dp" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<Button
android:id="@+id/btn_logout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="로그아웃"/>
<Button
android:id="@+id/btn_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="회원탈퇴"/>
</LinearLayout>
코드를 실행시키고 로그인 버튼 클릭하면
카카오 동의서가 나오고 동의를 하면 로그인 성공합니다.$

여기까지 "카카오 로그인 API" 사용하는 방법에 대해서 진행해 보았습니다.
감사합니다.