Implement Google Login with RxSocialLogin (Korean)

이 글은 안드로이드에서 RxSocialLogin 를 이용하여 구글 로그인을 구현하는 방법을 설명합니다. 모든 예제 코드는 코틀린으로 작성되었지만, 자바로도 같은 기능의 구현이 가능합니다.

사용된 메서드는 어떤 때나 변공될 수 있습니다. 항시 README 를 참고하세요.

프로젝트 불러오기

프로젝트에 RxSocialLogin 을 불러옵니다. RxAndroid 는 필수가 아니므로 사용하지 않다면 지워도 되지만, 정확한 Thread 처리를 위해 사용하기를 추천합니다. RxJava 의 새 기능 및 버그 수정을 위해 RxJava 에 대한 별도의 의존성을 추가합니다.

RxSocialLogin 의 최신 버전은 이며, RxJava 는 입니다.

Application 클래스에서의 초기화

README 를 따라서 Application 클래스에 초기화 코드를 추가합니다. 만일 여러 서비스를 추가할 경우, SocialLogin.init(this) 는 한 번만 호출되어야 합니다. 여러 서비스 연동 예제 링크는 다음과 같습니다. 링크

AndroidManifest.xml 파일에 Application 클래스를 선언하는 것을 잊지 마세요.

액티비티에 코드 작성

액티비티에 코드를 작성합니다. (Gist). GoogleLogin 필드가 필요하며, 액티비티의 onActivityResult 에서 GoogleLogin.onActivityResult 를 불러야 합니다.

로그인에 대한 결과는 RxSocialLogin.google 로 발행되는 subscription 으로 얻을 수 있습니다.

Firebase 에 프로젝트 추가

RxSocialLogin는 구글 로그인을 구현하기 위하여 Firebase Authentication 를 사용합니다. 따라서 프로젝트가 Firebase 에 연동되어 있어야 합니다.

키보드에서 Shift 두 번을 눌러 ‘Search Everywhere’ 를 표시하고, Firebase 를 검색합니다.

그러면, 안드로이드 스튜디오에 통합된 Firebaes Assistant 가 나올 것입니다. Authentication 버튼을 누르고 Email and password authentication 링크를 누릅니다.

Connect to Firebase 를 누릅니다.

Connect to Firebase 를 누릅니다. Firebaes Assistant 가 자동으로 새로운 Firebase 프로젝트를 생성하고 연결할 것입니다.

위 에러 메세지가 표시되더라도, 프로젝트 자체는 생성됩니다.

Firebase 콘솔에 들어가서, 생성된 Firebase Project 를 누릅니다.

세 개 점 버튼을 눌러 Setting을 누릅니다.

google-services.json 을 누르고 프로젝트의 app 모듈 폴더에 google-services.json 을 넣습니다.

Firebase Assistant 로 돌아와 Add Firebase Authentication to your app 를 누릅니다. 모든 작업이 끝나면 Firebase Assistant 가 아래 모습을 표시합니다.

인증 활성화

Firebase 콘솔로 돌아와, 왼쪽에 있는 Authentication 를 누르고 Sign-in method 탭을 누릅니다.

그러면 인증 제공자 페이지가 뜨게 되는데, Google 를 클릭합니다.

스위치를 키고, Web client ID를 메모장에 복사합니다. 이 정보는 GoogleConfig 에 필요합니다.

안드로이드 스튜디오로 돌아와 Applicaiton 클래스를 열고, 복사한 Web client ID 를 GoogleConfig.setClientTokenId 에 붙여넣습니다.

모든 작업이 끝났습니다. 이제 남은 것은 앱을 실행하기만 하면 되는 것 입니다.

Implement Google Login with RxSocialLogin (English)

This article explains how to implement Google Login on Android using RxSocialLogin. All code of example is written in Kotlin, but you can implement same feature in Java.

The methods used may change at any time. so you should check README of library.

Import

Import RxSocialLogin to your project. RxAndroid is optional. it’s recommended you dependent RxJava’s latest version for new feature and bug fix.

Lastest version of RxSocialLogin is , and RxJava is

Initialize in Application class

Write initialize code to Application class according to README. if you need to use another service, make sure SocialLogin.init(this) should call once. See link to see sample code of multiple service integration.

Don’t forget declare your Application class in AndroidManifest.xml.

Write code in Activity

Write code in MainActivity(Gist). you will need GoogleLogin property and call GoogleLogin.onActivityResult in Activity’s ActivityResult.

Response will come from subscription using RxSocialLogin.google.

add Project to Firebase

RxSocialLogin use Firebase Authentication for login to google. so, your project must registered in Firebase console.

On keyboard, double-click ‘Shift’ key to open ‘Search Everywhere’  and type ‘Firebase’.

You will get ‘Firebaes Assistant’ which integrated with Android Studio.

Click ‘Authentication’ and click ‘Email and password authentication’

