[안드로이드 스튜디오 - 코틀린] 로그인, 회원가입 구현하기

HAYEON·2023년 8월 5일
0
post-thumbnail

내부db / 로그인 / 회원가입 / 비밀번호 가리기 / 입력 형식 제한 - 정규식 / intent 화면 전환 / SQLite 활용 / SQLiteOpenHelper / hint 사이즈 변경 / 아이디, 닉네임 중복 확인 검사 / 한글 키보드 추가 / 내부 db 파일 전송 / 다른 db 나의 앱에 적용


내부 db를 이용하여 초간단 로그인과 회원가입 페이지을 구현해 보도록 하겠습니다. (구글링하며 찾은 코드를 활용하여, 내가 원하는 형태로 바꾸어 제작함)

SQLite를 이용하여 내부db에 회원 정보를 저장하기 때문에 다른 사람의 컴퓨터/스마트폰에서 앱을 열었을 때는 본인이 회원가입 했던 회원 정보는 남아있지 않습니다.
깃허브로 협업을 할 때에도 마찬가지임을 기억해 주세요.
(만약 본인이 만든 db를 다른 사람에게 전달하고자 한다면 맨 아래쪽 글을 참고해 주세요.)

📌 결과 이미지


📌 로그인, 회원가입 페이지 생성

일단 Empty Views Activity를 통해 프로젝트를 생성합니다.
MainActiviy는 로그인 페이지로 활용하고, RegisterActivity는 따로 생성해서 회원가입 페이지로 만들어 줍니다.

activity_main.xml

코드 상에서 저는 ImageButton을 사용했지만, 원하는 대로 바꿔서 구현하시면 됩니다. (디자인은 다른 팀원분의 디자인입니다.)

📣 참고로 사용자 입력을 받는 EditText에서는 왼쪽과 오른쪽에 padding을 살짝 주어 안쪽 여백이 생기도록 하는 것을 추천합니다.

inputType="textPassword"로 설정하면 비밀번호가 가려진 형태로 입력할 수 있습니다.

<?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"
    android:background="#0E5BDF"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/linearLayout3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="380dp"
        android:orientation="vertical"
        android:paddingLeft="100dp"
        android:paddingRight="100dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <EditText
            android:id="@+id/editTextId"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:backgroundTint="#FFFFFF"
            android:ems="10"
            android:hint="아이디"
            android:inputType="text"
            android:paddingLeft="9dp"
            android:textColor="#FFFFFF"
            android:textColorHint="#8DFFFFFF"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <EditText
            android:id="@+id/editTextPassword"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="11dp"
            android:layout_marginBottom="70dp"
            android:backgroundTint="#FFFFFF"
            android:ems="10"
            android:hint="비밀번호"
            android:inputType="textPassword"
            android:paddingLeft="8dp"
            android:textColor="#FFFFFF"
            android:textColorHint="#8DFFFFFF"
            app:layout_constraintBottom_toTopOf="@+id/btnLogin"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/editTextId" />
    </LinearLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="35dp"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <ImageButton
            android:id="@+id/btnLogin"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_marginBottom="20dp"
            android:layout_gravity="center"
            android:background="#00FF0000"
            app:srcCompat="@drawable/login" />

        <Button
            android:id="@+id/btnRegister"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_gravity="center|bottom"
            android:backgroundTint="#00FF0000"
            android:padding="5dp"
            android:text="회원가입" />
    </FrameLayout>

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_marginTop="100dp"
        android:src="@drawable/ic_launcher_foreground"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

register_main.xml

이 코드에서도 ImageButton을 사용했습니다. 원하는 대로 수정하여 사용할 수 있습니다. 중복 확인 버튼도 배치합니다.

