Develop/Kotlin

[AWS] 아마존 웹 서비스 코틀린 Android + Amazon Cognito

JunJangE 2021. 7. 29. 18:19

이전에 자바로 다뤘던 aws Amazon Cognito 구현을 코틀린으로 구현 해보자.

amplify 연동과 cognito 구현은 이전에 다뤘기 때문에 링크를 통해 확인하면 좋을 것 같다.

 

[AWS] 아마존 웹 서비스 Amplify + Android 프로젝트 연동

AWS Amplify와 Android 앱을 연동해보자. 클라우드 서비스 | 클라우드 컴퓨팅 솔루션| Amazon Web Services 제조 AWS를 활용한 Siemens의 에너지, 의료 서비스, 제조 분야 혁신 Siemens가 AWS를 사용하여 어떻게..

fre2-dom.tistory.com

 

 

[AWS] 아마존 웹 서비스 Android + Amazon Cognito 구현

지난번에 AWS Amplify와 Android 앱을 연동해보았다. [AWS] 아마존 웹 서비스 Amplify + Android 프로젝트 연동 Android 앱과 AWS의 서비스를 연동해보자. 클라우드 서비스 | 클라우드 컴퓨팅 솔루션| Amazon Web..

fre2-dom.tistory.com

우선 로그인창과 밀번호 재설정 창, 회원가입 창, 인증 코드를 받는 창 총 4가지 activity를 만든다.

이름은 다음과 같이 한다.

AuthActivity = 로그인 창

SignUpActivity = 회원가입 창

OkActivity = 인증 코드 창

ForgotActivity = 비밀번호 재설정 창

다음으로 메인 액티비티- 로그인- 회원가입- 인증 코드- 비밀번호 재설정 창 코드 순으로 코드를 확인해보자.

