Today's

길을 나서지 않으면 그 길에서 만날 수 있는 사람을 만날 수 없다

모바일 앱(안드로이드)

안드로이드 앱 만들기 : 소셜 로그인#2 (facebook 로그인)

Billcorea 2023. 2. 13. 11:43
반응형

소셜로그인

지난번 이야기는 미리 보고 오시면 도움이 됩니다.

 

https://billcorea.tistory.com/308

 

안드로이드 앱 만들기 : 소셜 로그인 ( 네이버, 카카오톡, 구글) 구현해 보기

소셜로그인 요새는 대부분의 사용자들이 이런저런 SNS 등에 가입이 되어 있기 때문에 또 다른 개인정보를 제공해 가면서 로그인을 하려고 하지 않습니다. 또한 각각에 등록된 비밀번호를 기억하

billcorea.tistory.com

 

Facebook Login

이번에는 Facebook으로 firebase에 로그인하는 과정을 만들어 보겠습니다. 

facebook_03.svg
0.01MB

이미지 버튼 아이콘을 만들기 위한 svg 이미지 입니다.  다른 방법도 있기는 하겠지만, 저는 이미지 버튼으로 구현을 할 생각이기 때문에 간단한 이미지를 만들어 보았습니다. 

 

facebook 로그인을 하려면 해야할 일이 먼저 facebook 개발자 계정을 만들어야 하고 해당 계정에 필요한 앱을 등록해야 합니다.   아래 그림과 같이 facebook 개발자 페이지에서 등록한 앱의 정보와 firebase 인증 설정에서 연결해야 하는 부분을 기술해 보았으니 참고해 보세요.

 

개발자 페이지 연결정보

Facebook 개발자페이지 앱정보

설정 - 기본설정 에서 앱 ID 와 앱 시크릿코드 가 있어야 firebase 인증 정보에 등록을 할 수 있습니다. 

 

Firebase Authentication 정보

sign-in method 에서 facebook을 선택하고 등록하는 창을 열어서 OAuth 리다이렉션 URI을 복사해서 facebook 개발자 페이지의 Facebook 로그인 설정의 유효한 OAuth 리다이렉션 URI에 붙여 넣기를 해 주어야 합니다.

 

여기까지가 해야 개발자 페이지 및 인증 설정이 마무리 됩니다.

 

이제 만들던 android 앱을 구현해 보겠습니다. 

 

gradle 파일에는 아래와 같이 추가되어 있어야 합니다.

    // firebase 연동 처리용
    implementation platform('com.google.firebase:firebase-bom:31.1.1')
    implementation 'com.google.firebase:firebase-auth-ktx:21.1.0'
    
    //facebook login
    implementation 'com.facebook.android:facebook-login:15.0.0'

 

다음은 manifest 파일을 살펴보겠습니다.   facebook 개발자 페이지의 가이드에 따라 아래와 같이 구성이 되어야 합니다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    // facebook
    <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>

	// facebook
    <queries>
        <provider android:authorities="com.facebook.katana.provider.PlatformProvider" />
    </queries>

    <application
        android:name=".viewModel.MyApplication"
       ...
        tools:targetApi="31">

		// facebook
        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>


        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:theme="@style/Theme.RemotePayment0119">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

		// facebook 
        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges=
                "keyboard|keyboardHidden|screenLayout|screenSize|orientation" />
        <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>

    </application>

</manifest>

 

이제 acitivity의 구현을 따라가 보겠습니다. 


import android.app.Activity
...

class MainActivity : ComponentActivity() {

    ...

    private val TAG = "---"

	// facebook
    val callbackManager = CallbackManager.Factory.create()
    val loginManager = LoginManager.getInstance()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ...

