본문 바로가기
카테고리 없음

[Android][Java] 안드로이드 카카오 로그인 구현하는 방법

by felix_203 2024. 5. 14.

안녕하세요~ 오늘은 안드로이드 스튜디오에서 카카오 로그인 API를 사용해서 카카오 로그인 기능을 구현하는 방법을 정리해 보았습니다.

 

 

 

 

 

 

맨처음 Kakao Developers에 들어가서 로그인을 합니다.

https://developers.kakao.com/

 

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" 사용하는 방법에 대해서 진행해 보았습니다.

감사합니다.