MainActivity

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.mobile.client.AWSMobileClient
import com.amazonaws.mobile.client.Callback
import com.amazonaws.mobile.client.UserStateDetails


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val signOut_button = findViewById<Button>(R.id.signOut_button) // 로그아웃 버튼

        // 로그아웃 버튼
        signOut_button.setOnClickListener {
            AWSMobileClient.getInstance().initialize(
                applicationContext,
                object : Callback<UserStateDetails?> {
                    override fun onResult(userStateDetails: UserStateDetails?) {
                        // 로그아웃 후 로그인 창으로 이동
                        AWSMobileClient.getInstance().signOut()
                        val i = Intent(this@MainActivity, AuthActivity::class.java)
                        startActivity(i)
                        finish()
                    }

                    override fun onError(e: Exception) {}
                })
        }
    }

    // 뒤로가기 2번 눌러야 종료
    private val FINISH_INTERVAL_TIME: Long = 2500
    private var backPressedTime: Long = 0
    private var toast: Toast? = null
    override fun onBackPressed() {
        val tempTime = System.currentTimeMillis()
        val intervalTime = tempTime - backPressedTime


        // 뒤로 가기 할 경우 홈 화면으로 이동
        if (0 <= intervalTime && FINISH_INTERVAL_TIME >= intervalTime) {
            super.onBackPressed()
            // 뒤로가기 토스트 종료
            toast!!.cancel()
            finish()
        } else {
            backPressedTime = tempTime
            toast =
                Toast.makeText(applicationContext, "'뒤로'버튼 한번 더 누르시면 종료됩니다.", Toast.LENGTH_SHORT)
//            toast.show()
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    tools:context=".SignUpActivity"
    android:orientation="vertical"
    android:gravity="center">


    <Button
        android:id="@+id/signOut_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="로그아웃"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"/>


</LinearLayout>

AuthActivity (로그인)

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.mobile.client.AWSMobileClient
import com.amazonaws.mobile.client.Callback
import com.amazonaws.mobile.client.UserState
import com.amazonaws.mobile.client.UserStateDetails
import com.amazonaws.mobile.client.results.SignInResult
import com.amazonaws.mobile.client.results.SignInState


class AuthActivity : AppCompatActivity() {
    private val TAG = AuthActivity::class.java.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_auth)
        val signIn_button = findViewById<Button>(R.id.signIn_button) // 로그인 버튼
        val signUp_button = findViewById<Button>(R.id.signUp_button) // 회원가입 버튼
        val forgot_Password_button =
            findViewById<Button>(R.id.forgot_Password_button) // 비밀번호를 잊어버리셨나요?

        // 로그인이 되어있는지 확인
        AWSMobileClient.getInstance()
            .initialize(applicationContext, object : Callback<UserStateDetails> {
                override fun onResult(userStateDetails: UserStateDetails) {
                    Log.i(TAG, userStateDetails.userState.toString())

                    // 로그인이 되어있으면 MainActivity 로 이동
                    if (userStateDetails.userState == UserState.SIGNED_IN) {
                        val i = Intent(this@AuthActivity, MainActivity::class.java)
                        startActivity(i)
                        finish()
                    }
                }

                override fun onError(e: Exception) {
                    Log.e(TAG, e.toString())
                }
            })

        // 로그인 버튼
        signIn_button.setOnClickListener { showSignIn() }

        // 회원가입 버튼
        signUp_button.setOnClickListener {
            val i = Intent(this@AuthActivity, SignUpActivity::class.java)
            startActivity(i)
            finish()
        }

        // 비밀번호를 잊어버리셨나요?
        forgot_Password_button.setOnClickListener {
            val i = Intent(this@AuthActivity, ForgotActivity::class.java)
            startActivity(i)
            finish()
        }
    }

    // 로그인 함수
    private fun showSignIn() {

        // 아이디 비밀번호 순
        val login_id = findViewById<EditText>(R.id.login_id)
        val login_paw = findViewById<EditText>(R.id.login_paw)
        val username = login_id.text.toString()
        val password = login_paw.text.toString()
        AWSMobileClient.getInstance().signIn(username, password, null, object : Callback<SignInResult> {
                override fun onResult(signInResult: SignInResult) {
                    runOnUiThread {
                        Log.d(TAG, "Sign-in callback state: " + signInResult.signInState)
                        when (signInResult.signInState) {
                            SignInState.DONE -> {
                                Toast.makeText(applicationContext, "환영합니다!", Toast.LENGTH_SHORT).show()
                                val i = Intent(this@AuthActivity, MainActivity::class.java)
                                startActivity(i)
                                finish()
                            }
                            SignInState.SMS_MFA -> Toast.makeText(applicationContext, "Please confirm sign-in with SMS.", Toast.LENGTH_SHORT).show()
                            
                            SignInState.NEW_PASSWORD_REQUIRED -> Toast.makeText(applicationContext, "Please confirm sign-in with new password.", Toast.LENGTH_SHORT).show()
                            
                            else -> Toast.makeText(applicationContext, "Unsupported sign-in confirmation: " + signInResult.signInState, Toast.LENGTH_SHORT).show()
                        }
                    }
                }

                override fun onError(e: Exception) {
                    Log.e(TAG, "Sign-in error : " + e.message)
                    when {
                        e.message!!.contains("Missing required parameter USERNAME") -> {
                            errorMessage("아이디와 비밀번호를 입력해주세요.")
                        }
                        e.message!!.contains("Incorrect username or password.") -> {
                            errorMessage("아이디와 비밀번호가 일치하지 않습니다.")
                        }
                        e.message!!.contains("User does not exist.") -> {
                            errorMessage("존재하지 않는 아이디입니다.")
                        }
                        e.message!!.contains("Unable to execute HTTP request") -> {
                            errorMessage("네트워크가 원활하지 않습니다.\n네트워크 연결 상태를 확인하세요.")
                        }
                        e.message!!.contains("User is not confirmed.") -> {


                            // 다이어로그 생성
                            val mHandler = Handler(Looper.getMainLooper())
                            mHandler.post {
                                val ad = AlertDialog.Builder(this@AuthActivity)
                                ad.setIcon(R.mipmap.ic_launcher)
                                ad.setTitle("인증 코드 미승인")
                                ad.setMessage("인증 코드를 승인하지 않았습니다.\n인증 코드를 승인하러 가시겠습니까?")

                                // 확인버튼
                                ad.setPositiveButton(
                                    "확인"
                                ) { dialog, which -> // 이메일에 문제가 없으면 인증 코드 창으로 이동
                                    val i = Intent(this@AuthActivity, OkActivity::class.java)
                                    i.putExtra("email", username) // username을 인증 코드 창에서 사용하기 위해
                                    startActivity(i)
                                    finish()
                                    dialog.dismiss()
                                }

                                // 취소버튼
                                ad.setNegativeButton(
                                    "취소"
                                ) { dialog, which -> dialog.dismiss() }
                                ad.show()
                            }
                        }
                    }
                }
            })
    }

    // 뒤로가기 2번 눌러야 종료
    private val FINISH_INTERVAL_TIME: Long = 2500
    private var backPressedTime: Long = 0
    private var toast: Toast? = null
    override fun onBackPressed() {
        val tempTime = System.currentTimeMillis()
        val intervalTime = tempTime - backPressedTime


        // 뒤로 가기 할 경우 홈 화면으로 이동
        if (0 <= intervalTime && FINISH_INTERVAL_TIME >= intervalTime) {
            super.onBackPressed()
            // 뒤로가기 토스트 종료
            toast!!.cancel()
            finish()
        } else {
            backPressedTime = tempTime
            toast =
                Toast.makeText(applicationContext, "'뒤로'버튼 한번 더 누르시면 종료됩니다.", Toast.LENGTH_SHORT)
//            toast.show()
        }
    }

    // 에러 메시지
    fun errorMessage(message: String?) {
        val mHandler = Handler(Looper.getMainLooper())
        mHandler.post { Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show() }
    }
}

