안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

[삽질의 기록]

안드로이드 네이티브로 네이버 로그인을 구현하는 기능을 구현했다.

API 30부터 AsyncTask의 지원이 중단되므로 아래 링크를 참고하여 Custom Thread를 필요한 부분만 일부 구현하여 로그인 기능을 만들었다.

calvinjmkim.tistory.com/35

안드로이드 (Deprecated) AsyncTask 대체하기

안드로이드에서 백그라운드 작업을 하기 위해 자주 사용하는 AsyncTask가 사망선고를 받았다. 작년 하반기에 올라온 이 커밋에서 AsyncTask에 @Deprecated가 붙었고, 커멘트에 다음과 같이 나와 있다. Asy

calvinjmkim.tistory.com

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

우선 네이버 아이디로 로그인하는 SDK를 다운로드 한 후 압축을 푼다.

다운로드는 아래 링크에서 할 수 있다.

github.com/naver/naveridlogin-sdk-android/releases

Releases · naver/naveridlogin-sdk-android

네이버 아이디로 로그인 SDK (안드로이드). Contribute to naver/naveridlogin-sdk-android development by creating an account on GitHub.

github.com

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

SDK 압축을 풀면 .aar 파일을 확인할 수 있다.

이를 라이브러리로 적용하기위해 아래 사진과 같이 File > New > New Module을 클릭한다.

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

여기서 import .JAR/.AAR Package를 클릭한다.

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

여기서 네이버 아이디로 로그인 하기 SDK를 다운로드 후 압축을 푼 .aar 파일 경로를 입력한 후 Finish를 클릭한다.

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

다음으로 File > Project Structure > Dependencies > app 폴더 선택 > Dependency 여러 개 있는 부분에서 + 버튼 클릭 > Module dependency > 해당 sdk 추가한 후 apply 클릭하면, 모듈이 등록된다.

build.gradle(:Module)

dependencies {
  implementation project(path: ':naveridlogin_android_sdk_4.2.6')
}

위 과정이 안 되는 경우, 직접 build.gradle(:Module)에 등록하면 된다.

아래와 같이 직접 등록하는 방법도 있다.

이 때, 당연히 해당 프로젝트 파일 안에 libs 폴더 안에 aar 파일이 있어야 한다.

dependencies {
  implementation files('libs/naveridlogin_android_sdk_4.2.6.aar')
}

다음으로, 네이버 로그인을 하기 위해서 인터넷 권한을 얻어야한다.

따라서, 메니페스트 파일에 아래 코드를 삽입한다.

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

그리고 하나하나 입력하기 귀찮기 때문에 client_id, client_secret 등을 미리 strings.xml 파일에 넣어놓는다.

res/values/strings.xml

<resources>
  <string name="client_id">{your client id}</string>
  <string name="client_secret">{your client secret}</string>
  <string name="client_name">{your client name (아무거나 상관 없음)}</string>
</resources>

client_id와 client_secret 값은 Naver Developer에서 얻을 수 있다.

developers.naver.com/main/

NAVER Developers

네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음

developers.naver.com

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

우선, 본인의 애플리케이션을 생성한다.

생성했다면, Application > 내 애플리케이션 > 애플리케이션 정보에 client_id와 secret 값이 보인다.

이 값을 strings.xml에 넣는다.

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

이 화면에서 API 설정에서 본인이 로그인에서 제공하는 정보 중 어떤 것을 얻을 지 체크도 한다.

이 과정이 끝나면, 다시 프로젝트로 돌아온다.

본인이 로그인을 구현하는 화면에 아래와 같은 코드를 삽입한다.

activity_login.xml

<com.nhn.android.naverlogin.ui.view.OAuthLoginButton
      android:id="@+id/naver_login_btn"
      android:layout_width="50dp"
      android:layout_height="50dp"
      android:src="@mipmap/ic_naver_login_round"
      android:layout_centerInParent="true"/>

그리고, login 부분을 초기화하는 함수를 아래와 같이 작성한다.

이 init() 함수를 onCreate() 함수에서 호출한다.

LoginActivity.java

private void init(){
      OAUTH_CLIENT_ID = mContext.getString(R.string.client_id);
      OAUTH_CLIENT_SECRET = mContext.getString(R.string.client_secret);
      OAUTH_CLIENT_NAME = mContext.getString(R.string.client_name);

      mOAuthLoginInstance = OAuthLogin.getInstance();
      mOAuthLoginInstance.init(mContext, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CLIENT_NAME);

      mOAuthLoginButton = (OAuthLoginButton) findViewById(R.id.naver_login_btn);
      mOAuthLoginButton.setOAuthLoginHandler(mOAuthLoginHandler);
}

다음으로, LoginHandler 코드를 작성한다. 여기서 성공적으로 login을 한다면, accessToken을 받을 수 있다.

이 accessToken을 통해 사용자 정보를 받아올 수 있다. 사용자 정보를 받아오는 함수는 getUser()에서 받아온다.

