안드로이드 개발/코틀린

[Kotlin] 파이어베이스 기반 전화번호 로그인

얌자 2021. 8. 6. 10:39

1. 파이어 베이스 연동 작업

 

  1. 파이어 베이스 홈페이지에서 프로젝트를 추가한 후에 앱과 연동 작업을 진행했습니다.

패키지 명을 앱 단위 build.gradle에서 불러와 입력하였습니다.

sha-1는 나중에 다시 설정 해 줄 수 있습니다.

 

 

 

 

2. vitameansHospital 앱 내의 폴더 안에 google-services.json 파일을 넣어줍니다.

 

 

 

3. 프로젝트 수준의 build.gradle (<project>/build.gradle): 에 해당 코드를 입력해줍니다.

 

 

 

buildscript {
  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }
  dependencies {
    ...
    // Add this line
    classpath 'com.google.gms:google-services:4.3.8'
  }
}

allprojects {
  ...
  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    ...
  }
}

 

 

4. 앱 수준의 build.gradle (<project>/<app-module>/build.gradle): 에 해당 코드를 입력해줍니다.

 

apply plugin: 'com.android.application'
// Add this line
apply plugin: 'com.google.gms.google-services'

dependencies {
  // Import the Firebase BoM
  implementation platform('com.google.firebase:firebase-bom:28.1.0')

  // Add the dependency for the Firebase SDK for Google Analytics
  // When using the BoM, don't specify versions in Firebase dependencies
  implementation 'com.google.firebase:firebase-analytics-ktx'

  // Add the dependencies for any other desired Firebase products
  // https://firebase.google.com/docs/android/setup#available-libraries
}

 

 

 

2. SHA-1인증서 지문 등록

전화번호 로그인 구현을 위해서는 SHA-1 키가 있어야 전화번호 인증이 가능합니다.

 

 

1. cmd 창을 키고 C:\Users\%username%\.android로 이동해줍니다.

 

 

2. keytool -list -v -keystore debug.keystore 를 입력해줍니다.

 

sha-1 같은 경우 비밀번호를 필요치 않아서 enter를 누르시면 넘어가집니다.

저 같은 경우 java가 깔려 있지 않았어서 key값이 존재하지 않았습니다. (덕분에 2시간 정도의 삽질 …)

 

 

**자바가 깔려 있지 않은 경우 **

  1. 자바를 다운로드한다.
  2. cmd 내에서 C:\Program Files (x86)\Java\jre1.8.0_291\bin 로 이동해준다.
  3. keytool -list -v -keystore "C:\Users\yumjj.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android 를 입력해준다.

파이어베이스 홈페이지 콘솔 내 프로젝트 설정에서 SHA 인증서 지문을 등록해주면 완료입니다.

 

 

 


사전 준비는 끝나고 직접 구현에 들어가겠습니다.

 

1.전화번호 인증 페이지 ui 제작

해당 페이지에서 번호 인증이 이루어집니다.

 

 

 

activity_phonenumber.xml

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <ImageView
        android:id="@+id/iv_back"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_margin="5dp"
        android:src="@drawable/ic_back"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>
    <TextView
        android:id="@+id/tv_phone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="전화번호 인증"
        android:fontFamily="@font/spoqa_han_sans_neo_bold"
        android:textSize="25dp"
        android:textColor="@color/black"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="30dp"
        app:layout_constraintTop_toBottomOf="@+id/iv_back"
        app:layout_constraintLeft_toLeftOf="parent"/>
    <EditText
        android:id="@+id/et_phone_sign"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="140dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="120dp"
        android:hint="전화번호를 입력해주세요"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/tv_phone" />

    <Button
        android:id="@+id/btn_certification"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="137dp"
        android:backgroundTint="@color/grey50Light"
        android:text="인증요청"
        android:textColor="@color/browser_actions_title_color"
        app:layout_constraintLeft_toRightOf="@id/et_phone_sign"
        app:layout_constraintTop_toTopOf="@id/tv_phone" />

    <EditText
        android:id="@+id/et_phone_certification"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="80dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:hint="인증 번호 입력"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/et_phone_sign" />
    <Button
        android:id="@+id/btn_certification_check"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="80dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:textColor="@color/black"
        android:text="인증하기"
        android:backgroundTint="@color/grey300"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/et_phone_certification"/>