activity_auth.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    tools:context=".AuthActivity"
    android:orientation="vertical"
    android:gravity="center">


    <LinearLayout

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        >

        <TextView
            android:id="@+id/login_id_text"
            android:layout_width="90dp"
            android:layout_height="30dp"
            android:text="아이디"
            android:textSize="20sp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/login_id"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10"
            android:inputType="textEmailAddress" />


    </LinearLayout>


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center"
        android:layout_marginTop="20dp">

        <TextView
            android:id="@+id/login_paw_text"
            android:layout_width="90dp"
            android:layout_height="30dp"
            android:text="비밀번호"
            android:textSize="20sp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/login_paw"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10"
            android:inputType="textPassword" />


    </LinearLayout>


    <Button
        android:id="@+id/signIn_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="로그인"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"/>
    <Button
        android:id="@+id/forgot_Password_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="비밀번호를 잊어버리셨나요?"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"/>

    <Button
        android:id="@+id/signUp_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="회원가입"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"/>





</LinearLayout>

SignUpActivity (회원가입)

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.mobile.client.AWSMobileClient
import com.amazonaws.mobile.client.Callback
import com.amazonaws.mobile.client.results.SignUpResult
import java.util.*


class SignUpActivity : AppCompatActivity() {
    var TAG = AuthActivity::class.java.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sign_up)
        val signUp_button2 = findViewById<Button>(R.id.signUp_button2) // 회원 가입 버튼

        // 회원 가입 버튼
        signUp_button2.setOnClickListener {
            // 이름, 아이디(이메일), 비밀번호 순
            val signUpName = findViewById<View>(R.id.signUpName) as EditText
            val signUpUsername = findViewById<View>(R.id.signUpUsername) as EditText
            val signUpPassword = findViewById<View>(R.id.signUpPassword) as EditText
            val name = signUpName.text.toString()
            val username = signUpUsername.text.toString()
            val password = signUpPassword.text.toString()
            val attributes: MutableMap<String, String> =
                HashMap()
            attributes["name"] = name
            attributes["email"] = username
            Log.d("TTT", attributes.toString())
            AWSMobileClient.getInstance().signUp(
                username,
                password,
                attributes,
                null,
                object :
                    Callback<SignUpResult> {
                    override fun onResult(signUpResult: SignUpResult) {
                        runOnUiThread {
                            Log.d(
                                TAG,
                                "Sign-up callback state: " + signUpResult.confirmationState
                            )
                            if (!signUpResult.confirmationState) {
                                val details = signUpResult.userCodeDeliveryDetails
                                Toast.makeText(applicationContext, "인증 메일을 보냈습니다.: " + details.destination, Toast.LENGTH_SHORT).show()

                                // 이메일에 문제가 없으면 인증 코드 창으로 이동
                                val i = Intent(this@SignUpActivity, OkActivity::class.java)
                                i.putExtra("email", username) // username을 인증 코드 창에서 사용하기 위해
                                startActivity(i)
                                finish()
                            } else {
                                // 인증 코드 창으로 이동
                                Toast.makeText(applicationContext, "Sign-up done.", Toast.LENGTH_SHORT).show()
                                Log.e(TAG, "Sddd")
                            }
                        }
                    }

                    override fun onError(e: Exception) {
                        Log.e(TAG, "Sign-up error", e)
                        when {
                            name.length <= 1 -> {
                                errorMessage("이름을 정확히 입력하세요.")
                            }
                            e.message!!.contains("An account with the given email already exists.") -> {
                                errorMessage("주어진 이메일을 가진 계정이 이미 존재합니다.")
                            }
                            e.message!!.contains("Value at 'username' failed to satisfy constraint") -> {
                                errorMessage("이메일을 입력해주세요.")
                            }
                            e.message!!.contains("Invalid email address format.") -> {
                                errorMessage("잘못된 이메일 주소 형식입니다.")
                            }
                            e.message!!.contains("Value at 'password' failed to satisfy constraint") -> {
                                errorMessage("비밀번호를 입력해주세요")
                            }
                            e.message!!.contains("Password did not conform with policy: Password not long enough") -> {
                                errorMessage("비밀번호는 8자 이상이어야 하며 특수 문자를 반드시 포함해야 합니다.")
                            }
                        }
                    }
                })
        }
    }

    override fun onBackPressed() {
        val i = Intent(this@SignUpActivity, AuthActivity::class.java)
        startActivity(i)
        finish()
    }

    // 에러 메시지
    fun errorMessage(message: String?) {
        val mHandler = Handler(Looper.getMainLooper())
        mHandler.post { Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show() }
    }
}

