[Kotlin] Firebase로 로그인 기능 구현하기 (3) - 페이스북 로그인

Jiyeahhh·2021년 11월 19일
0

1. Facebook Developer 들어가기

https://developers.facebook.com/

  • 로그인한 후, 새로운 앱 만들기(뭘 해야할 지 잘 모르겠어서 없음으로 했음)
  • 대시보드에서 페이스북 로그인 설정 > 안드로이드 선택

1. Android용 Facebook SDK 다운로드에서 다음 선택
2. Facebook SDK 가져오기

  • 다음 코드 build.gradle (Project)repositories에 추가
mavenCentral() 
  • 다음 코드 build.gradle (Module: app)dependencies에 추가
implementation 'com.facebook.android:facebook-android-sdk:[4,5)'

3. Android 프로젝트에 대해 Facebook에 알리기

  • 패키지 이름클래스 이름 추가

    fun printHashKey() {
        try {
            val info: PackageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
            for (signature in info.signatures) {
                val md: MessageDigest = MessageDigest.getInstance("SHA")
                md.update(signature.toByteArray())
                val hashKey: String = String(Base64.encode(md.digest(), 0))
                Log.i("TAG", "printHashKey() Hash Key: $hashKey")
            }
        } catch (e: NoSuchAlgorithmException) {
            Log.e("TAG", "printHashKey()", e)
        } catch (e: Exception) {
            Log.e("TAG", "printHashKey()", e)
        }
    }

👉 Hash 값을 얻기 위한 함수!

  • onCreate()에서 printHashKey() 실행
  • LogcatTag 검색하면 다음과 같이 Hash Key 확인 가능

4. 개발 및 릴리스 키 해시 추가

  • 위에서 구한 Hash key 추가

5. 앱에 대한 SSO 활성화

  • 다른 앱에서 쉽게 페이스북 로그인을 할 수 있도록 허가해주는 부분
  • 로 설정

6. 리소스 및 메니페스트 수정

  • app/res/values/strings.xmlid, protocol_scheme 추가
  • /app/manifest/AndroidManifest.xml에 권한 추가

  <uses-permission android:name="android.permission.INTERNET"/>
  • 다음 meta-data 요소, Facebook에 대한 활동, Chrome 맞춤 탭에 대한 활동 및 인텐트 필터application 요소 내에 추가
        <meta-data
            android:name="com.facebook.sdk.ApplicationId"
            android:value="@string/facebook_app_id" />

        <activity
            android:name="com.facebook.FacebookActivity"
            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter><action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>

FirebaseAuthentication > Sign-in-method페이스북 정보 매핑시키기

  • OAuth 리디렉션 URI 복사해서 붙여넣기 (Firebase → Facebook)

  • 설정 > 기본 설정에서 앱 ID앱 시크릿 코드 복사해서 붙여넣기 (Facebook → Firebase)

  • 설정 끝!


2. 소스 코드

  • facebookLogin 함수
fun facebookLogin() {
        // 페이스북에서 받을 권한 요청 - 프로필 이미지, 이메일
        LoginManager.getInstance()
            .logInWithReadPermissions(this, Arrays.asList("public_profile", "email"))
        // LoginResult : 페이스북 로그인이 최종 성공했을 때 넘어오는 부분
        LoginManager.getInstance()
            .registerCallback(callbackManager, object : FacebookCallback<LoginResult>{
                override fun onSuccess(result: LoginResult?) {
                    // Second step
                    // 로그인이 성공하면 페이스북 데이터를 파이어베이스에 넘기는 함수
                    handleFacebookAccessToken(result?.accessToken)
                }

                override fun onCancel() {
                }

                override fun onError(error: FacebookException?) {
                }

            })
    }
  • handleFacebookAccessToken 함수
// facebook 데이터를 firebase에 넘김
    fun handleFacebookAccessToken(token : AccessToken?) {
        var credential = FacebookAuthProvider.getCredential(token?.token!!)
        auth?.signInWithCredential(credential)
            ?.addOnCompleteListener {
                    task ->
                if(task.isSuccessful) {
                    // Third step
                    // Login, 아이디와 패스워드가 맞았을 때
//                    Toast.makeText(this,  "success", Toast.LENGTH_LONG).show()
                    moveMainPage(task.result?.user)
                } else {
                    // Show the error message, 아이디와 패스워드가 틀렸을 때
                    Toast.makeText(this, task.exception?.message, Toast.LENGTH_LONG).show()
                }
            }
    }

