[Android] Google Login 구현하기

Minji Jeong·2022년 4월 25일
2

Android

목록 보기
4/39
post-thumbnail

😏 Google Login 구현해보기 by Kotlin

✔ 구글 로그인을 구현하기 위한 필수 조건

✅ Google API 콘솔 프로젝트 구성하기

1. Google Play Service 추가

프로젝트 최상위 build.gradle 파일에 Google Maven 저장소가 있는지 확인해야 한다. 나같은 경우엔 Bumblebee 버전을 사용하고 있기 때문에 build.gradle이 아닌 settings.gradle에서 확인해야 한다.

    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }

Google Maven 저장소가 있는지 확인했다면, build.gradle(module)에서 Google Play Service를 종속 항목으로 추가한다.

    dependencies {
        implementation 'com.google.android.gms:play-services-auth:20.1.0'
    }
2. Google API 콘솔 프로젝트 구성

위의 단계까지 잘 수행했으면 공식 문서에서 콘솔 프로젝트를 구성하라고 할 것이다. 먼저 프로젝트 구성 버튼을 클릭하면 다음과 같이 프로젝트명을 입력하라는 메세지창이 뜬다. 선택할 프로젝트명이 목록에 존재하지 않으면 생성하면 된다.


다음 단계에서는 사용자가 구글 로그인을 진행할 때, 이메일같은 개인 정보 제공에 동의를 구하는 메세지창이 나올텐데, 이 때 표시될 앱의 이름을 적어주면 된다.


다음으로 어떤 클라이언트 유형을 사용하는지 선택한 뒤, 구글 로그인을 사용할 안드로이드 앱의 패키지명과 SHA-1 해시값을 입력해준다.


나는 SHA-1 해시값을 얻기 위해 터미널 창을 열고 다음과 같이 입력했다.

./gradlew signingReport

만약 여기서 '.'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다 라는 에러 메세지가 뜬다면 터미널에 다음과 같이 입력한 다음 ctrl + Enter를 입력한다.

gradlew signingReport

입력 결과는 다음과 같이 콘솔창에 나타난다. 여기서 SHA1 부분을 복사해 SHA-1 signing certificate에 붙여넣기한다.

> Task :app:signingReport
Variant: debug
Config: debug
Store: 
Alias: AndroidDebugKey
MD5: 
SHA1:

콘솔 프로젝트 구성이 완료되면 Client ID와 Client Secret이 보이고 Client Configuration을 다운받을 수 있다. 다운받은 json 파일은 프로젝트의 app 폴더에 복붙해준다.

3. 코드 작성

먼저, 구글 로그인 버튼 위젯을 XML에 추가한다.

    <com.google.android.gms.common.SignInButton
        android:id="@+id/googleLoginBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:ignore="MissingConstraints" />

다음으로 구글 로그인을 구현하고자 하는 액티비티나 프래그먼트에서 앱에 필요한 사용자 데이터를 요청하도록 구글 로그인을 구성한다. 나는 프래그먼트를 사용했기 때문에 onViewCreated() 내부에서 GoogleSignInOptions 인스턴스를 생성했다. 사용자의 ID와 기본 프로필 정보를 요청하기 위해 GoogleSignInOption 인스턴스 생성 시 파라미터로 DEFAULT_SIGN_IN을 전달하고, 사용자의 이메일 주소를 요청하기 위해 requestEmail()을 호출한다.

val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .build()

gso를 통해 가져올 클라이언트의 정보를 담을 GoogleSignInClient 인스턴스를 만든다.

mGoogleSignInClient = context?.let { GoogleSignIn.getClient(it, gso) }!!

버튼 클릭 시 실행될 메서드를 구현하는데, 내부에 로그인 인텐트를 만들어 구글 로그인이 진행되도록 한다. 공식 문서에서는 startActivityForResult가 사용되었지만, 해당 메서드는 deprecated 되었기 때문에 다른 방식을 사용했다.

private fun signIn(){
	val signInIntent = mGoogleSignInClient.signInIntent
    resultLauncher.launch(signInIntent)
}

private var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
	if (result.resultCode == 1) {
    	val data: Intent? = result.data
        val task: Task<GoogleSignInAccount> =
                GoogleSignIn.getSignedInAccountFromIntent(data)
        handleSignInResult(task)
        }
}

이렇게 인텐트를 시작하면 사용자에게 로그인할 Google 계정을 선택하라는 메세지가 표시된다. getSignedInAccountFromIntent는 로그인한 사용자에 대한 정보가 반환되기 때문에, task를 이용해 다음과 같이 사용자의 정보를 다룰 수 있다.

private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>){
	try {
    	val account = completedTask.getResult(ApiException::class.java)
        val email = account?.email.toString()
        val familyName = account?.familyName.toString()
    } catch (e: ApiException){
        Log.w("failed", "signInResult:failed code=" + e.statusCode)
    }
}
4. 로그아웃

로그아웃도 정말 간단하다. 먼저 로그아웃용 버튼을 만들고, 로그아웃을 구현해야 하는 화면에서 GoogleSignInClient 객체를 생성한다.

val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).build()
mGoogleSignInClient = this.let { GoogleSignIn.getClient(it, gso) }

로그아웃 버튼에 클릭 리스너를 연결하고, onClick() 내부에서 GoogleSignInClient의 signOut()을 호출한다.

binding.button.setOnClickListener(this)

...

override fun onClick(v: View?) {
	when(v?.id){
		R.id.logoutBtn -> {
        	logout()
        }
    }
}
    
private fun logout() {
    mGoogleSignInClient.signOut()
    	.addOnCompleteListener(this) {
            // 로그아웃 성공시 실행
            // 로그아웃 이후의 이벤트들(토스트 메세지, 화면 종료)을 여기서 수행하면 됨
       }
}
추가 ) 이미 로그인한 사용자인지 검사하기!

이미 로그인한 사용자인지 검사하는 코드는 onStart() 내부에 작성한다. onStart() 내부에서 이 작업을 하는 이유는 해당 액티비티나 프래그먼트가 실행되기 직전에 로그인 유무를 검사해야 하기 때문이다. GoogleSignIn.getLastSignedInAccount()가 null을 반환하지 않으면 사용자가 이미 구글로 앱에 로그인을 한 것이고, null을 반환한다면 사용자가 아직 구글을 사용해 앱에 로그인하지 않은 것이다.

override fun onStart() {
	super.onStart()
        val account = context?.let { GoogleSignIn.getLastSignedInAccount(it) }
        if (account!=null){
        	...
        }
}

References

https://developers.google.com/identity/sign-in/android/start-integrating
https://developers.google.com/identity/sign-in/android/sign-in
https://stackoverflow.com/questions/62671106/onactivityresult-method-is-deprecated-what-is-the-alternative
https://velog.io/@jhsung23/Android-%EA%B5%AC%EA%B8%80-%EB%A1%9C%EA%B7%B8%EC%9D%B8-API-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

profile
Mobile Software Engineer

0개의 댓글