activity_signup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    tools:context=".SignUpActivity"
    android:orientation="vertical"
    android:gravity="center">


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:layout_marginTop="20dp">
        <TextView
            android:id="@+id/signUpName_text"
            android:layout_width="90dp"
            android:layout_height="30dp"
            android:text="이름"
            android:textSize="20sp"
            android:textStyle="bold"
            tools:layout_editor_absoluteX="7dp"
            tools:layout_editor_absoluteY="318dp" />

        <EditText
            android:id="@+id/signUpName"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10"
            android:inputType="text"
            tools:layout_editor_absoluteX="213dp"
            tools:layout_editor_absoluteY="310dp" />


    </LinearLayout>
    <LinearLayout

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        >

        <TextView
            android:id="@+id/signUpUsername_text"
            android:layout_width="90dp"
            android:layout_height="30dp"
            android:text="이메일"
            android:textSize="20sp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/signUpUsername"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10" />


    </LinearLayout>


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:layout_marginTop="20dp">

        <TextView
            android:id="@+id/signUpPassword_text"
            android:layout_width="90dp"
            android:layout_height="30dp"
            android:text="비밀번호"
            android:textSize="20sp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/signUpPassword"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10"
            android:inputType="textPassword" />


    </LinearLayout>


    <Button
        android:id="@+id/signUp_button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:text="회원가입" />


</LinearLayout>

OkActivity (인증 코드)

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.mobile.client.AWSMobileClient
import com.amazonaws.mobile.client.Callback
import com.amazonaws.mobile.client.results.SignUpResult


