소개팅 앱 2. 회원 가입 및 로그인 구현하기

변현섭·2023년 8월 22일
0

지난 포스팅에 이어서 소개팅 앱을 계속해서 만들어보도록 하겠습니다. 이번 포스팅에서는 회원 가입 및 로그인 기능을 추가해보도록 하겠습니다.

1. 회원 가입 레이아웃 구성하기

① Java를 사용할 때와 마찬가지로, Kotlin을 사용할 때에도 Activity들을 패키지로 묶어 관리하는게 좋다.

② default 패키지 하위로 auth 패키지를 생성한 후 IntroActivity를 그 안에 넣는다. 또한 auth 패키지 하위로 JoinActivity를 추가한다.

③ IntroActivity에서 회원 가입 버튼을 눌렀을 때, JoinActivity로 화면이 전환될 수 있도록 아래의 내용을 IntroActivity에 입력한다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_intro)
    val joinBtn = findViewById<Button>(R.id.join)
    joinBtn.setOnClickListener {
        val intent = Intent(this, JoinActivity::class.java)
        startActivity(intent)
    }
}

④ activity_join.xml 파일에서 회원가입 화면의 레이아웃을 구성하자. ConstraintLayout의 배경도 같은 이미지로 설정하고, LinearLayout 컨테이너를 추가한다.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <ImageView
    	android:id="@+id/profile"
        android:src="@drawable/profile"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_margin="30dp"/>
</LinearLayout>

⑤ 사용자의 입력을 받기 위해 기존에는 EditText 태그를 사용했지만, 이번에는 TextInputLayout을 사용해보기로 하겠다. 앞서 작성한 LinearLayout 컨테이너 안에 계속해서 작성하면 된다.

  • 선택된 입력창을 초록색으로 나타내주고, 유효하지 않은 입력을 받은 입력창을 빨간색으로 나타내준다.
  • counterEnabled: 사용자 입력 텍스트의 글자 수를 counting한다.
  • counterMaxLength: 사용자 입력 텍스트의 최대 글자 수를 제한한다.
<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/email"
        android:hint="email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    app:counterMaxLength="12"
    app:counterEnabled="true">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/password"
        android:hint="password"
        android:inputType="textPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

⑥ 이메일과 패스워드에 이어 닉네임, 성별, 지역, 나이도 추가해주자.

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/nickname"
        android:hint="닉네임"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/gender"
        android:hint="성별"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/region"
        android:hint="지역"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/age"
        android:hint="나이"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

⑦ LinearLayout 컨테이너의 마지막 부분에 회원 가입 버튼을 추가하자.

<Button
	android:id="@+id/join"
    android:text="회원가입"
    android:layout_margin="10dp"
    android:background="@color/pink"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

⑧ LinearLayout 컨테이너 전체를 ScrollView 컨테이너로 감싼다.

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <LinearLayout
    ...
    </LinearLayout>
    
</ScrollView>
  • ScrollView를 적용하지 않으면, 아래와 같이 키보드 자판이 지역과 나이 입력칸을 가렸을 때, Back 버튼으로 키보드를 없애주어야만 다음 입력창에 입력할 수 있게 된다.
  • 그러나 ScrollView를 적용하면, 키보드가 떠있는 상태에서 화면을 스크롤하는 것만으로 다음 입력창에 입력할 수 있다.

⑨ 코드를 실행시켜 스크롤이 잘 적용되었는지 확인해보자.

2. 회원가입 구현하기

① JoinActivity 파일의 onCreate 메서드 안에 아래의 내용을 추가한다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_join)
    val joinBtn = findViewById<Button>(R.id.join)
    joinBtn.setOnClickListener {
        val email = findViewById<TextInputEditText>(R.id.email)
        val password = findViewById<TextInputEditText>(R.id.password)
    }
}

② 파이어베이스 콘솔에 접속하여 dating-app이라는 이름의 프로젝트를 생성한다. 파이어베이스 관련 설정을 진행한다. 자세한 내용은 아래의 링크를 참조하기 바란다.
>> 파이어베이스 관련 설정

  • Project 수준, Module 수준의 build.gradle 파일의 pugin을 추가한다.
  • 이메일/비밀번호 로그인 사용 설정 토글을 ON으로 변경하면 된다.
  • 파이어베이스 관련 의존성과 사용자 인증을 위한 의존성을 추가한다.
implementation(platform("com.google.firebase:firebase-bom:32.2.2"))
implementation("com.google.firebase:firebase-analytics-ktx")
implementation("com.google.firebase:firebase-auth-ktx")

③ JoinActivity 파일을 아래와 같이 수정한다.

private lateinit var auth: FirebaseAuth

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_join)
    
    auth = Firebase.auth
    val joinBtn = findViewById<Button>(R.id.join)
    joinBtn.setOnClickListener {
        val email = findViewById<TextInputEditText>(R.id.email)
        val password = findViewById<TextInputEditText>(R.id.password)
        auth.createUserWithEmailAndPassword(email.text.toString(), password.text.toString())
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    Log.d("JoinActivity", "회원가입 완료")
                    
                    val intent = Intent(this, MainActivity::class.java)
                    startActivity(intent)
                } else {
                    Log.d("JoinActivity", "회원가입 실패")
                }
            }
    }
}