<?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"
    android:background="#0E5BDF"
    tools:context=".RegisterActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="회원가입"
        android:textColor="#FFFFFF"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:layout_width="341dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="40dp"
        android:layout_marginTop="150dp"
        android:layout_marginEnd="40dp"
        android:orientation="vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <TextView
                    android:id="@+id/textView2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="top|left"
                    android:layout_marginBottom="34dp"
                    android:layout_marginLeft="8dp"
                    android:text="아이디"
                    android:textColor="#FFFFFF"
                    android:textSize="18sp" />

                <EditText
                    android:id="@+id/editTextId_Reg"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="8dp"
                    android:backgroundTint="#FFFFFF"
                    android:ems="10"
                    android:layout_gravity="bottom"
                    android:hint="@string/editId_hint"
                    android:inputType="text"
                    android:textColor="#FFFFFF"
                    android:textColorHint="#8DFFFFFF" />

                <Button
                    android:id="@+id/btnCheckId_Reg"
                    android:layout_width="80dp"
                    android:layout_height="30dp"
                    android:layout_gravity="right|top"
                    android:backgroundTint="#FFFFFF"
                    android:text="중복확인"
                    android:textAlignment="center"
                    android:textColor="#1C26FF"
                    android:padding="1dp"
                    android:textSize="12sp"/>
            </FrameLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp"
            android:orientation="horizontal">

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <TextView
                    android:id="@+id/textView3"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="top|left"
                    android:layout_marginBottom="34dp"
                    android:layout_marginLeft="8dp"
                    android:text="비밀번호"
                    android:textColor="#FFFFFF"
                    android:textSize="18sp"  />

                <EditText
                    android:id="@+id/editTextPass_Reg"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="8dp"
                    android:backgroundTint="#FFFFFF"
                    android:ems="10"
                    android:layout_gravity="bottom"
                    android:hint="@string/editPass_hint"
                    android:inputType="textPassword"
                    android:textColor="#FFFFFF"
                    android:textColorHint="#8DFFFFFF" />
            </FrameLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp"
            android:orientation="horizontal">

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <TextView
                    android:id="@+id/textView4"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="top|left"
                    android:layout_marginBottom="34dp"
                    android:layout_marginLeft="8dp"
                    android:text="비밀번호 확인"
                    android:textColor="#FFFFFF"
                    android:textSize="18sp" />

                <EditText
                    android:id="@+id/editTextRePass_Reg"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="8dp"
                    android:backgroundTint="#FFFFFF"
                    android:ems="10"
                    android:layout_gravity="bottom"
                    android:inputType="textPassword"
                    android:textColor="#FFFFFF"
                    android:textColorHint="#8DFFFFFF" />

            </FrameLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp"
            android:orientation="horizontal">

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <TextView
                    android:id="@+id/textView5"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="top|left"
                    android:layout_marginBottom="34dp"
                    android:layout_marginLeft="8dp"
                    android:text="닉네임"
                    android:textColor="#FFFFFF"
                    android:textSize="18sp" />

                <EditText
                    android:id="@+id/editTextNick_Reg"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="8dp"
                    android:backgroundTint="#FFFFFF"
                    android:ems="10"
                    android:layout_gravity="bottom"
                    android:hint="@string/editNick_hint"
                    android:inputType="text"
                    android:maxLength="20"
                    android:textColor="#FFFFFF"
                    android:textColorHint="#8DFFFFFF" />

                <Button
                    android:id="@+id/btnCheckNick_Reg"
                    android:layout_width="80dp"
                    android:layout_height="30dp"
                    android:layout_gravity="right|top"
                    android:backgroundTint="#FFFFFF"
                    android:text="중복확인"
                    android:textAlignment="center"
                    android:textColor="#1C26FF"
                    android:padding="1dp"
                    android:textSize="12sp"/>
            </FrameLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp"
            android:orientation="horizontal">

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <TextView
                    android:id="@+id/textView6"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="top|left"
                    android:layout_marginBottom="34dp"
                    android:layout_marginLeft="8dp"
                    android:text="휴대폰"
                    android:textColor="#FFFFFF"
                    android:textSize="18sp" />

                <EditText
                    android:id="@+id/editTextPhone_Reg"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingLeft="8dp"
                    android:backgroundTint="#FFFFFF"
                    android:ems="10"
                    android:layout_gravity="bottom"
                    android:hint="@string/editPhone_hint"
                    android:inputType="number"
                    android:textColor="#FFFFFF"
                    android:textColorHint="#8DFFFFFF" />

            </FrameLayout>

        </LinearLayout>
    </LinearLayout>

    <ImageButton
        android:id="@+id/btnRegister_Reg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="45dp"
        android:background="#00FF0000"
        android:src="@drawable/complete"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

