코딩스토리

[Android/안드로이드] 카카오톡 로그인 (v2 ‘사용자 정보 요청’ API로 업데이트) 본문

Android/유용한 기술

[Android/안드로이드] 카카오톡 로그인 (v2 ‘사용자 정보 요청’ API로 업데이트)

라크라꾸 2020. 4. 15. 21:35

이전에 카카오톡으로 로그인을 할 경우 다음과 같은 메시지와 같이 사용자 정보 데이터를 가져올 수가 없었습니다.

application(id=383706, name='Test2') using deprecated api(/v1/user/me)

이 에러는 카카오에서 v1 '사용자 정보 요청'API가 종료되었기 때문입니다.

  • 1차 : 2020년 2월 10일
  • 2차 : 2020년 8월 10일 (1차 종료일 이전에 v2 '사용자 정보 요청’을 적용한 서비스에 한정)

카카오에서 미리 공지를 해주었는데 종료가 되었기 때문에 해당 API를 호출하면 에러 응답을 받게 됩니다.

카카오톡 API를 다시 사용하기 위해서는 v2 '사용자 정보 요청' API로 업데이트를 해야하는데, 업데이트를 적용한 방법에 대해 포스팅을 해보겠습니다.

 

2020/01/03 - [Android/유용한 기술] - [Android/안드로이드] 카카오톡 로그인 연동

 

APP Key 발급 및 등록 부분은 Kakao Develop UI가 바뀌긴했지만 저 저 내용을 보면 알것 같아서 따로 작성하진 않겠습니다.

 

App Key가 등록이 되었다 가정하고 진행하겠습니다.

 

 

프로젝트에 Kakao SDK 추가

strings.xml

 

  <resources>
      <string name="app_name">KakaoLoginSample</string>
      <string name="kakao_app_key">앱 키</string>
  </resources>

build.gradle(Project:~)파일에 다음과 같이 두줄을 추가해줍니다.

build.gradle(Project:~)

 

  allprojects {
      repositories {
          google()
          jcenter()
          maven{
              url "https://maven.google.com"
          }
          /*카카오*/
          maven { url 'http://devrepo.kakao.com:8088/nexus/content/groups/public/'}
      }
  }

 

gradle.properties파일에도 다음과 같이 두줄을 추가해줍니다.

gradle.properties

이전과 다른점 중에 하나는 이전에 있던 버전에서 업데이트를 해주었습니다.

  KAKAO_SDK_GROUP=com.kakao.sdk
  KAKAO_SDK_VERSION=1.27.0

 

build.gradle(Module:app)에 카카오톡 SDK를 추가해줍니다.

build.gradle(Module:app)

 

  dependencies {
      implementation group: project.KAKAO_SDK_GROUP, name: 'usermgmt', version: project.KAKAO_SDK_VERSION
  }

 

카카오 API연동

Kakao SDK를 사용하기 위해서는 초기화를 해줘야 합니다. 초기화는 GlobalApplication 공유 클래스를 만들어 앱 수준에서 관리하도록 하겠습니다. kakaoSDKAdapter클래스는 KakaoAdapter를 상속받습니다.

 

GlobalApplication.java

package com.lakue.kakaologinsample;

import android.app.Application;
import android.content.Context;

import com.kakao.auth.ApprovalType;
import com.kakao.auth.AuthType;
import com.kakao.auth.IApplicationConfig;
import com.kakao.auth.ISessionConfig;
import com.kakao.auth.KakaoAdapter;
import com.kakao.auth.KakaoSDK;



public class GlobalApplication extends Application {
    private static GlobalApplication instance;

    public static GlobalApplication getGlobalApplicationContext() {
        if (instance == null) {
            throw new IllegalStateException("This Application does not inherit com.kakao.GlobalApplication");
        }

        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;

        // Kakao Sdk 초기화
        KakaoSDK.init(new KakaoSDKAdapter());
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        instance = null;
    }

    public class KakaoSDKAdapter extends KakaoAdapter {

        @Override
        public ISessionConfig getSessionConfig() {
            return new ISessionConfig() {
                @Override
                public AuthType[] getAuthTypes() {
                    return new AuthType[] {AuthType.KAKAO_LOGIN_ALL};
                }

                @Override
                public boolean isUsingWebviewTimer() {
                    return false;
                }

                @Override
                public boolean isSecureMode() {
                    return false;
                }

                @Override
                public ApprovalType getApprovalType() {
                    return ApprovalType.INDIVIDUAL;
                }

                @Override
                public boolean isSaveFormData() {
                    return true;
                }
            };
        }

        // Application이 가지고 있는 정보를 얻기 위한 인터페이스
        @Override
        public IApplicationConfig getApplicationConfig() {
            return new IApplicationConfig() {
                @Override
                public Context getApplicationContext() {
                    return GlobalApplication.getGlobalApplicationContext();
                }
            };
        }
    }
}

GlobalApplication 객체를 공유하기 위해서 manifests.xml에 다음과 같이 추가를 해야합니다.

 

AuthType

Kakao SDK로그인을 하는 방식에 대한 Enum class

 

KAKAO_TALK 0 kakaotalk으로 login을 하고 싶을때 지정.
KAKAO_STORY 1 kakaostory으로 login을 하고 싶을때 지정.
KAKAO_ACCOUNT 2 웹뷰 Dialog를 통해 카카오 계정연결을 제공하고 싶을경우 지정.
KAKAO_TALK_EXCLUDE_NATIVE_LOGIN 3 카카오톡으로만 로그인을 유도하고 싶으면서 계정이 없을때 계정생성을 위한 버튼도 같이 제공을 하고 싶다면 지정.
KAKAO_TALK과 중복 지정불가.
KAKAO_LOGIN_ALL 4 모든 로그인 방식을 사용하고 싶을 때 지정.

 

manifests.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.lakue.kakaologinsample">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:name=".GlobalApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <meta-data
            android:name="com.kakao.sdk.AppKey"
            android:value="@string/kakao_app_key" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

인터넷을 사용하기 위해 <uses-permission android:name="android.permission.INTERNET" /> 를 넣어줘야 하고,

카카오에서 받아온 앱 키를 설정할 메타데이터 를 넣어줘야 합니다.

 

Login버튼 구현

로그인 버튼은 페이스북과 마찬가지로 카카오에서 제공하는 로그인 버튼과 사용자 맘대로 꾸밀 수 있는 커스텀 로그인버튼이 있습니다. 이번 프로젝트에서 두개 다 사용해보겠습니다.

 

activity_main.xml

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center"
      android:orientation="vertical"
      tools:context=".MainActivity">
  
      <Button
          android:id="@+id/btn_custom_login"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="카카오 로그인" />
  
      <com.kakao.usermgmt.LoginButton
          android:id="@+id/btn_kakao_login"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"/>
  
      <Button
          android:id="@+id/btn_custom_login_out"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="카카오 로그아웃" />
  
  
  </LinearLayout>

 

이제 MainActivity에서 버튼을 클릭했을 때 로그인을 요청해줍니다.

 

MainActivity.java

package com.lakue.kakaologinsample;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.kakao.auth.AuthType;
import com.kakao.auth.Session;
import com.kakao.usermgmt.UserManagement;
import com.kakao.usermgmt.callback.LogoutResponseCallback;

public class MainActivity extends AppCompatActivity {

    private Button btn_custom_login;
    private Button btn_custom_login_out;
    private SessionCallback sessionCallback = new SessionCallback();
    Session session;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn_custom_login = (Button) findViewById(R.id.btn_custom_login);
        btn_custom_login_out = (Button) findViewById(R.id.btn_custom_login_out);

        session = Session.getCurrentSession();
        session.addCallback(sessionCallback);

        btn_custom_login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                session.open(AuthType.KAKAO_LOGIN_ALL, MainActivity.this);
            }
        });

        btn_custom_login_out.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                UserManagement.getInstance()
                        .requestLogout(new LogoutResponseCallback() {
                            @Override
                            public void onCompleteLogout() {
                                Toast.makeText(MainActivity.this, "로그아웃 되었습니다.", Toast.LENGTH_SHORT).show();
                            }
                        });
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // 세션 콜백 삭제
        Session.getCurrentSession().removeCallback(sessionCallback);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        // 카카오톡|스토리 간편로그인 실행 결과를 받아서 SDK로 전달
        if (Session.getCurrentSession().handleActivityResult(requestCode, resultCode, data)) {
            return;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }
}

 

 