④ 이제 코드를 실행시켜보자. 이메일과 비밀번호를 입력한 상태에서 회원가입 버튼을 클릭하면 파이어베이스에 사용자 등록이 완료되고, MainActivity로 화면이 전환된다.

  • 참고로 비밀번호는 반드시 6자 이상이어야 한다.

3. 자동 로그인 구현하기

① 사용자의 등록 여부에 따라 스플래시 화면에서 MainActivity 또는 IntroActivity로 화면 전환이 이루어질 수 있도록 SplashActivity를 아래와 같이 수정한다.

private lateinit var auth: FirebaseAuth

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_splash)
    auth = Firebase.auth
    val uid = auth.currentUser?.uid.toString()
    
    if(uid == null) {
        Handler().postDelayed({
            startActivity(Intent(this, IntroActivity::class.java))
            finish()
        }, 3000)
    }
    
    else {
        Handler().postDelayed({
            startActivity(Intent(this, MainActivity::class.java))
            finish()
        }, 3000)
    }
}

② 파이어베이스의 uid가 필요한 상황이 많기 때문에, uid를 가져오는 메서드를 정의하는 Class를 만드는 것이 좋다.

  • default 패키지 하위로 utils 패키지를 추가한다.
  • utils 패키지 하위로 FirebaseAuthUtils라는 이름의 Kotlin Class를 추가한다.

③ FirebaseAuthUtils 클래스에 아래의 내용을 입력한다.

companion object {
    private lateinit var auth : FirebaseAuth
    fun getUid() : String {
        auth = Firebase.auth
        return auth.currentUser?.uid.toString()
    }
}
  • companion object는 클래스 내부에 정의되는 싱글톤 객체로, 인스턴스 생성 없이 바로 접근이 가능하다.
  • 즉, Java에서의 static과 유사한 역할을 한다.

④ 이제 조금 더 편리한 방법으로 사용자의 uid 값을 받아올 수 있게 되었다. SplashActivity의 코드를 아래와 같이 수정하자.

// private lateinit var auth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_splash)
    // auth = Firebase.auth
    // val uid = auth.currentUser?.uid.toString()
    val uid = FirebaseAuthUtils.getUid()

4. 로그인 & 로그아웃 구현하기

1) 로그아웃 구현하기

① 먼저 로그아웃 아이콘을 drawable 디렉토리에 넣어주자.

② CardStackView 태그 속성으로 아래의 내용을 추가한다.

android:layout_marginTop="60dp"

③ activity_main.xml 파일에 ConstraintLayout 컨테이너를 추가한다.

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="60dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">
    <ImageView
    	android:id="@+id/logout"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_margin="3dp"
        android:src="@drawable/logout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

④ MainActivity의 onCreate 메서드에 아래의 내용을 추가한다.

super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val logoutBtn = findViewById<ImageView>(R.id.logout)
logoutBtn.setOnClickListener {
    Firebase.auth.signOut()
    
    val intent = Intent(this, IntroActivity::class.java)
    startActivity(intent)
}

2) 로그인 구현하기

① auth 디렉토리 하위로 LoginActivity를 생성한다.

② activity_login.xml 파일의 레이아웃을 LinearLayout으로 변경하고 배경 이미지를 지정한다.

<LinearLayout
	android:background="@drawable/date"
    android:orientation="vertical"

③ activity_join.xml 파일에서 사용했던 이메일과 비밀번호 입력창을 가져와 LinearLayout 컨테이너 안에 붙여 넣는다.

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="200dp"
	android:layout_marginHorizontal="10dp">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/email"
        android:hint="email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    app:counterMaxLength="12"
    app:counterEnabled="true">
    
    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/password"
        android:hint="password"
        android:inputType="textPassword"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
        
</com.google.android.material.textfield.TextInputLayout>

④ 로그인 버튼도 추가해주자.

<Button
    android:id="@+id/login"
    android:text="로그인"
    android:layout_marginTop="50dp"
	android:layout_marginHorizontal="10dp"
    android:background="@color/pink"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

⑤ IntroActivity 파일에서 로그인 버튼에 대한 클릭 이벤트 리스너를 등록하자.

val loginBtn = findViewById<Button>(R.id.login)
loginBtn.setOnClickListener {
    val intent = Intent(this, LoginActivity::class.java)
    startActivity(intent)
}

⑥ LoginActivity 파일에 기존 사용자 로그인 로직을 아래와 같이 추가한다.

private lateinit var auth : FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_login)
    auth = Firebase.auth
    val loginBtn = findViewById<Button>(R.id.login)
    loginBtn.setOnClickListener {
        val email = findViewById<TextInputEditText>(R.id.email)
        val password = findViewById<TextInputEditText>(R.id.password)
        auth.signInWithEmailAndPassword(email.text.toString(), password.text.toString())
            .addOnCompleteListener(this) { task ->
                if(task.isSuccessful) {
                    val intent = Intent(this, MainActivity::class.java)
                    startActivity(intent)
                }
                else {
                    Toast.makeText(this, "로그인 정보를 확인해주세요", Toast.LENGTH_SHORT).show()
                }
            }
    }
}

⑦ 코드를 실행시켜보면, 로그인이 정상적으로 진행되는 것을 확인할 수 있다.

profile
Java Spring, Android Kotlin, Node.js, ML/DL 개발을 공부하는 인하대학교 정보통신공학과 학생입니다.

0개의 댓글