Naver OAuth 2.0 for Android

이미지 출처: https://developers.naver.com/docs/login/bi/


01. Naver OAuth 2.0 API 신청하기

https://developers.naver.com/apps/#/register?api=nvlogin

02. 라이브러리 및 샘플 프로젝트 다운로드

https://developers.naver.com/docs/login/sdks/

03. API 사용가이드 상세

https://developers.naver.com/docs/login/android/

04. 샘플 프로젝트 임포트 및 샘플코드 수정

package me.blog.korn123.android_cookbook_2017.naver;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
 
import com.beardedhen.androidbootstrap.TypefaceProvider;
import com.google.gson.Gson;
import com.nhn.android.naverlogin.OAuthLogin;
import com.nhn.android.naverlogin.OAuthLoginDefine;
import com.nhn.android.naverlogin.OAuthLoginHandler;
 
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
 
import butterknife.BindView;
import butterknife.ButterKnife;
import me.blog.korn123.android_cookbook_2017.R;
 
/**
 * Created by hanjoong on 2017-03-08.
 * 네이버 개발자센터 제공 코드의 일부를 수정함.
 */
public class NaverLoginActivity extends AppCompatActivity {
 
    private static Context mContext;
    private static String OAUTH_CLIENT_ID = "QQxxxxxxxxxxxx";
    private static String OAUTH_CLIENT_SECRET = "yTp5Gxxxxxxx";
    private static String OAUTH_CLIENT_NAME = "네이버 아이디로 로그인";
    private static OAuthLogin mOAuthLoginInstance;
 
    private StringBuilder sb = new StringBuilder();
 
    @BindView(R.id.accessToken)
    TextView mAccessToken;
 
    @BindView(R.id.refreshTokenView)
    TextView mRefreshTokenView;
 
    @BindView(R.id.type)
    TextView mType;
 
    @BindView(R.id.state)
    TextView mState;
 
    @BindView(R.id.userInfo)
    TextView mUserInfo;
 
    @BindView(R.id.profileImage)
    ImageView mProfileImage;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TypefaceProvider.registerDefaultIconSets();
        setContentView(R.layout.activity_naver_login);
        ButterKnife.bind(this);
        mContext = NaverLoginActivity.this;
 
        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 
        OAuthLoginDefine.DEVELOPER_VERSION = true;
        initData();
        updateView();
    }
 
    /**
     * startOAuthLoginActivity() 호출시 인자로 넘기거나, OAuthLoginButton  등록해주면 인증이 종료되는    있다.
     */
    private OAuthLoginHandler mOAuthLoginHandler = new OAuthLoginHandler() {
        @Override
        public void run(boolean success) {
            if (success) {
                updateView();
            } else {
                String errorCode = mOAuthLoginInstance.getLastErrorCode(mContext).getCode();
                String errorDesc = mOAuthLoginInstance.getLastErrorDesc(mContext);
                Toast.makeText(mContext, "errorCode:" + errorCode + ", errorDesc:" + errorDesc, Toast.LENGTH_SHORT).show();
            }
        };
    };
 
    private void initData() {
        mOAuthLoginInstance = OAuthLogin.getInstance();
 
        mOAuthLoginInstance.init(mContext, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CLIENT_NAME);
        /*
         * 2015 8 이전에 등록하고  정보 갱신을 안한 경우 기존에 설정해준 callback intent url  넣어줘야 로그인하는데 문제가 안생긴다.
         * 2015 8 이후에 등록했거나  뒤에  정보 갱신을 하면서 package name  넣어준 경우 callback intent url  생략해도 된다.
         */
        //mOAuthLoginInstance.init(mContext, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CLIENT_NAME, OAUTH_callback_intent_url);
    }
 
    private void updateView() {
        String accessToken = mOAuthLoginInstance.getAccessToken(mContext);
        String refreshToken = mOAuthLoginInstance.getRefreshToken(mContext);
        long expiresAt = mOAuthLoginInstance.getExpiresAt(mContext);
        String tokenType = mOAuthLoginInstance.getTokenType(mContext);
        mAccessToken.setText("accessToken: " + accessToken);
        mRefreshTokenView.setText("refreshToken: " + refreshToken);
        mType.setText("type: " + tokenType);
        mState.setText("state: " + mOAuthLoginInstance.getState(mContext).toString());
        getSupportActionBar().setTitle("Naver OAuth token 유효시간");
        getSupportActionBar().setSubtitle(new Timestamp(expiresAt * 1000).toString());
 
        clearProfile();
    }
 
    private void clearProfile() {
        mUserInfo.setText((String) "");
        sb.setLength(0);
        mProfileImage.setImageResource(0);
    }
 
    public void executeTask(View view) {
        int id = view.getId();
        switch (id) {
            case R.id.login:
                mOAuthLoginInstance.startOauthLoginActivity(NaverLoginActivity.this, mOAuthLoginHandler);
                break;
            case R.id.requestUserInfo1:
                new RequestApiTask().execute();
                break;
            case R.id.refreshToken:
                new RefreshTokenTask().execute();
                break;
            case R.id.logout:
                mOAuthLoginInstance.logout(mContext);
                updateView();
                break;
            case R.id.deleteToken:
                mOAuthLoginInstance.logoutAndDeleteToken(mContext);
                updateView();
            default:
                break;
        }
    }
 
    private class RefreshTokenTask extends AsyncTask<Void, Void, String> {
        @Override
        protected String doInBackground(Void... params) {
            return mOAuthLoginInstance.refreshAccessToken(mContext);
        }
        protected void onPostExecute(String res) {
            updateView();
        }
    }
 
    private class RequestApiTask extends AsyncTask<Void, Void, Bitmap> {
        @Override
        protected void onPreExecute() {
            clearProfile();
        }
       
        /**
         * background thread에서 회원프로필 조회  프로필 이미지 생성
         * @param params
         * @return
         */
        @Override
        protected Bitmap doInBackground(Void... params) { // separate thread
            Bitmap profileImage = null;
            String url = "https://openapi.naver.com/v1/nid/me";
            String at = mOAuthLoginInstance.getAccessToken(mContext);
            String jsonString = mOAuthLoginInstance.requestApi(mContext, at, url);
            Map map = new Gson().fromJson(jsonString, HashMap.class);
            if (map.get("resultcode").equals("00")) {
                Map childMap = (Map)map.get("response");
                String profileUrl = String.valueOf(childMap.get("profile_image"));
                sb.append("message: " + map.get("message") + "\n");
                sb.append("resultcode: " + map.get("resultcode")+ "\n");
                sb.append("response.email: " + childMap.get("email") + "\n");
                sb.append("response.nickname: " + childMap.get("nickname") + "\n");
                sb.append("response.age: " + childMap.get("age") + "\n");
                sb.append("response.gender: " + childMap.get("gender") + "\n");
                sb.append("response.name: " + childMap.get("name") + "\n");
                sb.append("response.birthday: " + childMap.get("birthday") + "\n");
                profileImage = uriToBitmap(profileUrl);
            } else {
                makeSnackBar(findViewById(android.R.id.content), String.valueOf(map.get("message")));
            }
 
            return profileImage;
        }
       
        /**
         * main thread에서 프로필  이미지를 업데이트
         * @param profileImage
         */
        protected void onPostExecute(Bitmap profileImage) {    // main thread
            mUserInfo.setText(sb.toString());
            mProfileImage.setImageBitmap(profileImage);
        }
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                break;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }
 
    public void makeSnackBar(View view, String message) {
        Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction("Action", null).show();
    }
 
    public Bitmap uriToBitmap(String profileUrl) {
        HttpURLConnection connection = null;
        Bitmap bitmap = null;
        try {
            URL url = new URL(profileUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            InputStream input = connection.getInputStream();
            bitmap = BitmapFactory.decodeStream(input);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(connection!=null)connection.disconnect();
        }
        return bitmap;
    }
 
}