SessionCallback 클래스 구현

카카오톡 로그인 요청을 코드는 완성되었습니다. 이제 로그인 결과값을 전달받기 위한 Callback클래스를 구현하겠습니다.

 

SessionCallback.java

package com.lakue.kakaologinsample;

import android.util.Log;

import com.kakao.auth.ISessionCallback;
import com.kakao.network.ErrorResult;
import com.kakao.usermgmt.UserManagement;
import com.kakao.usermgmt.callback.MeV2ResponseCallback;
import com.kakao.usermgmt.response.MeV2Response;
import com.kakao.usermgmt.response.model.Profile;
import com.kakao.usermgmt.response.model.UserAccount;
import com.kakao.util.OptionalBoolean;
import com.kakao.util.exception.KakaoException;

public class SessionCallback implements ISessionCallback {

    // 로그인에 성공한 상태
    @Override
    public void onSessionOpened() {
        requestMe();
    }

    // 로그인에 실패한 상태
    @Override
    public void onSessionOpenFailed(KakaoException exception) {
        Log.e("SessionCallback :: ", "onSessionOpenFailed : " + exception.getMessage());
    }

    // 사용자 정보 요청
    public void requestMe() {
        UserManagement.getInstance()
                .me(new MeV2ResponseCallback() {
                    @Override
                    public void onSessionClosed(ErrorResult errorResult) {
                        Log.e("KAKAO_API", "세션이 닫혀 있음: " + errorResult);
                    }

                    @Override
                    public void onFailure(ErrorResult errorResult) {
                        Log.e("KAKAO_API", "사용자 정보 요청 실패: " + errorResult);
                    }

                    @Override
                    public void onSuccess(MeV2Response result) {
                        Log.i("KAKAO_API", "사용자 아이디: " + result.getId());

                        UserAccount kakaoAccount = result.getKakaoAccount();
                        if (kakaoAccount != null) {

                            // 이메일
                            String email = kakaoAccount.getEmail();

                            if (email != null) {
                                Log.i("KAKAO_API", "email: " + email);

                            } else if (kakaoAccount.emailNeedsAgreement() == OptionalBoolean.TRUE) {
                                // 동의 요청 후 이메일 획득 가능
                                // 단, 선택 동의로 설정되어 있다면 서비스 이용 시나리오 상에서 반드시 필요한 경우에만 요청해야 합니다.

                            } else {
                                // 이메일 획득 불가
                            }

                            // 프로필
                            Profile profile = kakaoAccount.getProfile();

                            if (profile != null) {
                                Log.d("KAKAO_API", "nickname: " + profile.getNickname());
                                Log.d("KAKAO_API", "profile image: " + profile.getProfileImageUrl());
                                Log.d("KAKAO_API", "thumbnail image: " + profile.getThumbnailImageUrl());

                            } else if (kakaoAccount.profileNeedsAgreement() == OptionalBoolean.TRUE) {
                                // 동의 요청 후 프로필 정보 획득 가능

                            } else {
                                // 프로필 획득 불가
                            }
                        }
                    }
                });
    }
}
Name Type Description
onSuccess UserProfile 사용자 정보 요청이 성공한 경우로 사용자 정보 객체를 받습니다.
onSessionClosed ErrorResult 세션이 닫혀 실패한 경우로 에러 결과를 받습니다. 재로그인 / 토큰발급이 필요합니다.
onFailure ErrorResult 가입이 안된 경우와 세션이 닫힌 경우를 제외한 다른 이유로 요청이 실패한 경우 콜백입니다.

 

