Personal Study/안드로이드

[Android][Java] 카카오 로그인 v2 구현하기

vㅔ로 2021. 9. 16. 01:09
728x90

진짜.. 많이 헤맸던 카카오 로그인

지금까지 소셜 로그인이 아니라 SMTP로 이메일 로그인만 구현해봤는데 카카오 로그인은 진짜 더 어려웠다. 

계속 올리려고 마음만 먹다가 이제 올려보려고 노력중이다. 이러고 또 임시 저장 글에 처박히겠지...? (드디어 다시 쓰기 시작)

다음에는 SMTP 로그인하는 방법도 글을 올려야겠다. 

 

카카오 로그인은 정말 다른 분들 블로그, 티스토리 등 여러 도움을 받았기 때문에 나도 기록겸해서 올려둔다. 

애석하게도 카카오 공식 문서가 다 코틀린으로 되어 있어서 코틀린 모르는 나는 자바로 구현하려고 아둥바둥댔다.

Java로 안드로이드 개발하는 나는 레퍼런스 찾는데도 엄청 오래 걸렸다...

이 문서가 '카카오 로그인 v2 예제 java'를 찾아 구글을 뒤지는 당신에게 도움이 되기를 바랍니다. (제 경험담입니다)

 

** 앱 플랫폼 등록, 해시키 등록 등 기본적인 부분은 모두 마쳤다고 간주하고 글을 작성하겠습니다 **

** 설정 중 부족한 부분이 있을 수 있습니다 **

 


gradle (project)의 allprojects 부분에 추가합니다.

maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }

 

gradle (module)의 dependencies 부분에 추가합니다.

필요한 부분만 나눠서 넣으시면 됩니다. 로그인은 카카오 로그인 v2 부분만 넣으셔도 사용하실 수 있습니다.

implementation "com.kakao.sdk:v2-user:2.5.2" // 카카오 로그인
implementation "com.kakao.sdk:v2-talk:2.5.2" // 친구, 메시지(카카오톡)
implementation "com.kakao.sdk:v2-story:2.5.2" // 카카오스토리
implementation "com.kakao.sdk:v2-link:2.5.2" // 메시지(카카오링크)
implementation "com.kakao.sdk:v2-navi:2.5.2" // 카카오내비

gradle(module)의 android 부분에 넣어줍니다.

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
    jvmTarget = "1.8"
}

 

GlobalApplication.java를 만듭니다.

import android.app.Application;

import com.kakao.sdk.common.KakaoSdk;

public class GlobalApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        KakaoSdk.init(this, "네이티브 앱 키 넣기");
    }
}

Manifest의 application name에 ".GlobalApplication" 추가

Manifest application 부분에 추가

<meta-data
            android:name="com.kakao.sdk.AppKey"
            android:value="앱 키 Ex) kakao네이티브앱키" />

 


이 부분부터 LoginActivity 구현입니다.

 

<LoginActivity.java>

 

import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
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 kotlin.Unit;
import kotlin.jvm.functions.Function2;

public class LoginActivity extends AppCompatActivity {
    private final static String TAG = "유저";
    private Button kakaoAuth, googleAuth;
    public static Context mContext;
    private SharedPreferences sharedPreferences;
    private User currentUser;
    private String userImageString = "";
    private Bitmap mBitmap;
    SharedPreferences.Editor editor;
    private Boolean isTrue = false;
    private Boolean nextIntent = false;
    private String meetingId;
    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        Function2<OAuthToken, Throwable, Unit> callback = new Function2<OAuthToken, Throwable, Unit>() {
            @Override
            public Unit invoke(OAuthToken oAuthToken, Throwable throwable) {
                if (oAuthToken != null) {
                    Log.i("user", oAuthToken.getAccessToken() + " " + oAuthToken.getRefreshToken());
                }
                if (throwable != null) {
                    // TBD
                    Log.w(TAG, "invoke: " + throwable.getLocalizedMessage());
                }
                updateKakaoLoginUi();

                return null;
            }
        };