</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

2.전화번호 인증 기능 구현

 

로직

 

startPhoneNumberVerification으로 인증번호 발송 PhoneAuthProvider.OnVerificationStateChangedCallbacks() 내의 onCodeSent 에서 인증 번호 및 토큰 값 획득

val credential = PhoneAuthProvider.getCredential(verificationId!!, code)onCodeSent 에서 받은 인증 번호와 전화번호를 통해 받은 인증 코드를 각각 입력하여 객체 생성

signInWithPhoneAuthCredential(credential: PhoneAuthCredential)에 위에서 만든 객체 입력하면 로그인 끝

 

 

 

1. 모듈(앱 수준) Gradle 파일(일반적으로 app/build.gradle)에서 Firebase 인증 Android 라이브러리의 종속 항목을 선언합니다.

 

dependencies {
    // Import the BoM for the Firebase platform
    implementation platform('com.google.firebase:firebase-bom:28.0.1')

    // 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-ktx'
}

 

 

2. 사용자 전화로 인증 코드 전송

 

PhoneAuthProvider.verifyPhoneNumber 메서드에 전화번호를 전달하여 Firebase가 사용자의 전화번호를 확인하도록 요청합니다.

 

val options = PhoneAuthOptions.newBuilder(auth)
    .setPhoneNumber(phoneNumber)       // Phone number to verify
    .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
    .setActivity(this)                 // Activity (for callback binding)
    .setCallbacks(callbacks)          // OnVerificationStateChangedCallbacks
    .build()
PhoneAuthProvider.verifyPhoneNumber(options)

 

PhoneAuthProvider.verifyPhoneNumber를 호출할 때는 요청 결과를 처리하는 콜백 함수의 구현을 포함하는 OnVerificationStateChangedCallbacks의 인스턴스도 제공해야 합니다. 예를 들면 다음과 같습니다.

 

 

private var callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

    override fun onVerificationCompleted(credential: PhoneAuthCredential) {

        signInWithPhoneAuthCredential(credential)
    }

    override fun onVerificationFailed(e: FirebaseException) {

        if (e is FirebaseAuthInvalidCredentialsException) {
            // Invalid request
        } else if (e is FirebaseTooManyRequestsException) {
            // The SMS quota for the project has been exceeded
        }

    }

    override fun onCodeSent(
        verificationId: String,
        token: PhoneAuthProvider.ForceResendingToken
    ) {
        storedVerificationId = verificationId
        resendToken = token
    }
}

 

 

3. PhoneAuthCredential 객체 만들기

사용자가 Firebase에서 사용자의 전화로 보낸 인증 코드를 입력하면 인증 코드 및 onCodeSent 또는 onCodeAutoRetrievalTimeOut 콜백에 전달된 인증 ID를 사용하여 PhoneAuthCredential 객체를 만듭니다.

PhoneAuthCredential 객체를 만들려면 다음과 같이 PhoneAuthProvider.getCredential을 호출합니다.

 

val credential = PhoneAuthProvider.getCredential(verificationId!!, code)

 

 

 

4. 사용자 로그인

 

 

onVerificationCompleted 콜백 또는 PhoneAuthProvider.getCredential 호출을 통해 PhoneAuthCredential 객체를 가져온 후 FirebaseAuth.signInWithCredential에 PhoneAuthCredential 객체를 전달하여 로그인 과정을 완료합니다.

 

