스터디에서 간단한 앱을 제작 중이고, 구글 로그인 기능을 구현했다.
관련 유튜브 영상에서 파이어베이스에 앱을 등록하는 방법, 이미지url 로딩에 도움이 되는 오픈소스를 참고했다.
파이어베이스 제품을 사용하기 위해 구성파일과 SDK를 추가하고, 파이어베이스 '구글로그인 인증' 구현해보았다.
구글 로그인은 크게 두가지 개념을 찾아봄으로써 이해할 수 있다. 어떤 객체가 필요한가, 인텐트로 결과를 주고받는 흐름을 따라가는 것이다. 이와 관련해 공식문서에 나온 예시코드를 선택적으로 변형했다.
첫번째 implementation: 앱에 파이어베이스 인증 추가 단계
dependencies {
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:29.0.0')
// Declare the dependency for the Firebase Authentication library
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-auth'
}
프로젝트에서 파이어베이스 라이브러리 제품들을 사용할 예정이다. 위의 그림처럼 권장목록과 원하는 기능들을 gradle에 추가해주었다.(AdMob,인증, 인앱 메세지, 인앱 메세지 표시, 원격구성 등) 그리고 이 라이브러리들의 버전을 관리할 수 있는 것이 맨 윗줄에 추가한 firebase-bom 이다.
implementation platform('com.google.firebase:firebase-bom:29.0.3')
implementation 'com.google.firebase:firebase-analytics'
implementation'com.google.firebase:firebase-auth:21.0.1'
implementation 'com.firebaseui:firebase-ui-auth:7.2.0'
implementation 'com.google.firebase:firebase-inappmessaging:20.1.1'
implementation 'com.google.firebase:firebase-inappmessaging-display:20.1.1'
implementation 'com.google.android.gms:play-services-auth:19.2.0'
두번째 implementation: 필요한 그외 dependency 추가 단계
파이어베이스가 제공하는 라이브러리, SDK 외에 Glide라는 오픈소스 프레임워크도 추가했다. 안드로이드용 오픈 소스 미디어 관리 및 이미지 로딩 프레임워크인데, 구글로그인에 성공한 사용자의 PhotoUrl을 로딩해서 화면에 띄우기 위해 사용할 예정이다.
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
크게 구글플레이 서비스의 구글로그인 API와 파이어베이스의 인증API로 이루어졌다.
1.GoogleSignInOptions
Auth.GOOGLE_SIGN_IN_API를 설정하는데 쓰이는 옵션을 담고있는 객체
2.GoogleSignInClient
API에서 구글로그인과 상호작용하는 클라이언트 객체
3.GoogleSignInAccount
로그인된 구글유저의 기본계정 정보를 담고 있는 객체
4.GoogleSignIn
Google 로그인 API의 진입점
5.AuthCredential
Represents a credential that the Firebase Authentication server can use to authenticate a user.
파이어베이스 인증서버가 사용자를 인증하기 위해 사용할 수 있는 사용자 인증정보를 나타냄
6.FirebaseAuth
파이어베이스 인증 SDK의 진입점
다시 코드의 흐름을 살펴보았다.
아래의 그림과 같이 구글로그인 설정과 파이어베이스 인증객체를 초기화한 후 로그인이 시작된다.
1.signIn()
구글로그인 페이지에서 사용자가 정보를 입력하기 위해선 해당 페이지로 이동해야 한다. 따라서 구글로그인과 상호작용할 수 있는 클라이언트 객체가 인텐트를 구글로그인 페이지 쪽으로 보내고, OnActivityResult를 통해 인텐트와 그 외 정보를 받을 수 있다.
private void signIn() {
Intent signInIntent = mGoogleSignInClient.getSignInIntent(); //구글로그인 페이지로 가는 인텐트 객체
startActivityForResult(signInIntent, RC_SIGN_IN); //Google Sign In flow 시작
}
2.OnActivityResult
구글로그인 인텐트에서 생성된 결과값을 이용해서 로그인이 성공했는지 확인하기 위해 requestcode가 일치하는지 확인한다.(나는 정수형 상수로 100을 임의로 지정했다.)
인텐트 GoogleSignIn는 구글로그인 API의 진입점이기 때문에 메소드를 사용해서 GoogleSignInAccount 객체 형식으로도 가공할 수 있다. 나는 파이어베이스 인증을 한 후 구글로그인 계정의 PhotoUrl과 DisplayName을 꺼내려다보니 계정의 토큰과 계정 자체의 객체 모두를 파이어베이스 인증API와 관련된 함수의 매개변수로 넘겨주었다.
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//구글로그인 인텐트에서 생성된 결과값이 리턴됨
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) { //requestCode를 받은 경우
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = task.getResult(ApiException.class);
Log.d(TAG, "firebaseAuthWithGoogle:" + account.getId());
//GoogleSignInAccount 객체에서 ID 토큰을 가져와서 firebaseAuthWithGoogle함수로 전달
firebaseAuthWithGoogle(account.getIdToken(), account);
} catch (ApiException e) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e);
}
}
}
3.firebaseAuthWithGoogle()
결국 앞의 구글로그인을 한 이유는 로그인된 사용자의 ID토큰과 계정객체를 알아내기 위함이 아니었을까 싶다. 얻은 토큰을 파이어베이스 사용자 인증정보로 바꿔서 인증을 완료한다. Task가 성공하면 내가 원했던 계정의 정보들을 인텐트에 담아서 원하는 액티비티로 보내는 것으로 마무리했다.
//전달받은 ID 토큰을 Firebase 사용자 인증 정보로 교환하고 해당 정보를 사용해 Firebase에 인증
private void firebaseAuthWithGoogle(String idToken, GoogleSignInAccount account) {
AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success
Toast.makeText(LoginActivity.this,"구글 로그인 성공",Toast.LENGTH_SHORT).show();
Intent intent = new Intent(getApplicationContext(),ResultActivity.class);
intent.putExtra("UserName", account.getDisplayName());
intent.putExtra("PhotoUrl", account.getPhotoUrl());
startActivity(intent);
} else {
// If sign in fails, display a message to the user.
Toast.makeText(LoginActivity.this,"구글 로그인 실패",Toast.LENGTH_SHORT).show();
}
}
});
}
정상적으로 동작하지만 폰으로 접속하는 것만큼 빠르지가 않다. 실제 서비스에서 이러면 별점 2.5나올 것 같은 속도이다. ㅋㅋㅋㅋㅋ 어떤 문제가 있는지 검토하는 게 새로운 공부거리가 될 듯하다!
일부분씩 포스팅한 코드의 원본은 아래 깃허브의 브랜치 GoogleLogin_LYI에 있다. 첫 앱스터디의 결과물이라서 조잡하지만, 로그인을 구현예시로는 만족스럽다.
https://github.com/Appstudy-inu/FirstApp