❔ hint 사이즈 조절

코드에서 EditTexthint의 여러가지 성질을 조정하기 위해서 string 파일에 코드를 추가해 주었습니다.
파일 위치 : res -> values -> strings.xml

아래와 같이 코드를 추가해주면 hint폰트 사이즈를 바꿀 수 있게 됩니다.

string.xml

<string name="editId_hint"><font size="14">6~15자 영문/숫자 조합으로 입력</font></string>

📌 DBHelper 클래스 생성

로그인과 회원가입을 구현하기 위해 DBHelper 클래스를 작성합니다.

DBHelper 클래스에서는 내부db를 사용하여 회원가입 정보를 저장하는 등의 코드를 작성할 것입니다.

DBHelper.kt

이 코드는 아이디, 비밀번호, 닉네임, 전화번호를 받습니다. 모두 string 타입으로 db에 저장하는 것을 참고해 주세요.
원하는 대로 코드를 수정하여, 아이디와 비밀번호로만 구성된 db를 작성할 수도 있습니다.

class DBHelper(context: Context) :
    SQLiteOpenHelper(context, "Login.db", null, 1) {
    // users 테이블 생성
    override fun onCreate(MyDB: SQLiteDatabase?) {
        MyDB!!.execSQL("create Table users(id TEXT primary key, password TEXT, nick TEXT, phone TEXT)")
    }
    
    // 정보 갱신
    override fun onUpgrade(MyDB: SQLiteDatabase?, i: Int, i1: Int) {
        MyDB!!.execSQL("drop Table if exists users")
    }
    
    // id, password, nick, phone 삽입 (성공시 true, 실패시 false)
    fun insertData (id: String?, password: String?, nick: String?, phone: String?): Boolean {
        val MyDB = this.writableDatabase
        val contentValues = ContentValues()
        contentValues.put("id", id)
        contentValues.put("password", password)
        contentValues.put("nick", nick)
        contentValues.put("phone", phone)
        val result = MyDB.insert("users", null, contentValues)
        MyDB.close()
        return if (result == -1L) false else true
    }
    
    // 사용자 아이디가 없으면 false, 이미 존재하면 true
    fun checkUser(id: String?): Boolean {
        val MyDB = this.readableDatabase
        var res = true
        val cursor = MyDB.rawQuery("Select * from users where id =?", arrayOf(id))
        if (cursor.count <= 0) res = false
        return res
    }
    
    // 사용자 닉네임이 없으면 false, 이미 존재하면 true
    fun checkNick(nick: String?): Boolean {
        val MyDB = this.readableDatabase
        var res = true
        val cursor = MyDB.rawQuery("Select * from users where nick =?", arrayOf(nick))
        if (cursor.count <= 0) res = false
        return res
    }
    
    // 해당 id, password가 있는지 확인 (없다면 false)
    fun checkUserpass(id: String, password: String) : Boolean {
        val MyDB = this.writableDatabase
        var res = true
        val cursor = MyDB.rawQuery(
            "Select * from users where id = ? and password = ?",
            arrayOf(id, password)
        )
        if (cursor.count <= 0) res = false
        return res
    }

    // DB name을 Login.db로 설정
    companion object {
        const val DBNAME = "Login.db"
    }
}

📌 로그인 코틀린 코드 구현

MainActivity.kt - 로그인 페이지

로그인 페이지에서는 아이디와 비밀번호를 입력 받습니다.
아이디와 비밀번호 중 하나라도 입력이 비어있지 않은지 검사한 후, 아이디와 비밀번호가 db에서 일치하는 지를 검사합니다.
모든 if문을 통과하면 intent를 통해서 HomeActivity로 페이지가 이동합니다.

그리고 회원가입 버튼을 누르면 회원가입 페이지로 이동하도록 코드를 작성하였습니다.

class MainActivity : AppCompatActivity() {
    lateinit var btnLogin: ImageButton
    lateinit var editTextId: EditText
    lateinit var editTextPassword: EditText
    lateinit var btnRegister: Button
    var DB:DBHelper?=null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        DB = DBHelper(this)

        btnLogin = findViewById(R.id.btnLogin)
        editTextId = findViewById(R.id.editTextId)
        editTextPassword = findViewById(R.id.editTextPassword)
        btnRegister = findViewById(R.id.btnRegister)  
        