전체 소스 코드

package org.techtown.howlstagram_f16

import android.app.Activity
import android.content.ContentValues.TAG
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import com.google.android.gms.auth.api.Auth
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.auth.GoogleAuthProvider
import kotlinx.android.synthetic.main.activity_login.*
import android.content.pm.PackageManager

import android.content.pm.PackageInfo
import android.util.Base64
import android.util.Log
import com.facebook.AccessToken
import com.facebook.CallbackManager
import com.facebook.FacebookCallback
import com.facebook.FacebookException
import com.facebook.login.LoginManager
import com.facebook.login.LoginResult
import com.google.firebase.auth.FacebookAuthProvider
import java.lang.Exception
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.*


class LoginActivity : AppCompatActivity() {
   // firebase 인증을 위한 변수
   var auth : FirebaseAuth? = null
   // 구글 로그인 연동에 필요한 변수
   var googleSignInClient : GoogleSignInClient? = null
   var GOOGLE_LOGIN_CODE = 9001
   // 페이스북 로그인 결과를 가져오는 callbackManager
   var callbackManager : CallbackManager? = null

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_login)

       auth = FirebaseAuth.getInstance()
       email_login_button.setOnClickListener {
           signinAndSignup()
       }
       google_sign_in_button.setOnClickListener {
           //First step
           googleLogin()
       }
       facebook_login_button.setOnClickListener {
           // First step
           facebookLogin()
       }
       // 사용자 ID와 프로필 정보를 요청하기 위해 gso를 인자로 전달해서 GoogleSignInClient 객체 생성
       var gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
           .requestIdToken(getString(R.string.default_web_client_id))
           .requestEmail()
           .build()
       googleSignInClient = GoogleSignIn.getClient(this, gso)