Click ‘Connect to Firebase’.

Click ‘Connect to Firebase’ again. Firebase Assistant will create and connect new Firebase project.

Although you get this error message, Firebase project is created.

Browse to Firebase Console, click Firebase project which you created.

Click 3-dot button and click ‘Settings’ button.

Click ‘google-services.json’ button and put ‘google-service.json’ to directory of app module.

Back to Firebase Assistant, click ‘Add Firebase Authentication to your app’. After sync in done, Firebase Assistant display success flags.

Enable Authentication

Back to Firebase console, Click ‘Authentication’ in left side and click ‘Sign-in method’.

You will get this ‘Sign-in providers’ page. click ‘Google’.

Enable switch and copy ‘Web client ID’ to notepad. this information is need in Google Config.

Back to Android Studio, open your Application class and paste copied ‘Web client ID’ into GoogleConfig.setClientTokenId.

All work is done. All you have to do is run the application.

Introduction to RxSocialLogin :: Provides SocialLogin feature with RxJava

도입

약 9개월 전, 소셜 로그인 기능을 통합한 SocialLogin 라이브러리(https://github.com/WindSekirun/SocialLogin)를 만들어서 배포한 적이 있다. 이제까지는 무리 없이 사용했었지만, 최근 MVVM에 RxJava 를 도입하면서 콜백 방식이나 여러 가지가 마음에 안 드는 점이 있었다. 또한, 카카오 유저 v2 지원에 대한 요청(https://github.com/WindSekirun/SocialLogin/issues/13)이 들어와 처리하는 도중 코드를 관리하는 도중에도 자바로 작성한 것이라 조금 아쉬운 점이 있었다.

따라서 날 잡아서 SocialLogin 라이브러리를 다시 만드는 작업을 하기로 결정했는데, 적용될 작업은 다음과 같다.

  • 모든 메서드는 Kotlin 으로 재 작성
  • 가능하면 콜백 받는 방식을 RxJava 로 변경
  • Naver 로그인 요청 방식 변경
  • logout() 메서드 정리
  • README 문서 정리

이 5개 작업을 비롯해 재정비 작업을 완료했기에, 금일 시간 기준으로 0.5.0을 배포하였고, 이름을 RxSocialLogin(https://github.com/WindSekirun/RxSocialLogin) 으로 명명했다. 이 글에서는 간단한 소개 및 개발하면서 느꼈던 제약사항 (주로 RxJava) 에 대해 정리해보려고 한다.

소개

RxSocialLogin(https://github.com/WindSekirun/RxSocialLogin) 은 통합적인 소셜 로그인 기능을 제공하는 라이브러리로 페이스북, 카카오, 네이버, 라인, 트위터, 구글을 지원하는데, 기존 SocialLogin 과 차이는 없다. 또한 기존 라이브러리에도 있었던 장점인 모든 서비스에 대응하는 xxxLogin 클래스가 서로 같은 메서드를 가져 큰 차이점 없이 도입할 수 있다는 점도 변함이 없다.

하지만 내부적으로 RxJava, RxAndroid 를 도입하면서 기존에 사용하던 OnResponseListener 가 아닌 RxSocialLogin.kakao 로 결과값을 받을 수 있게 하여, 소셜 로그인 결과로 다른 작업을 Reactive 하게 진행할 수 있다.

RxSocialLogin 설계는 RxBinding(https://github.com/JakeWharton/RxBinding) 라이브러리의 설계를 많이 참고했는데, 기존 Listener 는 그대로 지원하는 동시에 Listener 를 포함하는 RxKakaoLogin 등의 클래스를 만들어 기존 구조를 크게 바꾸지 않으면서도 Callback 방식에서 Reactive 방식으로 업그레이드 하는 목표를 달성했다.

val kakaoDisposable = RxSocialLogin.kakao(kakaoLogin)
            .subscribe(Consumer<LoginResultItem> {
                Log.d(MainActivity::class.java.simpleName, "onNext: typeStr: ${it.toString()}")
            }, Consumer<Throwable> {
                Log.d(MainActivity::class.java.simpleName, "onError: ${it.message}")
            })

지금까지 각 소셜 서비스에서 제공하는 값을 받기 위해 사용했던 Map<UserInfoType, String> 또한 크게 변경되었는데, 기존에 있던 이 Map 객체에서 값을 꺼내서 사용해야 했던 단점을 회피하고자 새로운 결과 객체인 LoginResultItem 을 만들어 그대로 활용이 가능하게 만들었다. 따라서 Observable 가 LoginResultItem 만을 가지고 발행할 수 있게 했다.

그 외에도 구글 로그인 방법을 Google Sign-In API(https://developers.google.com/identity/sign-in/android/sign-in) 을 사용하는 것이 아닌 Firebase 인증(https://firebase.google.com/docs/auth/?hl=ko) 을 사용하여 Firebase 인증이 제공하는 다른 서비스 제공자들에 대해서도 구현할 수 있게 되었다.

제약 사항

현재 시점에서 RxJava 로 설계를 변경한 라이브러리는 이 라이브러리가 처음이었기에, 고민한 사항도  많았고, 아쉬운 부분도 많았다.

첫 번째로, 각 서비스를 호출하는 부분을 메인 스레드에서 호출할 수 있도록 강제한 점이다. 일반적으로 subscribe 하는 데에는 크게 문제는 없지만, 소셜 로그인의 결과값으로 서버 API 를 호출해야 할 경우에는 문제가 생긴다. 이는 원본 Observable, 즉 RxSocialLogin 가 요구하는 Thread 는 메인 스레드 이나, 서버 API 가 요구하는 Thread 는 메인 스레드가 아닌 백그라운드 스레드 ,정확히는 io 스레드이다. RxJava2 의 특성상 .subscribeOn 은 한 번만 적용되기 때문에 각 Observable 에 맞춘 스레드 변경이 불가능하다는 점이 있다.

만일 소셜 로그인 > 페이스북 친구 목록 가져오기 > 서버에 친구 목록 보내기 > ViewModel 갱신 이라는 비지니스 로직이 있을 경우에는 아래 방법으로 처리를 해야 한다.

// due to limitation, divide chain into two group
// see https://github.com/WindSekirun/RxSocialLogin#limitations
Disposable disposable = RxSocialLogin.facebook(facebookLogin)
        .subscribeOn(AndroidSchedulers.mainThread())
        .subscribe(resultItem -> FacebookUtils.newMyFriendsRequest(resultItem)
                .flatMap(data -> mSettingRepository.updateFriendsList(memberNumber, data))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(data -> loadData(), EMPTY_ERROR), EMPTY_ERROR);

addDisposable(disposable);

두 번째로, 소셜 로그인 결과를 가져오기를 실패했을 때 UndeliverableException 라는 오류가 가끔 나오는데, 이에 대한 해결책으로 Observer 에서 onNext (또는 onError) 하기 전 Observer.isDispose 를 체크하여 dispose 가 되지 않은 상태에서만 발행하게 했는데도 발생이 된다.

단, 이 문제는 onError 를 발행할 때 에만 문제가 되는 사항이고, 일반적인 경우에는 onError  가 반환된 일이 적어 아주 치명적인 문제는 아니지만 사용자 (= 개발자) 가 각 소셜 서비스의 프로젝트 설정을 잘못 했을 경우에는 자주 반환되는데, 그럴 때 마다 해당 문제가 발생하여 앱이 죽는 것이다.

당장은 RxJavaPlugin 의 setErrorHandler 메서드를 통하여 해당 예외가 발생하지 않게는 처리했지만, 이 클래스는 앱의 RxJava 로직 전반에 적용되므로 다소 위험하다는 단점이 있다.

그리고 사소하지만 개인 개발환경 (Macbook Pro 15′) 의 안드로이드 스튜디오가 build.gradle 를 변경할 때 마다 ‘Please select Android SDK’ 라는 문구가 뜨며 빌드가 안 되는 문제가 있었는데, 결국에는 임시 해결방법으로 최근 프로젝트 목록에서 삭제 후 재 임포트 라는 방식으로 해결했다. 해당 방법에 대한 자세한 사항은 https://stackoverflow.com/a/50000408 에서 볼 수 있다.

위 글에서 한 댓글에 아주 공감되었는데, 그 댓글은 다음과 같다.

To everyone that skipped over this…. I did not think this would fix my issue and I tried everything under this answer first. This is the only thing that worked. Don’t know why. Yeah it is super weird that this is the fix, but it is. Try this one

이 답변을 넘긴 모두에게, 나는 이 방법이 이슈를 해결할 것이라 생각하지 않아 아래에 있는 모든 답변을 시도했다. 이 방법 만이 작동했다. 왜 인지는 모르겠고 왜 작동하는지도 모르겠지만 어찌되었든 작동되니 이 방법을 사용해라

약 40분동안 삽질한 입장에서 매우 공감이 될 수 밖에 없었다 <(._.)>

마무리

개선할 사항은 분명하게도 남아있지만, 첫 RxJava-related 라이브러리가 생긴 것 만으로도 충분히 성공했다고 생각한다. Callback 을 쓰는 대신 Observable 나 Single 를 사용하는 것도 익숙해졌고, 앞으로도 계속 공부하면서 익혀 나가야 겠다고 생각했다.

마지막으로, 기존에 있던 SocialLogin 라이브러리는 7월 11일 기준으로 Deprecated 처리를 했고, 앞으로의 모든 업데이트는 RxSocialLogin 에서만 이루어질 계획이다.


특성 이미지는 https://www.tutorialrepublic.com/snippets/preview.php?topic=bootstrap&file=sign-in-from-with-social-login-button 에 있는 화면입니다.