        kakaoAuth = findViewById(R.id.kakao_auth_button);  // 저는 카카오톡 로그인 버튼을 만들어서 했습니다.

        kakaoAuth.setOnClickListener(new View.OnClickListener() {   // 로그인 버튼 클릭 시
            @Override
            public void onClick(View v) {
                if (UserApiClient.getInstance().isKakaoTalkLoginAvailable(LoginActivity.this)) {
                    // 카카오톡이 있을 경우?
                    UserApiClient.getInstance().loginWithKakaoTalk(LoginActivity.this, callback);
                } else {
                    UserApiClient.getInstance().loginWithKakaoAccount(LoginActivity.this, callback);
                }
            }
        });
        updateKakaoLoginUi();
    }

    public void updateKakaoLoginUi() {
        // 카카오 UI 가져오는 메소드 (로그인 핵심 기능)
        UserApiClient.getInstance().me(new Function2<User, Throwable, Unit>() {
            @Override
            public Unit invoke(User user, Throwable throwable) {
                if (user != null) {
                    // 유저 정보가 정상 전달 되었을 경우
                    Log.i(TAG, "id " + user.getId());   // 유저의 고유 아이디를 불러옵니다.
                    Log.i(TAG, "invoke: nickname=" + user.getKakaoAccount().getProfile().getNickname());  // 유저의 닉네임을 불러옵니다.
                    Log.i(TAG, "userimage " + user.getKakaoAccount().getProfile().getProfileImageUrl());    // 유저의 이미지 URL을 불러옵니다.

                    // 이 부분에는 로그인이 정상적으로 되었을 경우 어떤 일을 수행할 지 적으면 됩니다.
                }
                if (throwable != null) {
                    // 로그인 시 오류 났을 때
                    // 키해시가 등록 안 되어 있으면 오류 납니다.
                    Log.w(TAG, "invoke: " + throwable.getLocalizedMessage());
                }
                return null;
            }
        });
    }
}

 


후기

처음 해본 소셜 로그인이었는데, 너무너무 어려웠다.

콜백에 대한 이해가 부족한 상태로 하려니 조금 죽을 맛이었다...

콜백함수, 코틀린 공부가 필요하다는 것을 뼈저리게 느꼈다. 

 


이 부분부터는 온전히 기록용이라 사용하기에는 애매하실 수 있습니다.

 

** 번외 - 카카오톡 로그아웃 **

 

 

logoutButton.setOnClickListener(new View.OnClickListener() {
            // 로그아웃 버튼
            @Override
            public void onClick(View v) {
                UserApiClient.getInstance().logout(new Function1<Throwable, Unit>() {
                    @Override
                    public Unit invoke(Throwable throwable) {
                        ((LoginActivity)LoginActivity.mContext).updateKakaoLoginUi(); // LoginActivity의 updateKakaoLoginUi를 가져오기 위해 context(this 저장)를 만들었습니다.
                        return null;
                    }
                });
                Intent backIntent = new Intent(getApplicationContext(), LoginActivity.class);  // 로그인 화면으로 이동
                startActivity(backIntent);
                finish();
            }
        });

 

** 번외 - 해시키(키해시) 함수 **

 

private void getHashKey(){
        PackageInfo packageInfo = null;
        try {
            packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        if (packageInfo == null)
            Log.e("KeyHash", "KeyHash:null");

        for (Signature signature : packageInfo.signatures) {
            try {
                MessageDigest md = MessageDigest.getInstance("SHA");
                md.update(signature.toByteArray());
                Log.d("KeyHash", Base64.encodeToString(md.digest(), Base64.DEFAULT));
            } catch (NoSuchAlgorithmException e) {
                Log.e("KeyHash", "Unable to get MessageDigest. signature=" + signature, e);
            }
        }
    }

 

 

728x90