KUSITMS/학술제

[안드로이드 스튜디오] 소셜 로그인 연동 - 카카오/구글/네이버

gom1n 2021. 10. 14. 02:30

카카오 로그인, 구글 로그인, 네이버 로그인을 구현해보았다.

연동 단계는 다 비슷하다. 1) 앱 등록 및 API 끌어오기     2) 코드 구현 (로그인, 로그아웃)

 

INDEX

1. 카카오 로그인

2. 구글 로그인

3. 네이버 로그인

(개인적으로 구글 > 카카오 > 네이버 순으로 어려웠다....)


1. 카카오 로그인

1) 카카오 디벨로퍼 사이트에 들어가 '내 애플리케이션' 등록을 한다.

https://developers.kakao.com/

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

생성하면 '플랫폼'에 들어가 안드로이드 앱을 등록시켜준다.

이때, 해쉬키(Hash Key)가 필요한데, 이것을 간단히 구하는 코드가 있다.

이걸 쓰고 돌리면 로그캣에 나의 해시키가 나온다. 등록!

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);
            }
        }
    }

 

2) 디벨로퍼 사이트에서 설정

내 애플리케이션 > '앱 선택' > 카카오 로그인 에 들어가 활성화시킨다.

이걸 찾는데에 굉장히 헤맸었다.

 

여기서 꼭! 활성화를 해준다. OFF > ON

 

 

동의하기 미리화면도 한번 봐준다. 잘 나왔다.

 

내 애플리케이션 > '앱 선택' > 카카오 로그인 > 동의항목에 들어가 카카오계정에서 가져올 데이터들을 체크한다.

현재 닉네임과 프사를 제외한 나머지 항목들은 다 검수가 필요해, 우선 저 두개만 체크설정해주었다.

 

 

3) build.Gradle (app), (project) / build.properties / strings.xml 설정

build.Gradle (app) 에 추가

// kakao login
    implementation group: project.KAKAO_SDK_GROUP, name: 'usermgmt', version: project.KAKAO_SDK_VERSION

 

build.Gradle (project) 에 추가

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

 

위의것만 하면 오류난다. build.properties에 들어가 아래를 추가해준다.

KAKAO_SDK_GROUP=com.kakao.sdk
KAKAO_SDK_VERSION=1.27.0

strings.xml에서 키를 입력해준다.

<resources>
    <string name="app_name">loginTest</string>
    <string name="kakao_app_key">xxx</string>
</resources>

 

 

4) AndroidManifest.xml

매니페스트에 GlobalApplication을 등록해줘야한다.

android:name=".GlobalApplication"

 

 

5) MainActivity.java / SessionCallback.java / GlobalApplication.java 를 만들어준다.

MainActivity.java

주어진 카카오버튼을 쓸 수도, 직접 로그인버튼을 만들어줄 수도 있다. (나는 직접 만들어줌) (그냥)

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.Base64;
import android.util.Log;
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;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

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_kakao_login = (Button) findViewById(R.id.btn_kakao_login);
        btn_kakao_logout = (Button) findViewById(R.id.btn_kakao_logout);

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

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

        btn_kakao_logout.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.java

카톡로그인 후 액티비티를 이동하고 싶다면, 이 세션콜백 클래스의 onSuccess()에 넣어주면 된다.

(나중엔 이 클래스를 메인 액티비티 클래스 안에 넣어주었다.)

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 {
                                // 프로필 획득 불가
                            }
                        }
                    }
                });
    }
}

 

 

GlobalApplication.java

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();
                }
            };
        }
    }
}

 

 

카톡 로그인 성공!


2. 구글로그인

구글로그인 연동하는 법을 찾아보면 firebase와 연동해서 하는 자료가 대다수이다.

이번 프로젝트에서는 로그인쪽에선 파이어베이스를 사용하지 않기 때문에, 

유일하게 안 하는 자료를 찾아 첨부한다. 굉장히 도움이 되었다.

https://develop-writing.tistory.com/32

 

[Android] 구글 로그인을 안드로이드 앱에 연동하기

이번에는 구글 로그인을 연동해보겠습니다. 구글 로그인도 카카오 로그인처럼 실 서비스에 적용하기 위해서는 다음 3단계를 거쳐야 합니다. 1. 앱 등록 및 설정 2. 기능 구현 3. 릴리즈 키 등록 저

develop-writing.tistory.com

 

우선 단계는 이러하다.

1) Google API Console에 들어가 앱 등록 및 설정

2) 코드 (기능 구현)

 

 

1) Google API Console에 들어가 앱 등록 및 설정

https://console.cloud.google.com/projectselector2/apis/dashboard?hl=ko&supportedpurview=project 

 

Google Cloud Platform

하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.

accounts.google.com

여기로 들어가 대시보드에서 프로젝트 하나를 생성한다.