class OkActivity : AppCompatActivity() {
    var TAG = AuthActivity::class.java.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_ok)

        // 인증 확인 버튼
        val Ok_button = findViewById<Button>(R.id.Ok_button)
        // 인증 재전송 버튼
        val Re_Ok_button = findViewById<Button>(R.id.Re_Ok_button)

        // SignUpActivity 에서 사용된 username 정보를 가져와 TextView에 넣는다.
        val TextView = findViewById<TextView>(R.id.signUpUsername2)
        val intent = intent
        val bundle = intent.extras
        val username = bundle!!.getString("email")
        TextView.text = username

        // 인증 버튼
        Ok_button.setOnClickListener {
            val code_name = findViewById<EditText>(R.id.code_name)
            val code = code_name.text.toString()
            AWSMobileClient.getInstance().confirmSignUp(
                username,
                code,
                object :
                    Callback<SignUpResult> {
                    override fun onResult(signUpResult: SignUpResult) {
                        runOnUiThread {
                            Log.d(TAG, "Sign-up callback state: " + signUpResult.confirmationState)
                            if (!signUpResult.confirmationState) {
                                val details = signUpResult.userCodeDeliveryDetails
                                Toast.makeText(applicationContext, "Confirm sign-up with: " + details.destination, Toast.LENGTH_SHORT).show()
                            } else {

                                // 회원가입이 완료되면 로그인 창으로 이동
                                Toast.makeText(applicationContext, "성공적으로 회원가입 되셨습니다.", Toast.LENGTH_SHORT).show()
                                val i = Intent(this@OkActivity, AuthActivity::class.java)
                                startActivity(i)
                                finish()
                            }
                        }
                    }

                    override fun onError(e: Exception) {
                        Log.e(TAG, "Confirm sign-up error", e)
                        if (e.message!!.contains("Value '' at 'confirmationCode' failed to satisfy constraint")) {
                            errorMessage("인증 코드를 입력해주세요.")
                        } else if (e.message!!.contains("Invalid verification code provided, please try again.")) {
                            errorMessage("인증 코드를 다시 확인해주세요.")
                        }
                    }
                })
        }

        // 인증 코드 재전송 버튼
        Re_Ok_button.setOnClickListener {
            AWSMobileClient.getInstance().resendSignUp(
                username,
                object :
                    Callback<SignUpResult> {
                    override fun onResult(signUpResult: SignUpResult) {
                        Log.i(TAG, "A verification code has been sent via" + signUpResult.userCodeDeliveryDetails.deliveryMedium + " at " + signUpResult.userCodeDeliveryDetails.destination
                        )
                        Toast.makeText(applicationContext, "인증 메일이 재전송 되었습니다.", Toast.LENGTH_SHORT).show()
                    }

                    override fun onError(e: Exception) {
                        Log.e(TAG, e.toString())
                    }
                })
        }
    }

    // 뒤로가기 2번 눌러야 종료
    private val FINISH_INTERVAL_TIME: Long = 2500
    private var backPressedTime: Long = 0
    private var toast: Toast? = null
    override fun onBackPressed() {
        val tempTime = System.currentTimeMillis()
        val intervalTime = tempTime - backPressedTime


        // 뒤로 가기 할 경우 로그인 화면으로 이동
        if (0 <= intervalTime && FINISH_INTERVAL_TIME >= intervalTime) {
            val i = Intent(this@OkActivity, AuthActivity::class.java)
            startActivity(i)

            // 뒤로가기 토스트 종료
            toast!!.cancel()
            finish()
        } else {
            backPressedTime = tempTime
            toast =
                Toast.makeText(applicationContext, "'뒤로'버튼 한번 더 누르시면 종료됩니다.", Toast.LENGTH_SHORT)
//            toast.show()
        }
    }

    // 에러 메시지
    fun errorMessage(message: String?) {
        val mHandler = Handler(Looper.getMainLooper())
        mHandler.post { Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show() }
    }
}