        // 로그인 버튼 클릭
        btnLogin!!.setOnClickListener {
            val user = editTextId!!.text.toString()
            val pass = editTextPassword!!.text.toString()

            // 빈칸 제출시 Toast
            if (user == "" || pass == "") {
            	Toast.makeText(this@MainActivity, "아이디와 비밀번호를 모두 입력해주세요.", Toast.LENGTH_SHORT).show()
            }
            else {
                val checkUserpass = DB!!.checkUserpass(user, pass)
                // id 와 password 일치시
                if (checkUserpass == true) {
                    Toast.makeText(this@MainActivity, "로그인 되었습니다.", Toast.LENGTH_SHORT).show()

                    val intent = Intent(this, HomeActivity::class.java)
                    startActivity(intent)
                }
                else {
                    Toast.makeText(this@MainActivity, "아이디와 비밀번호를 확인해 주세요.", Toast.LENGTH_SHORT).show()
                }
            }
        }
        // 회원가입 버튼 클릭시
        btnRegister.setOnClickListener {
            val loginIntent = Intent(this@MainActivity, RegisterActivity::class.java)
            startActivity(loginIntent)
        }
    }
}

📌 회원가입 코틀린 코드 구현

회원가입 페이지에서는 아이디, 비밀번호, 닉네임, 전화번호를 입력받습니다.
그중에서 아이디와 닉네임은 버튼을 통해 중복 검사를 합니다. 그리고 비밀번호는 입력을 한 번 더 받아서 재확인을 합니다.

RegisterActivity.kt

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.ImageButton
import android.widget.Toast
import java.util.regex.Pattern