LoginActivity.java

  private OAuthLoginHandler mOAuthLoginHandler = new OAuthLoginHandler() {
      @Override
      public void run(boolean success) {
          if(success){
              String accessToken = mOAuthLoginInstance.getAccessToken(mContext);
              long expiresAt = mOAuthLoginInstance.getExpiresAt(mContext);
              getUser(accessToken);
          }
          else{
              String errorCode = mOAuthLoginInstance.getLastErrorCode(mContext).getCode();
              String errorDesc = mOAuthLoginInstance.getLastErrorDesc(mContext);
          }
      }
  };

getUser 함수는 다음과 같다. getUser 함수에서 getUserTask라는 CustomThread를 생성 후 실행한다.

LoginActivity.java

private void getUser(String token){
  new GetUserTask().execute(token);
}

GetUserTask class는 아래와 같이 구성되어있다.

ThreadTask class에는 doInBackGround와 onPostExecute 함수로 구성되어있다.

또한, Naver Developer의 네이버 회원 프로필 조회 API 명세를 통해 HttpURLConnection을 통해 사용자 정보를 얻어왔다.

LoginActivity.java

private class GetUserTask extends ThreadTask<String, String>{
      @Override
      protected String doInBackground(String s) {
          String header = "Bearer " + s;
          String url = "https://openapi.naver.com/v1/nid/me";

          Map<String, String> requestHeaders = new HashMap<>();
          requestHeaders.put("Authorization", header);
          String responseBody = get(url, requestHeaders);

          return responseBody;
      }

      private String get(String url, Map<String, String> requestHeaders){
          HttpURLConnection connection = connect(url);
          try {
              connection.setRequestMethod("GET");
              for (Map.Entry<String, String> header : requestHeaders.entrySet()) {
                  connection.setRequestProperty(header.getKey(), header.getValue());
              }
              int responseCode = connection.getResponseCode();
              if (responseCode == HttpURLConnection.HTTP_OK) {
                  return readBody(connection.getInputStream());
              } else {
                  return readBody(connection.getErrorStream());
              }
          } catch (IOException e) {
              throw new RuntimeException("API 요청 및 응답 실패");
          } finally {
              connection.disconnect();
          }
      }

      private HttpURLConnection connect(String apiurl){
          try{
              URL url = new URL(apiurl);
              return (HttpURLConnection)url.openConnection();
          } catch (MalformedURLException e) {
              throw new RuntimeException("API URL이 잘못되었습니다. : " + apiurl, e);
          } catch (IOException e) {
              throw new RuntimeException("연결을 실패했습니다. : " + apiurl, e);
          }
      }

      private String readBody(InputStream body){
          InputStreamReader streamReader = new InputStreamReader(body);
          try(BufferedReader lineReader = new BufferedReader(streamReader)){
              StringBuilder responseBody = new StringBuilder();
              String line;
              while((line = lineReader.readLine()) != null){
                  responseBody.append(line);
              }
              return responseBody.toString();
          } catch (IOException e) {
              throw new RuntimeException("API 응답을 읽는데 실패했습니다. ", e);
          }
      }

      /*
      nickname, email, gender, birthday 외에도 회원 이름(본명?), 프로필 사진, 연령대도 가져올 수 있음.
       */
      @Override
      protected void onPostExecute(String s) {
          try {
              JSONObject jsonObject = new JSONObject(s);
              if(jsonObject.getString("resultcode").equals("00")){
                  JSONObject object = new JSONObject(jsonObject.getString("response"));
                  String nickname = object.getString("nickname");
                  String email = object.getString("email");
                  String gender = object.getString("gender");
                  String birthday = object.getString("birthday");
                  model = new NaverUserModel(nickname, email, gender, birthday);
              }
              loginDoneActivity();
          } catch (JSONException e) {
              e.printStackTrace();
          }
      }
  }

Naver Developer 회원 정보 조회 API 명세

developers.naver.com/docs/login/profile/

네이버아이디로로그인 회원 프로필 조회 가이드

NAVER Developers - 네이버아이디로로그인 회원 프로필 조회 가이드

developers.naver.com

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

+) ThreadTask.java

public abstract class ThreadTask<T1, T2> implements Runnable {
  T1 mArgument;
  T2 mResult;

  final public void execute(final T1 arg){
      mArgument = arg;
      Thread thread = new Thread(this);
      thread.start();

      try {
          thread.join();
      }
      catch (InterruptedException e){
          e.printStackTrace();
          onPostExecute(null);
          return;
      }
      onPostExecute(mResult);
  }

  @Override
  public void run() {
      mResult = doInBackground(mArgument);
  }

  protected abstract T2 doInBackground(T1 arg);

  protected abstract void onPostExecute(T2 Result);
}

++) 깃허브로 정리

github.com/Banlim/implement_social_login/blob/main/naver_login/README.md

Banlim/implement_social_login

implement_social_login_with_android || flutter. Contribute to Banlim/implement_social_login development by creating an account on GitHub.

github.com

안드로이드 네이버 로그인 버튼 - andeuloideu neibeo logeu-in beoteun

+++) Retrofit2 + Rxjava2를 통해 회원 프로필 조회하는 방법 추가 예정.