/
PhoneAuthActivity.kt
202 lines (186 loc) · 9.24 KB
/
PhoneAuthActivity.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package com.mtjin.envmate.views.sign_up.phone_auth
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import com.google.firebase.FirebaseException
import com.google.firebase.FirebaseTooManyRequestsException
import com.google.firebase.auth.*
import com.google.firebase.auth.ktx.auth
import com.google.firebase.ktx.Firebase
import com.mtjin.envmate.R
import com.mtjin.envmate.base.BaseActivity
import com.mtjin.envmate.databinding.ActivityPhoneAuthBinding
import com.mtjin.envmate.utils.TAG
import com.mtjin.envmate.utils.UserInfo
import com.mtjin.envmate.views.sign_up.user_info.UserInfoActivity
import dagger.hilt.android.AndroidEntryPoint
import java.util.concurrent.TimeUnit
@AndroidEntryPoint
class PhoneAuthActivity : BaseActivity<ActivityPhoneAuthBinding>(R.layout.activity_phone_auth) {
private lateinit var auth: FirebaseAuth
private var storedVerificationId = ""
private var resendToken: PhoneAuthProvider.ForceResendingToken? = null
private val viewModel: PhoneAuthViewModel by viewModels()
private val callbacks by lazy {
object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
// 번호인증 혹은 기타 다른 인증(구글로그인, 이메일로그인 등) 끝난 상태
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
// This callback will be invoked in two situations:
// 1 - Instant verification. In some cases the phone number can be instantly
// verified without needing to send or enter a verification code.
// 2 - Auto-retrieval. On some devices Google Play services can automatically
// detect the incoming verification SMS and perform verification without
// user action.
showToast("인증코드가 전송되었습니다. 90초 이내에 입력해주세요 :)")
UserInfo.phoneAuthNum = credential.smsCode.toString()
binding.phoneAuthEtAuthNum.setText(credential.smsCode.toString())
binding.phoneAuthEtAuthNum.isEnabled = false
Handler(Looper.getMainLooper()).postDelayed({
verifyPhoneNumberWithCode(credential)
}, 1000)
}
// 번호인증 실패 상태
override fun onVerificationFailed(e: FirebaseException) {
// This callback is invoked in an invalid request for verification is made,
// for instance if the the phone number format is not valid.
Log.w(TAG, "onVerificationFailed", e)
if (e is FirebaseAuthInvalidCredentialsException) {
// Invalid request
} else if (e is FirebaseTooManyRequestsException) {
// The SMS quota for the project has been exceeded
}
showToast("인증실패")
}
// 전화번호는 확인 되었으나 인증코드를 입력해야 하는 상태
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
// The SMS verification code has been sent to the provided phone number, we
// now need to ask the user to enter the code and then construct a credential
// by combining the code with a verification ID.
Log.d(TAG, "onCodeSent:$verificationId")
// Save verification ID and resending token so we can use them later
storedVerificationId = verificationId // verificationId 와 전화번호인증코드 매칭해서 인증하는데 사용예정
resendToken = token
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize Firebase Auth
auth = Firebase.auth
binding.vm = viewModel
initViewModelCallback()
}
private fun initViewModelCallback() {
with(viewModel) {
requestPhoneAuth.observe(this@PhoneAuthActivity, Observer { // 인증번호 요청
UserInfo.tel = viewModel.etPhoneNum.value.toString() // 전화번호 저장
if (it) {
startPhoneNumberVerification(
"+82" + viewModel.etPhoneNum.value.toString().substring(1)
)
} else {
showToast("전화번호를 입력해주세요")
}
})
requestResendPhoneAuth.observe(this@PhoneAuthActivity, Observer { // 인증번호 재요청
if (it) {
resendVerificationCode(
"+82" + viewModel.etPhoneNum.value.toString().substring(1)
, resendToken
)
} else {
showToast("전화번호를 입력해주세요")
}
})
authComplete.observe(this@PhoneAuthActivity, Observer { // 인증완료 버튼 클릭 시
// 휴대폰 인증번호로 인증 및 로그인 실행
// onCodeSent() 에서 받은 vertificationID 와 문자메시지로 전송한 인증코드값으로 Credintial 만든 후 인증 시도
try {
val phoneCredential =
PhoneAuthProvider.getCredential(
storedVerificationId,
viewModel.etAuthNum.value!!
)
verifyPhoneNumberWithCode(phoneCredential)
} catch (e: Exception) {
Log.d(TAG, e.toString())
}
})
}
}
// 전화번호 인증코드 요청
private fun startPhoneNumberVerification(phoneNumber: String) {
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(phoneNumber) // Phone number to verify
.setTimeout(90L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
binding.phoneAuthBtnAuth.run {
text = "재전송"
setTextColor(
ContextCompat.getColor(
this@PhoneAuthActivity, R.color.dark_gray_333333
)
)
background = ContextCompat.getDrawable(
this@PhoneAuthActivity, R.drawable.bg_btn_stroke_dark_gray_333333_radius_8dp
)
}
}
// 전화번호 인증코드 재요청
private fun resendVerificationCode(
phoneNumber: String,
token: PhoneAuthProvider.ForceResendingToken?
) {
val optionsBuilder = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(phoneNumber) // Phone number to verify
.setTimeout(90L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
if (token != null) {
optionsBuilder.setForceResendingToken(token) // callback's ForceResendingToken
}
PhoneAuthProvider.verifyPhoneNumber(optionsBuilder.build())
}
// 전화번호 인증 실행 (onCodeSent() 에서 받은 vertificationID 와
// 문자로 받은 인증코드로 생성한 PhoneAuthCredential 사용)
private fun verifyPhoneNumberWithCode(phoneAuthCredential: PhoneAuthCredential) {
UserInfo.tel = binding.phoneAuthEtPhoneNum.text.toString()
if (UserInfo.tel.isNotBlank() && UserInfo.phoneAuthNum.isNotBlank() &&
(UserInfo.tel == binding.phoneAuthEtPhoneNum.text.toString() && UserInfo.phoneAuthNum == binding.phoneAuthEtAuthNum.text.toString())
) { // 이전에 인증한 번호와 인증번호인 경우
showToast("인증 성공")
UserInfo.tel = binding.phoneAuthEtPhoneNum.text.toString()
startActivity(Intent(this@PhoneAuthActivity, UserInfoActivity::class.java))
return
}
Firebase.auth.signInWithCredential(phoneAuthCredential)
.addOnCompleteListener(this@PhoneAuthActivity) { task ->
if (task.isSuccessful) {
showToast("인증 성공")
UserInfo.tel = binding.phoneAuthEtPhoneNum.text.toString()
binding.phoneAuthEtAuthNum.isEnabled = true
startActivity(
Intent(this@PhoneAuthActivity, UserInfoActivity::class.java)
)
} else {
binding.phoneAuthTvAuthNum.text =
getString(R.string.auth_num_wrong_text)
binding.phoneAuthTvAuthNum.setTextColor(
ContextCompat.getColor(this@PhoneAuthActivity, R.color.red_FF5050)
)
binding.phoneAuthEtAuthNum.isEnabled = true
}
}
}
}