activity_ok.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    tools:context=".OkActivity"
    android:orientation="vertical"
    android:gravity="center">

    <TextView
        android:id="@+id/ok_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="마지막 단계입니다!\n
        인증 메일이 아래의 이메일 주소로 전송되었습니다!\n
        24시간 이내로 인증을 완료해주세요!"
        android:textSize="16dp"
        android:textStyle="bold" />

    <LinearLayout

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        >

        <TextView
            android:id="@+id/signUpUsername2_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="이메일 주소"
            android:textSize="16dp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/signUpUsername2"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:gravity="center"
            android:textStyle="bold"
            android:textColor="@color/black"
            android:textSize="20dp"
            android:text="이메일" />


    </LinearLayout>

    <LinearLayout

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        >

        <TextView
            android:id="@+id/code_name_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="인증 코드"
            android:textSize="16dp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/code_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="text" />
        <Button
            android:id="@+id/Re_Ok_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="재전송" />



    </LinearLayout>



    <Button
        android:id="@+id/Ok_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:text="확인" />


</LinearLayout>

ForgotActivity (비밀번호 재설정)

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.amazonaws.mobile.client.AWSMobileClient
import com.amazonaws.mobile.client.Callback
import com.amazonaws.mobile.client.results.ForgotPasswordResult
import com.amazonaws.mobile.client.results.ForgotPasswordState


class ForgotActivity : AppCompatActivity() {
    private val TAG = AuthActivity::class.java.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_forgot)
        val code_button = findViewById<Button>(R.id.code_button) // 인증 코드 버튼
        val new_paw_button = findViewById<Button>(R.id.new_paw_button) // 비밀번호 재설정 버튼


        // 인증 버튼
        code_button.setOnClickListener { // 인증코드 확인
            val paw_signUpUsername = findViewById<View>(R.id.paw_signUpUsername) as EditText
            val username = paw_signUpUsername.text.toString()
            AWSMobileClient.getInstance().forgotPassword(username, object : Callback<ForgotPasswordResult> {
                    override fun onResult(result: ForgotPasswordResult) {
                        runOnUiThread {
                            Log.d(TAG, "forgot password state: " + result.state)
                            if (result.state == ForgotPasswordState.CONFIRMATION_CODE) {
                                Toast.makeText(applicationContext, "이메일 주소로 인증 코드가 전송되었습니다.", Toast.LENGTH_SHORT).show()
                            } else {
                                Log.e(TAG, "un-supported forgot password state")
                            }
                        }
                    }

                    override fun onError(e: Exception) {
                        Log.e(TAG, "forgot password error", e)
                        if (e.message!!.contains("Value at 'username' failed to satisfy constraint")) {
                            errorMessage("이메일을 입력해주세요.")
                        } else if (e.message!!.contains("Username/client id combination not found.")) {
                            errorMessage("이메일 주소와 일치하는 회원이 없습니다.")
                        }
                    }
                })
        }


        // 비밀번호 재설정 버튼
        new_paw_button.setOnClickListener {
            // 인증코드, 비밀번호 재설정
            val paw_code_name = findViewById<View>(R.id.paw_code_name) as EditText
            val new_paw_name = findViewById<View>(R.id.new_paw_name) as EditText
            val CONFIRMATION_CODE = paw_code_name.text.toString()
            val NEW_PASSWORD_HERE = new_paw_name.text.toString()
            AWSMobileClient.getInstance().confirmForgotPassword(
                NEW_PASSWORD_HERE,
                CONFIRMATION_CODE,
                object :
                    Callback<ForgotPasswordResult> {
                    override fun onResult(result: ForgotPasswordResult) {
                        runOnUiThread {
                            Log.d(TAG, "forgot password state: " + result.state)
                            if (result.state == ForgotPasswordState.DONE) {

                                // 비밀번호가 재설정 되었스면 로그인 창으로 이동
                                Toast.makeText(applicationContext, "성공적으로 비밀번호가 재설정 되었습니다.", Toast.LENGTH_SHORT).show()
                                val i = Intent(this@ForgotActivity, AuthActivity::class.java)
                                startActivity(i)
                                finish()
                            } else {
                                Log.e(TAG, "un-supported forgot password state")
                            }
                        }
                    }

                    override fun onError(e: Exception) {
                        Log.e(TAG, "forgot password error", e)
                        when {
                            e.message!!.contains(" Value '' at 'confirmationCode' failed to satisfy constraint") -> {
                                errorMessage("인증 코드를 입력해주세요.")
                            }
                            e.message!!.contains("Invalid verification code provided, please try again.") -> {
                                errorMessage("인증 코드를 다시 확인해주세요.")
                            }
                            e.message!!.contains("Value at 'password' failed to satisfy constraint") -> {
                                errorMessage("비밀번호는 8자 이상이어야 하며 특수 문자를 반드시 포함해야 합니다.")
                            }
                            e.message!!.contains("Password did not conform with policy") -> {
                                errorMessage("비밀번호는 8자 이상이어야 하며 특수 문자를 반드시 포함해야 합니다.")
                            }
                        }
                    }
                })
        }
    }

    override fun onBackPressed() {
        val i = Intent(this@ForgotActivity, AuthActivity::class.java)
        startActivity(i)
        finish()
    }

    // 에러 메시지
    fun errorMessage(message: String?) {
        val mHandler = Handler(Looper.getMainLooper())
        mHandler.post { Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show() }
    }
}

