지난 포스팅에 이어서 소개팅 앱을 계속해서 만들어보도록 하겠습니다. 이번 포스팅에서는 회원 가입 및 로그인 기능을 추가해보도록 하겠습니다.
① 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 컨테이너 안에 계속해서 작성하면 된다.
<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>
⑨ 코드를 실행시켜 스크롤이 잘 적용되었는지 확인해보자.
① 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이라는 이름의 프로젝트를 생성한다. 파이어베이스 관련 설정을 진행한다. 자세한 내용은 아래의 링크를 참조하기 바란다.
>> 파이어베이스 관련 설정
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로 화면이 전환된다.
① 사용자의 등록 여부에 따라 스플래시 화면에서 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를 만드는 것이 좋다.
③ FirebaseAuthUtils 클래스에 아래의 내용을 입력한다.
companion object {
private lateinit var auth : FirebaseAuth
fun getUid() : String {
auth = Firebase.auth
return auth.currentUser?.uid.toString()
}
}
④ 이제 조금 더 편리한 방법으로 사용자의 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()
① 먼저 로그아웃 아이콘을 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)
}
① 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()
}
}
}
}
⑦ 코드를 실행시켜보면, 로그인이 정상적으로 진행되는 것을 확인할 수 있다.