Table of contents


Open source project on GitHub


Jupyter/IPython Notebook


Open API


NoSQL


Jekyll


Gradle


Kotlin


C++

  • C++ keywords
  • 윤성우 열혈강의 C++ 프로그래밍 예제코드 [펼치기]
    1. C언어 기반의 C++ 1
      • printf와 scanf를 대신하는 입출력 방식
      • 함수 오버로딩(Function Overloading)
      • 매개변수의 디폴트 값(Default Value)
      • 인라인 함수(Inline)함수
      • 이름공간(namespace)에 대한 소개
    2. C언어 기반의 C++ 2
      • 새로운 자료형 bool
      • 참조자(Reference)의 이해
      • 참조자(Reference)와 함수
      • maloc & free를 대신하는 new & delete
      • C++에서 C언어의 표준함수 호출하기
    3. 클래스의 기본
      • C++에서의 구조체
      • 클래스(Class)와 객체(Object)
      • 객체지향 프로그래밍의 이해
    4. 클래스의 완성
      • 정보은닉(Information Hiding)
      • 캡슐화(Encapsulation)
      • 생성자(Constructor)와 소멸자(Destructor)
      • 클래스와 배열 그리고 this 포인터
    5. 복사 생성자
      • ‘복사 생성자’ 와의 첫 만남
      • ‘깊은 복사’와 ‘얕은 복사’
      • 복사 생성자의 호출시점
    6. friend와 static 그리고 const
      • const와 관련해서 아직 못다한 이야기
      • 클래스와 함수에 대한 friend 선언
      • C++에서의 static
    7. 상속(Inheritance)의 이해
      • 상속에 들어가기에 앞서
      • 상속의 문법적인 이해
      • protected 선언과 세 가지 형태의 상속
      • 상속을 위한 조건
    8. 상속과 다형성
      • 객체 포인터의 참조관계
      • 가상함수(Vitual Function)
      • 가상 소멸자와 참조자의 참조 가능성
    9. 가상(Virtual)의 원리와 다중상속
      • 멤버함수와 가상함수의 동작원리
      • 다중상속(Multiple Inheritance)에 대한 이해
    10. 연산자 오버로딩 1
      • 연산자 오버로딩의 이해와 유형
      • 단항 연산자의 오버로딩의
      • 교환법칙 문제의 해결
      • cout, cin 그리고 endl의 정체
    11. 연산자 오버로딩 2
      • 반드시 해야 하는 대입 연산자의 오버로딩
      • 배열의 인덱스 연산자 오버로딩
      • 그 이외의 연산자 오버로딩
    12. String 클래스의 디자인
      • C++ 표준과 표즌 string 클래스
      • 문자열 처리 클래스의 정의
    13. 템플릿(Template) 1
      • 템플릿(Template)에 대한 이해와 함수 템플릿
      • 클래스 템플릿(Class Temlpate)
    14. 템플릿(Template) 2
      • Chapter 13에서 공부한 내용의 확장
      • 클래스 템플릿의 특수화(Class Temlpate Specialization)
      • 템플릿의 인자
      • 템플릿과 static
    15. 예외처리(Exception Handling)
      • 예외상황과 예외처리의 이해
      • C++의 예외처리 메커니즘
      • Stack Unwinding(스택 풀기)
      • 예외상황을 표현하는 예외 클래스의 설계
      • 예외처리와 관련된 또 다른 특성들
    16. C++의 형 변환 연산자
      • C++에서의 형 변환 연산

ETC