class RegisterActivity : AppCompatActivity() {
    var DB:DBHelper?=null
    lateinit var editTextId: EditText
    lateinit var editTextPassword: EditText
    lateinit var editTextRePassword: EditText
    lateinit var editTextNick: EditText
    lateinit var editTextPhone: EditText
    lateinit var btnRegister: ImageButton
    lateinit var btnCheckId: Button
    var CheckId:Boolean=false
    lateinit var btnCheckNick: Button
    var CheckNick:Boolean=false
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_register)

        DB = DBHelper(this)
        editTextId = findViewById(R.id.editTextId_Reg)
        editTextPassword = findViewById(R.id.editTextPass_Reg)
        editTextRePassword = findViewById(R.id.editTextRePass_Reg)
        editTextNick = findViewById(R.id.editTextNick_Reg)
        editTextPhone = findViewById(R.id.editTextPhone_Reg)
        btnRegister = findViewById(R.id.btnRegister_Reg)
        btnCheckId = findViewById(R.id.btnCheckId_Reg)
        btnCheckNick = findViewById(R.id.btnCheckNick_Reg)
        
        // 아이디 중복확인
        btnCheckId.setOnClickListener {
            val user = editTextId.text.toString()
            val idPattern = "^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z[0-9]]{6,15}$"

            if (user == "") {
                Toast.makeText(
                    this@RegisterActivity,
                    "아이디를 입력해주세요.",
                    Toast.LENGTH_SHORT
                ).show()
            }
            else {
                if (Pattern.matches(idPattern, user)) {
                    val checkUsername = DB!!.checkUser(user)
                    if(checkUsername == false){
                        CheckId = true
                        Toast.makeText(this@RegisterActivity, "사용 가능한 아이디입니다.", Toast.LENGTH_SHORT).show()
                    }
                    else {
                        Toast.makeText(this@RegisterActivity, "이미 존재하는 아이디입니다.", Toast.LENGTH_SHORT).show()
                    }
                }
                else {
                    Toast.makeText(this@RegisterActivity, "아이디 형식이 옳지 않습니다.", Toast.LENGTH_SHORT).show()
                }
            }
        }

        // 닉네임 중복확인
        btnCheckNick.setOnClickListener {
            val nick = editTextNick.text.toString()
            val nickPattern = "^[ㄱ-ㅣ가-힣]*$"

            if (nick == "") {
                Toast.makeText(
                    this@RegisterActivity,
                    "닉네임을 입력해주세요.",
                    Toast.LENGTH_SHORT
                ).show()
            }
            else {
                if (Pattern.matches(nickPattern, nick)) {
                    val checkNick = DB!!.checkNick(nick)
                    if(checkNick == false){
                        CheckNick = true
                        Toast.makeText(this@RegisterActivity, "사용 가능한 닉네임입니다.", Toast.LENGTH_SHORT).show()
                    }
                    else {
                        Toast.makeText(this@RegisterActivity, "이미 존재하는 닉네임입니다.", Toast.LENGTH_SHORT).show()
                    }
                }
                else {
                    Toast.makeText(this@RegisterActivity, "닉네임 형식이 옳지 않습니다.", Toast.LENGTH_SHORT).show()
                }
            }
        }

        // 완료 버튼 클릭 시
        btnRegister.setOnClickListener {
            val user = editTextId.text.toString()
            val pass = editTextPassword.text.toString()
            val repass = editTextRePassword.text.toString()
            val nick = editTextNick.text.toString()
            val phone = editTextPhone.text.toString()
            val pwPattern = "^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z[0-9]]{8,15}$"
            val phonePattern = "^(\\+[0-9]+)?[0-9]{10,15}$"
            // 사용자 입력이 비었을 때
            if (user == "" || pass == "" || repass == "" || nick == "" || phone == "") Toast.makeText(
                this@RegisterActivity,
                "회원정보를 모두 입력해주세요.",
                Toast.LENGTH_SHORT
            ).show()
            else {
                // 아이디 중복 확인이 됐을 때
                if (CheckId == true) {
                    // 비밀번호 형식이 맞을 때
                    if (Pattern.matches(pwPattern, pass)) {
                        // 비밀번호 재확인 성공
                        if (pass == repass) {
                            // 닉네임 중복확인
                            if (CheckNick == true) {
                                // 번호 형식
                                if (Pattern.matches(phonePattern, phone)) {
                                    val insert = DB!!.insertData(user, pass, nick, phone)
                                    // 가입 성공 시 Toast를 띄우고 메인 화면으로 전환
                                    if (insert == true) {
                                        Toast.makeText(
                                            this@RegisterActivity,
                                            "가입되었습니다.",
                                            Toast.LENGTH_SHORT
                                        ).show()
                                        val intent =
                                            Intent(applicationContext, MainActivity::class.java)
                                        startActivity(intent)
                                    }
                                    // 가입 실패 시
                                    else {
                                        Toast.makeText(
                                            this@RegisterActivity,
                                            "가입 실패하였습니다.",
                                            Toast.LENGTH_SHORT
                                        ).show()
                                    }

                                } else {
                                    Toast.makeText(
                                        this@RegisterActivity,
                                        "전화번호 형식이 옳지 않습니다.",
                                        Toast.LENGTH_SHORT
                                    ).show()
                                }
                            }
                            // 닉네임 중복확인 하지 않았을 때
                            else {
                                Toast.makeText(
                                    this@RegisterActivity,
                                    "닉네임 중복확인을 해주세요.",
                                    Toast.LENGTH_SHORT
                                ).show()
                            }
                        }
                        // 비밀번호 재확인 실패
                        else {
                            Toast.makeText(
                                this@RegisterActivity,
                                "비밀번호가 일치하지 않습니다.",
                                Toast.LENGTH_SHORT
                            ).show()
                        }
                    }
                    // 비밀번호 형식이 맞지 않을 때
                    else {
                        Toast.makeText(
                            this@RegisterActivity,
                            "비밀번호 형식이 옳지 않습니다.",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
                // 아이디 중복확인이 되지 않았을 때
                else {
                    Toast.makeText(this@RegisterActivity, "아이디 중복확인을 해주세요.", Toast.LENGTH_SHORT)
                        .show()
                }
            }
        }
    }
}

📣 패턴 검사 (정규식)

위 코드에는 패턴 검사에 대한 내용이 들어가 있습니다. 아이디나 비밀번호에 들어갈 문자의 종류나 길이를 제한하는 것입니다.
예를 들어 아이디에 영어, 숫자, 특수 문자가 모두 들어가게 하거나 전화번호에 숫자만 들어가게 하는 등의 방법이 있습니다.

아이디 패턴 : ^(?=.[A-Za-z])(?=.[0-9])[A-Za-z[0-9]]{6,15}$
비밀번호 패턴 : ^(?=.[A-Za-z])(?=.[0-9])[A-Za-z[0-9]]{8,15}$
닉네임 패턴 : ^[ㄱ-ㅣ가-힣]*$
전화번호 패턴 : ^(\+[0-9]+)?[0-9]{10,15}$

아이디, 비밀번호 패턴은 아래와 같은 의미를 갖습니다.

^ : 문자열의 시작을 나타냄.
(?=.*[A-Za-z]) : 최소한 한 개의 알파벳 문자 (대문자 또는 소문자)가 포함되어야 함.
(?=.*[0-9]) : 최소한 한 개의 숫자가 포함되어야 함.
[A-Za-z[0-9]]{6,15}: 알파벳 문자 또는 숫자로 이루어진 6~15자의 문자열을 나타냄.
$ : 문자열의 끝을 나타냄.

닉네임 패턴은 아래와 같은 의미를 갖습니다. 참고로 닉네임 입력은 xml 파일에서 android:maxLength="20"로 최대 글자수를 제한하였습니다.

^ : 문자열의 시작을 나타냄.
[ㄱ-ㅣ가-힣] : [ㄱ-ㅣ]는 자음 범위, [가-힣]는 모든 한글 범위를 나타냄.
* : 0회 이상의 반복을 나타내며, 0 글자 이상의 한글 문자로 이루어진 문자열을 의미함.
$ : 문자열의 끝을 나타냄.

전화번호 패턴은 아래와 같은 의미를 갖습니다.

^ : 문자열의 시작을 나타냄.
(\+[0-9]+)? : 국제 전화번호를 작성할 수 있는 패턴임.
[0-9]{10,15}: 10자에서 15자의 숫자로 구성된 전화번호를 나타냄.
$ : 문자열의 끝을 나타냄.

< 국제 전화번호 패턴 >
\+ : + 문자를 의미함.
[0-9]+ : 하나 이상의 숫자로 구성된 국제 전화번호 코드.
? : 해당 부분이 0 또는 1회 나타날 수 있다는 것을 나타냄.


❔한글 키보드가 나오지 않는다면?

에뮬레이터를 켠 후,
설정(Settings) -> System -> Language & input -> Languages -> add a language -> 한글 추가
하면 키보드에 한글 키보드가 추가되어, 전환할 수 있습니다.

➕ 중복 확인 버튼 없는 회원가입

처음에는 중복 확인 버튼을 따로 넣지 않고, 회원가입 버튼을 눌렀을 때 자동으로 검사하도록 구현했었습니다.
이처럼 만약 버튼을 넣지 않고 중복 검사까지 하는 형태를 만들고 싶다면 다음처럼 수정할 수 있습니다.

RegisterAcitivity.kt

btnRegister.setOnClickListener {
    val user = editTextId.text.toString()
    val pass = editTextPassword.text.toString()
    val repass = editTextRePassword.text.toString()
    val nick = editTextNick.text.toString()
    val phone = editTextPhone.text.toString()
    val pwPattern = "^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z[0-9]]{8,15}$"
    val idPattern = "^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z[0-9]]{6,15}$"
    val nickPattern = "^[ㄱ-ㅣ가-힣]*$"
    val phonePattern = "^(\\+[0-9]+)?[0-9]{10,15}$"
    // 사용자 입력이 비었을 때
    if (user == "" || pass == "" || repass == "" || nick == "" || phone == "") Toast.makeText(
        this@RegisterActivity,
        "회원정보를 모두 입력해주세요.",
        Toast.LENGTH_SHORT
    ).show()
    else {
        // 아이디 형식이 맞을 때
        if (Pattern.matches(idPattern, user)) {
            val checkUsername = DB!!.checkUser(user)
            // 비밀번호 형식이 맞을 때
            if (Pattern.matches(pwPattern, pass)) {
                // 비밀번호 재확인 성공
                if (pass == repass) {

                    // 닉네임 형식 체크
                    if (Pattern.matches(nickPattern, nick)) {
                        val checkNick = DB!!.checkNick(nick)
                        // 번호 형식
                        if (Pattern.matches(phonePattern, phone)) {
                            // 새로운 아이디일 때
                            if (checkUsername == false) {
                                if (checkNick == false) {
                                    val insert = DB!!.insertData(user, pass, nick, phone)
                                    // 가입 성공 시 Toast를 띄우고 메인 화면으로 전환
                                    if (insert == true) {
                                        Toast.makeText(
                                            this@RegisterActivity,
                                            "가입되었습니다.",
                                            Toast.LENGTH_SHORT
                                        ).show()
                                        val intent = Intent(applicationContext, MainActivity::class.java)
                                        startActivity(intent)
                                    }
                                    // 가입 실패 시
                                    else {
                                        Toast.makeText(
                                            this@RegisterActivity,
                                            "가입 실패하였습니다.",
                                            Toast.LENGTH_SHORT
                                        ).show()
                                    }
                                }
                                // 존재하는 닉네임일 경우
                                else {
                                    Toast.makeText(
                                        this@RegisterActivity,
                                        "이미 존재하는 닉네임입니다.",
                                        Toast.LENGTH_SHORT
                                    ).show()
                                }
                            }
                            // 존재하는 id일 경우
                            else {
                                Toast.makeText(
                                    this@RegisterActivity,
                                    "이미 존재하는 아이디입니다.",
                                    Toast.LENGTH_SHORT
                                ).show()
                            }
                        }
                        else {
                            Toast.makeText(this@RegisterActivity, "전화번호 형식이 옳지 않습니다.", Toast.LENGTH_SHORT).show()
                        }
                    }
                    else {
                        Toast.makeText(this@RegisterActivity, "닉네임 형식이 옳지 않습니다.", Toast.LENGTH_SHORT).show()
                    }
                }
                // 비밀번호 재확인 실패
                else {
                    Toast.makeText(this@RegisterActivity, "비밀번호가 일치하지 않습니다.", Toast.LENGTH_SHORT).show()
                }
            }
            // 비밀번호 형식이 맞지 않을 때
            else {
                Toast.makeText(
                    this@RegisterActivity,
                    "비밀번호 형식이 옳지 않습니다.",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
        // 아이디 형식이 맞지 않을 때
        else {
            Toast.makeText(this@RegisterActivity, "아이디 형식이 옳지 않습니다.", Toast.LENGTH_SHORT).show()
        }
    }

➕ 생성한 로그인 DB 전달/적용 방법

만약 본인이 회원가입할 때에 사용만들어진 Login.db를 다른 사람에게 전달하고자 할 때 혹은 전달받은 Login.db를 나의 앱에서 적용하고 싶을 때, 아래와 같은 방법을 사용하시면 됩니다.

<전달 방법>

  1. 에뮬레이터와 앱을 실행한다.

  2. 안드로이드 스튜디오 화면 오른쪽 아래에 있는 Device File Explorer를 연다.

  3. data 폴더를 클릭하고 그 안의 data 폴더를 클릭하여 연다.

  4. 파일 안에서 본인이 만든 앱 이름을 찾고, 마우스 오른쪽을 클릭하여 Save As를 누른다.

  5. 원하는 위치에 파일을 저장한다. (저는 Downloads 파일에 저장하였습니다.)

  6. 해당 폴더를 열고 db파일을 마우스 오른쪽 클릭 또는 ctrl+c 하여 복사한다.

  7. 상대에게 파일을 전송한다.

<적용 방법>

  1. 상대가 보내온 db 파일을 복사해둔다. (마우스 오른쪽 클릭 또는 ctrl+c)

  2. 에뮬레이터와 앱을 실행한다.

  3. 안드로이드 스튜디오 화면 오른쪽 아래에 있는 Device File Explorer를 연다.

  4. data -> data -> 본인 앱 이름의 파일 -> databases 를 찾고, 그안의 Login.db를 마우스 오른쪽 클릭하여 삭제한다.

  5. 아까 복사해둔 파일을 databases 폴더에 붙여 넣는다. (ctrl+v)


이렇게 지금까지 로그인, 회원가입 페이지를 만들어 보았습니다.
감사합니다.

profile
개발 공부 기록✒️

2개의 댓글

comment-user-thumbnail
2023년 8월 5일

개발자로서 배울 점이 많은 글이었습니다. 감사합니다.

1개의 답글