private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
    auth.signInWithCredential(credential)
        .addOnCompleteListener(this) { task ->
            if (task.isSuccessful) {
                // Sign in success, update UI with the signed-in user's information
                Log.d(ContentValues.TAG, "signInWithCredential:success")
                val user = task.result?.user
                startActivity(Intent(this, MainAct::class.java))
            } else {
                // Sign in failed, display a message and update the UI
                Log.w(ContentValues.TAG, "signInWithCredential:failure", task.exception)
                if (task.exception is FirebaseAuthInvalidCredentialsException) {

                }
                // Update UI
            }
        }
}

 

 

phoneNumberAct.kt 전체코드

 

package com.example.vitameanshospital.login

import android.content.ContentValues
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.vitameanshospital.MainAct
import com.example.vitameanshospital.R
import com.google.firebase.FirebaseException
import com.google.firebase.FirebaseTooManyRequestsException
import com.google.firebase.auth.*
import com.google.firebase.auth.ktx.auth
import com.google.firebase.ktx.Firebase
import kotlinx.android.synthetic.main.activity_hospital.*
import kotlinx.android.synthetic.main.activity_phonenumber.*
import java.util.concurrent.TimeUnit

class PhoneNumberAct:AppCompatActivity() {

    private lateinit var auth: FirebaseAuth

    private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken

    private var callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

        override fun onVerificationCompleted(credential: PhoneAuthCredential) {

            signInWithPhoneAuthCredential(credential)
        }

        override fun onVerificationFailed(e: FirebaseException) {

            if (e is FirebaseAuthInvalidCredentialsException) {
                // Invalid request
            } else if (e is FirebaseTooManyRequestsException) {
                // The SMS quota for the project has been exceeded
            }

        }

        override fun onCodeSent(
            verificationId: String,
            token: PhoneAuthProvider.ForceResendingToken
        ) {
            storedVerificationId = verificationId
            resendToken = token
        }
    }


    private var storedVerificationId: String? = ""

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

        auth = Firebase.auth

        iv_back.setOnClickListener {
            finish()
        }

        btn_certification.setOnClickListener {

            val phoneNumber =et_phone_sign.text.toString()
            if(phoneNumber==null){
                Toast.makeText(applicationContext, "전화번호를 입력해주세요", Toast.LENGTH_SHORT).show()
            }
            else{
                startPhoneNumberVerification(phoneNumber)
            }

        }

        btn_certification_check.setOnClickListener {
            val certificationCode = et_phone_certification.text.toString()
            verifyPhoneNumberWithCode(storedVerificationId,certificationCode)

        }
    }

    override fun onStart() {
        super.onStart()
        // Check if user is signed in (non-null) and update UI accordingly.
        val currentUser = auth.currentUser

    }


    private fun startPhoneNumberVerification(phoneNumber: String) {
        // [START start_phone_auth]
        val options = PhoneAuthOptions.newBuilder(auth)
            .setPhoneNumber(phoneNumber)       // Phone number to verify
            .setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
            .setActivity(this)                 // Activity (for callback binding)
            .setCallbacks(callbacks)          // OnVerificationStateChangedCallbacks
            .build()
        PhoneAuthProvider.verifyPhoneNumber(options)
        // [END start_phone_auth]
    }


    private fun verifyPhoneNumberWithCode(verificationId: String?, code: String) {

        val credential = PhoneAuthProvider.getCredential(verificationId!!, code)
        signInWithPhoneAuthCredential(credential)
    }

    private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
        auth.signInWithCredential(credential)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(ContentValues.TAG, "signInWithCredential:success")
                    val user = task.result?.user
                    startActivity(Intent(this, MainAct::class.java))
                } else {
                    // Sign in failed, display a message and update the UI
                    Log.w(ContentValues.TAG, "signInWithCredential:failure", task.exception)
                    if (task.exception is FirebaseAuthInvalidCredentialsException) {

                    }
                    // Update UI
                }
            }
    }



}