        setContent {

            val scrollableState = rememberScrollState()

            RemotePayment0119Theme {
                // A surface container using the 'background' color from the theme
                Column(
                    modifier = Modifier
                        .fillMaxSize()
                        .padding(30.dp)
                        .verticalScroll(scrollableState),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.Center
                ) {
                    DestinationsNavHost(navGraph = NavGraphs.root) {
                        ...
                        composable(LoginOptionsDestination) {
                            LoginOptions(
                                ...
                                doFacebookLogin = {
                                    doFacebookLogin()
                                },
                                ...
                            )
                        }
                    }
                }
            }
        }
    }

    private fun doFacebookLogin() {
        loginManager.logIn(this@MainActivity, callbackManager, listOf("email", "public_profile","openid"))
        loginManager.registerCallback(callbackManager, object : FacebookCallback<LoginResult> {
            override fun onCancel() {
                Log.e("", "onCancel")
                loginManager.logOut()
            }

            override fun onError(error: FacebookException) {
                Log.e("", "error=${error.localizedMessage}")
            }

            override fun onSuccess(result: LoginResult) {
                Log.e("", "accessToken Removed authToken=${result.authenticationToken}")
                handleFacebookAccessToken(result.accessToken)
            }
        })

    }

    private fun handleFacebookAccessToken(token: AccessToken) {
        Log.e(TAG, "handleFacebookAccessToken:$token")

        val credential = FacebookAuthProvider.getCredential(token.token)
        auth.signInWithCredential(credential)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.e(TAG, "signInWithCredential:success")
                    val user = auth.currentUser
//                    updateUI(user)
                } else {
                    // If sign in fails, display a message to the user.
                    Log.e(TAG, "signInWithCredential:failure", task.exception)
                    Toast.makeText(baseContext, "Authentication failed.",
                        Toast.LENGTH_SHORT).show()
//                    updateUI(null)
                }
            }
    }


    ...

    fun printHashKey(context: Context): String {

        val TAG = "HASH_KEY"
        var hashKey : String? = null
        try {
            val info : PackageInfo = context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES)
            for (signature in info.signatures) {
                var md : MessageDigest = MessageDigest.getInstance("SHA")
                md.update(signature.toByteArray())
                hashKey = String(Base64.encode(md.digest(), 0))
                Log.e(TAG, "hashKey=$hashKey")
            }

        } catch (e:Exception){
            Log.e(TAG, e.toString())
        }

        return "$hashKey"

    }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    RemotePayment0119Theme {
        DestinationsNavHost(navGraph = NavGraphs.root)
    }
}

callBackmanager을 선언한 다음,  loginManager에 callback을 등록해 줍니다. 다음은 loginManager에서 callback 이 돌아왔을 때 처리할 부분을 등록해 주면 됩니다. 

 

handleFacebookAccessToken 함수는 firebase 개발자 가이드에서 설명하고 있는 부분입니다. 저 함수를 호출하는 것으로 firebase에 로그인은 바로 처리됩니다. 이미 등록된 이메일이라면 로그인이 되고 그렇지 않은 경우는 자동으로 사용자 등록을 해 줍니다. 

 

주의할 점

  • facebook에서 돌아오는 accessToken 은 logger cat에 표시되지 않습니다. 로그를 찍어 보면 AccessToken Removed라고 표시되기 때문에 초심자의 경우 헤맬 수 있습니다. 
  • handleFacebookAccessToken 함수에서는 facebook 계정의 이메일을 이용하기 때문에 다른 방법으로 이미 동일한 이메일이 등록되어 있다면 사용할 수 없습니다. 구글 로그인이나, 이메일 로그인을 통해서 이미 가입된 이메일 여부를 확인해 주어야 합니다. 
  • 인증에 대한 부분만 기술하였기 때문에 회원 등록등을 하기 위해서는 정보 수집에 관한 구현은 따로 진행되어야 합니다. 
  • 기능 사용을 위해서는. Facebook 개발자 계정에서 해당 앱에 대한 인증을 진행해야 합니다.

 

이 두 가지만 주의한다면 허송세월하는 일 없이 구현을 해 볼 수 있을 것 같습니다.  카카오나 네이버를 통한 로그인 계정 구현처럼 서버 리스를 구현하지 않아도 되니 구글 로그인 보다 더 수월하게 해 볼 수 있습니다. 

 

 

 

로그인 예시

 

이제 Facebook 계정을 통한 로그인이 해 볼 수 있겠습니다.

 

 

전체 소스는 아래 github 에서 참고 하세요.

https://github.com/nari4169/RemotePayment0119

 

반응형