만들라는 대로 착착착 만들어주면 된다. 

 

그 다음, 아래 공식문서에 들어가자.

https://developers.google.com/identity/sign-in/android/start-integrating

 

Android 앱에 Google 로그인 통합 시작  |  Google Sign-In for Android

Android 앱에 Google 로그인 통합 시작 자체 앱에서 Google 로그인 통합을 시작하려면 먼저 Google API 콘솔 프로젝트를 구성하고 Android Studio 프로젝트를 설정해야 합니다. 이 페이지의 단계는 바로 이 작

developers.google.com

 

잘 따라하면 된다.

자알 따라하는 과정이 궁금하다면, 클릭

더보기

1-1) build.gradle

allprojects {
    repositories {
        google()

        // If you're using a version of Gradle lower than 4.1, you must instead use:
        // maven {
        //     url 'https://maven.google.com'
        // }
    }
}

 

1-2) build.gradle (app)

apply plugin: 'com.android.application'
    ...

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:19.2.0'
    }

 

1-3) 프로젝트 등록 및 client ID 알아내기

파란 버튼 클릭
프로젝트 선택
안드로이드 선택 > 패키지 이름 + SHA지문 입력

 

이 과정을 완료하면 client ID와 client Secret이 나온다. 잘 복붙해놓자. 

 

 

2) 구글 로그인 연동 코드 

2-1) 버튼 클릭 함수 - 구글 클라이언트 객체 생성 후 signIn() 함수 호출

//구글 로그인
btn_google_login = (Button) findViewById(R.id.btn_google_login);
btn_google_login.setOnClickListener(new View.OnClickListener() {
	@Override
    public void onClick(View view) {
    	// 앱에 필요한 사용자 데이터를 요청하도록 로그인 옵션을 설정한다.
        // DEFAULT_SIGN_IN parameter는 유저의 ID와 기본적인 프로필 정보를 요청하는데 사용된다.
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
               .requestEmail() // email addresses도 요청함
               .build();

        // 위에서 만든 GoogleSignInOptions을 사용해 GoogleSignInClient 객체를 만듬
        mGoogleSignInClient = GoogleSignIn.getClient(MainActivity.this, gso);
        signIn();
    }
});

 

 

2-2) signIn() 함수 / onActivityResult 오버라이드

private void signIn() {
        Intent signInIntent = mGoogleSignInClient.getSignInIntent();
        startActivityForResult(signInIntent, RC_SIGN_IN);
}

 

 

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
        if (requestCode == RC_SIGN_IN) {
            // The Task returned from this call is always completed, no need to attach
            // a listener.
            Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
            handleSignInResult(task);
        }
        if (requestCode == 12501) { return; }   // google account 선택 안 했을 때
}

여기서 RC_SIGN_IN 이라는 구글 로그인 성공의 request code는 0116이다.

 private int RC_SIGN_IN = 0116;  //google login request code

 

 

2-3) 사용자 정보 가져오기

private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount acct = completedTask.getResult(ApiException.class);

            if (acct != null) {
                String personName = acct.getDisplayName();
                String personGivenName = acct.getGivenName();
                String personFamilyName = acct.getFamilyName();
                String personEmail = acct.getEmail();
                String personId = acct.getId();
                Uri personPhoto = acct.getPhotoUrl();

                Log.d(TAG, "handleSignInResult:personName "+personName);
                Log.d(TAG, "handleSignInResult:personGivenName "+personGivenName);
                Log.d(TAG, "handleSignInResult:personEmail "+personEmail);
                Log.d(TAG, "handleSignInResult:personId "+personId);
                Log.d(TAG, "handleSignInResult:personFamilyName "+personFamilyName);
                Log.d(TAG, "handleSignInResult:personPhoto "+personPhoto);
            }
        } catch (ApiException e) {
            // The ApiException status code indicates the detailed failure reason.
            // Please refer to the GoogleSignInStatusCodes class reference for more information.
            Log.e(TAG, "signInResult:failed code=" + e.getStatusCode());

        }
}

 

 

구글로그인 연동 성공!

 

번외) 로그아웃 함수

	//google logout
    private void googleSignOut() {
        mGoogleSignInClient.signOut()
                .addOnCompleteListener(this, new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        Toast.makeText(SubActivity.this, "로그아웃 되었습니다.", Toast.LENGTH_SHORT).show();
                        Intent intent = new Intent(SubActivity.this, MainActivity.class);
                        startActivity(intent);
                    }
                });
    }

3. 네이버 로그인

아래 블로그를 참고하면 놀라울 정도로 그냥 잘된다. 천재이신듯... 

(카카오로그인도 이 분꺼 보고 했는데,,,)

https://lakue.tistory.com/49

 

[Android/안드로이드] 네이버 아이디로 로그인(Naver Login) 연동