갑자기 잘 되던 카카오톡 로그인이 안된다는 문의가 많이 와서 한번 찾아보게 되었습니다. 다음과 같이 사용자정보를 가져올 수 있습니다.

 

Kakao Developer를 참고하며 만들긴 했지만 실수한부분이 있을 수 있습니다. 지적할 부분이 있거나, 잘 안되서 문의주실분은 댓글 부탁드립니다~~

 

혹시몰라 깃허브에 파일 올려다 놓을게요 앱 키만 변경해서 사용해주세요~~

https://github.com/lakue119/KakaoLoginSample

 

lakue119/KakaoLoginSample

Contribute to lakue119/KakaoLoginSample development by creating an account on GitHub.

github.com

 

4 Comments
  • 프로필사진 1 2020.05.17 22:18 궁금한게 사용자 관리v2 를 사용하신건가요?
    코드 상에서는 사용자관리 v1 코드밖에 안보여서요,.,
  • 프로필사진 라크라꾸 2020.05.17 22:31 신고 현재 사용자관리 v2를 사용하고있습니다.. 어느부분이 v1코드로되있는지 알수있을까요...?? 제가작성할때는 다 v2로한거로 수정한거라서요...ㅠㅠ
  • 프로필사진 1 2020.05.18 15:27 아 제가 착각한 모양이네요, 죄송합니다.
    카카오 로그인SDK v2에서 로그인후 UserApiClient.rx.me() 으로 정보를 받아올 수 있길래 이게 V2 인줄 알았네요. 혼란 드려서 죄송합니다!
  • 프로필사진 신입개발자 2020.06.12 10:09 카카오톡에서 제공하는 컨셉의 버튼은 activity에서 따로 코딩을 안하나요? 그리고
    session = session.getCurrentSession();
    session.addCallback(sessionCallback); 이 부분들에서 getCurrentSession은 어디있는건가요. 빨간줄 뜹니다..
댓글쓰기 폼