activity_forgot.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    tools:context=".OkActivity"
    android:orientation="vertical"
    android:gravity="center">

    <TextView
        android:id="@+id/ok_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="비밀번호를 잊어버리셨나요?\n
        인증 메일이 가입했던 이메일 주소로 전송됩니다!\n
        인증 코드 입력 후 비밀번호를 재설정 해주세요!"
        android:textSize="16dp"
        android:textStyle="bold" />

    <LinearLayout

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        >

        <TextView
            android:id="@+id/paw_signUpUsername_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="이메일 주소"
            android:textSize="16dp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/paw_signUpUsername"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10"
            android:inputType="text" />


    </LinearLayout>

    <Button
        android:id="@+id/code_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:text="인증 코드 발송" />


    <LinearLayout

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        >

        <TextView
            android:id="@+id/paw_code_name_text"
            android:layout_width="90dp"
            android:layout_height="30dp"
            android:text="인증 코드"
            android:textSize="16dp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/paw_code_name"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10"
            android:inputType="text" />




    </LinearLayout>
    <LinearLayout

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        >

        <TextView
            android:id="@+id/new_paw_name_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="비밀번호 재설정"
            android:textSize="16dp"
            android:textStyle="bold" />

        <EditText
            android:id="@+id/new_paw_name"
            android:layout_width="300dp"
            android:layout_height="50dp"
            android:ems="10"
            android:inputType="text" />



    </LinearLayout>



    <Button
        android:id="@+id/new_paw_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:text="확인" />


</LinearLayout>

위 코드를 모두 작성했다면 mainfests -> AndroidMainfest.xml에 들어가 처음 화면을 로그인 화면으로 설정하고 스택이 쌓이지 않게 하기 위해 noHistory를 true로 바꿔준다.

AndroidMainfest.xml

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AWSKotlin">
        <activity android:name=".SignUpActivity">

        </activity>
        <activity android:name=".OkActivity" />
        <activity android:name=".ForgotActivity" />
        <activity android:name=".MainActivity" />
        <activity android:name=".AuthActivity"
            android:noHistory="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

주석을 잘 확인하면서 위 모든 코드를 작성하면 다음 결과 영상과 같은 결과를 얻을 수 있다.

<결과 영상>

Java를 통한 aws 코드는 다음 링크를 통해 확인할 수 있다.

 

FreeDom

한칸 한칸

fre2-dom.tistory.com

github

 

GitHub - junjange/aws-Learning: aws 학습

aws 학습. Contribute to junjange/aws-Learning development by creating an account on GitHub.

github.com