이번 포스팅에는 안드로이드 네아로(네이버 아이디로 로그인)연동하는법에 대해 알아보겠습니다. 우선 네이버 개발문서로 가서 통신 키값을 가져와야 합니다. https://developers.naver.com/docs/login/andr

lakue.tistory.com

 

여기서 하라는대로 네이버의 오픈API 이용 신청을 클릭, 

쭉쭉쭉 입력 후 등록을 하면 client ID와 client Secret이 나온다.

 

 

1) build.gradle (app)

dependencies {
    
        ...
        
        //네이버 로그인
        implementation 'com.naver.nid:naveridlogin-android-sdk:4.2.6'   // import from jcenter
    
        // naveridlogin dependencies
        def android_x_version = "1.0.0"
        implementation "androidx.appcompat:appcompat:$android_x_version"
        implementation "androidx.legacy:legacy-support-core-utils:$android_x_version"
        implementation "androidx.browser:browser:$android_x_version"
        implementation "androidx.legacy:legacy-support-v4:$android_x_version"
    }

 

2) strings.xml 에 추가.

<resources>
        <string name="app_name">NaverLoginSample</string>
    
        <string name="naver_client_id">xxx</string>
        <string name="naver_client_secret">xxx</string>
        <string name="naver_client_name">xxx</string>
    </resources>

(naver_client_name은 아무거나 써줬는데 됐다.)

(나는 앞서 카카오로그인을 구현해놨고 거기서 app_name을 이미 써줬기 때문에 패스해줌)

 

3) 버튼 추가

아래 링크에 나오는 네이버 로그인 로고를 다운로드 받아 버튼처럼 사용한다. 

https://developers.naver.com/docs/login/bi/bi.md

 

로그인 버튼 사용 가이드 - LOGIN

네이버 아이디로 로그인은 애플리케이션에 사용할 수 있는 네이버 로그인 버튼 기본 이미지를 제공합니다. 애플리케이션의 상황에 맞게 버튼 이미지의 디자인을 변경할 수 있지만 네이버 고유

developers.naver.com

 

4) 코드

로그인 후 다른 액티비티로 이동하려면 if(success) 함수 안에 써주면 된다.

import androidx.appcompat.app.AppCompatActivity;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import android.widget.Toast;
    
    import com.nhn.android.naverlogin.OAuthLogin;
    import com.nhn.android.naverlogin.OAuthLoginHandler;
    
    public class MainActivity extends AppCompatActivity {
    
        LinearLayout ll_naver_login;
        Button btn_logout;
    
        OAuthLogin mOAuthLoginModule;
        Context mContext;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mContext = getApplicationContext();
            
            ll_naver_login = findViewById(R.id.ll_naver_login);
            btn_logout = findViewById(R.id.btn_logout);
    
            ll_naver_login.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mOAuthLoginModule = OAuthLogin.getInstance();
                    mOAuthLoginModule.init(
                            mContext
                            ,getString(R.string.naver_client_id)
                            ,getString(R.string.naver_client_secret)
                            ,getString(R.string.naver_client_name)
                            //,OAUTH_CALLBACK_INTENT
                            // SDK 4.1.4 버전부터는 OAUTH_CALLBACK_INTENT변수를 사용하지 않습니다.
                    );
    
                    @SuppressLint("HandlerLeak")
                    OAuthLoginHandler mOAuthLoginHandler = new OAuthLoginHandler() {
                        @Override
                        public void run(boolean success) {
                            if (success) {
                                String accessToken = mOAuthLoginModule.getAccessToken(mContext);
                                String refreshToken = mOAuthLoginModule.getRefreshToken(mContext);
                                long expiresAt = mOAuthLoginModule.getExpiresAt(mContext);
                                String tokenType = mOAuthLoginModule.getTokenType(mContext);
    
                                Log.i("LoginData","accessToken : "+ accessToken);
                                Log.i("LoginData","refreshToken : "+ refreshToken);
                                Log.i("LoginData","expiresAt : "+ expiresAt);
                                Log.i("LoginData","tokenType : "+ tokenType);
    
                            } else {
                                String errorCode = mOAuthLoginModule
                                        .getLastErrorCode(mContext).getCode();
                                String errorDesc = mOAuthLoginModule.getLastErrorDesc(mContext);
                                Toast.makeText(mContext, "errorCode:" + errorCode
                                        + ", errorDesc:" + errorDesc, Toast.LENGTH_SHORT).show();
                            }
                        };
                    };
    
                    mOAuthLoginModule.startOauthLoginActivity(MainActivity.this, mOAuthLoginHandler);
                }
            });
    
            btn_logout.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mOAuthLoginModule.logout(mContext);
                    Toast.makeText(MainActivity.this, "로그아웃 되었습니다.", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

 

네이버 로그인 성공!


힘들다.