//        printHashKey()       // 해시 키 가져오는 함수

       // 로그인 응답을 처리할 CallbackManager
       callbackManager = CallbackManager.Factory.create()
   }

   fun printHashKey() {
       try {
           val info: PackageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
           for (signature in info.signatures) {
               val md: MessageDigest = MessageDigest.getInstance("SHA")
               md.update(signature.toByteArray())
               val hashKey: String = String(Base64.encode(md.digest(), 0))
               Log.i("TAG", "printHashKey() Hash Key: $hashKey")
           }
       } catch (e: NoSuchAlgorithmException) {
           Log.e("TAG", "printHashKey()", e)
       } catch (e: Exception) {
           Log.e("TAG", "printHashKey()", e)
       }
   }

   // googleSignInClient를 signInIntent 메소드를 통해서 signInIntent를 만들고, startActivityForResult에 전달
   // 새 액티비티를 열고, 결과 값 전달 => onActivityResult()가 결과 값 받음
   // 사용자가 signIn에 성공하면 onActivityResult() 실행
   fun googleLogin() {
       var signInIntent = googleSignInClient?.signInIntent
       startActivityForResult(signInIntent, GOOGLE_LOGIN_CODE)
   }

   fun facebookLogin() {
       // 페이스북에서 받을 권한 요청 - 프로필 이미지, 이메일
       LoginManager.getInstance()
           .logInWithReadPermissions(this, Arrays.asList("public_profile", "email"))
       // LoginResult : 페이스북 로그인이 최종 성공했을 때 넘어오는 부분
       LoginManager.getInstance()
           .registerCallback(callbackManager, object : FacebookCallback<LoginResult>{
               override fun onSuccess(result: LoginResult?) {
                   // Second step
                   // 로그인이 성공하면 페이스북 데이터를 파이어베이스에 넘기는 함수
                   handleFacebookAccessToken(result?.accessToken)
               }

               override fun onCancel() {
               }

               override fun onError(error: FacebookException?) {
               }

           })
   }
   // facebook 데이터를 firebase에 넘김
   fun handleFacebookAccessToken(token : AccessToken?) {
       var credential = FacebookAuthProvider.getCredential(token?.token!!)
       auth?.signInWithCredential(credential)
           ?.addOnCompleteListener {
                   task ->
               if(task.isSuccessful) {
                   // Third step
                   // Login, 아이디와 패스워드가 맞았을 때
//                    Toast.makeText(this,  "success", Toast.LENGTH_LONG).show()
                   moveMainPage(task.result?.user)
               } else {
                   // Show the error message, 아이디와 패스워드가 틀렸을 때
                   Toast.makeText(this, task.exception?.message, Toast.LENGTH_LONG).show()
               }
           }
   }

   // requestCode == 구글 로그인 코드
   // result에 구글에 로그인했을 때 구글에서 넘겨주는 결과 값 저장
   // result가 성공하면 firebaseAuthWithGoogle()에 결과 아이디 넘겨줌
   override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
       super.onActivityResult(requestCode, resultCode, data)
       // 로그인 결과를 callbackManager를 통해 loginManager에게 전달
       callbackManager?.onActivityResult(requestCode, resultCode, data)
       if(requestCode == GOOGLE_LOGIN_CODE) {
           var result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
           // result가 성공했을 때 이 값을 firebase에 넘겨주기
           if(result!!.isSuccess) {
               var account = result.signInAccount
               // Second step
               firebaseAuthWithGoogle(account)
           }
       }
   }
   // account에서 id 토큰을 가져와서 firebase 사용자 인증 정보로 교환해야 함 => signInWithCredential()
   fun firebaseAuthWithGoogle(account : GoogleSignInAccount?) {
       var credential = GoogleAuthProvider.getCredential(account?.idToken,null)
       auth?.signInWithCredential(credential)
           ?.addOnCompleteListener {
                   task ->
               if(task.isSuccessful) {
                   // Login, 아이디와 패스워드가 맞았을 때
//                    Toast.makeText(this,  "success", Toast.LENGTH_LONG).show()
                   moveMainPage(task.result?.user)
               } else {
                   // Show the error message, 아이디와 패스워드가 틀렸을 때
                   Toast.makeText(this, task.exception?.message, Toast.LENGTH_LONG).show()
               }
           }
   }
   // email과 password를 받아오고 addOnCompleteListener로 성공 유무의 값을 받아 성공하면 메인페이지로 이동
   fun signinAndSignup() {
       auth?.createUserWithEmailAndPassword(email_edittext.text.toString(),password_edittext.text.toString())
           ?.addOnCompleteListener {
           task ->
               if(task.isSuccessful) {
                   // Creating a user account
                   moveMainPage(task.result?.user)
               } else if(task.exception?.message.isNullOrEmpty()) {
                   // Show the error message
                   Toast.makeText(this, task.exception?.message, Toast.LENGTH_LONG).show()
               } else {
                   // Login if you have account
                   signinEmail()
               }
       }
   }
   fun signinEmail() {
       auth?.signInWithEmailAndPassword(email_edittext.text.toString(),password_edittext.text.toString())
           ?.addOnCompleteListener {
                   task ->
               if(task.isSuccessful) {
                   // Login, 아이디와 패스워드가 맞았을 때
                   moveMainPage(task.result?.user)
               } else {
                   // Show the error message, 아이디와 패스워드가 틀렸을 때
                   Toast.makeText(this, task.exception?.message, Toast.LENGTH_LONG).show()
               }
           }
   }
   // 로그인이 성공하면 다음 페이지로 넘어가는 함수
   fun moveMainPage(user:FirebaseUser?) {
       // 파이어베이스 유저 상태가 있을 경우 다음 페이지로 넘어갈 수 있음
       if(user != null) {
           startActivity(Intent(this, MainActivity::class.java))
       }
   }
}

결과 및 에러 해결

🆘 For your account security, logging into Facebook from an embedded browser is disabled. You may be able to continue by updating the app you're logging in from and trying again.

implementation 'com.facebook.android:facebook-android-sdk:[8,9)'
  • 그리고 실행했더니 잘 된다!

profile
람차람차

0개의 댓글

관련 채용 정보