Phone 在 Fragment 中使用 Kotlin 的 OTP
Phone OTP by using Kotlin in Fragment
感谢阅读本文 post。我目前正在片段中为我在 Kotlin 中的应用程序实施 phone OTP。由于没有资源可用于 Fragment,主要用于 Activity,因此,我将 Activity OTP 应用到我的片段中,正如预期的那样,一旦我在那里输入手机号码并输入登录名,它就会崩溃按钮。一旦按下登录按钮并插入手机号码,它就会转到 OTP activity。
你能从我下面的代码中找到它崩溃一次的原因吗?非常感谢。
package com.example.myApp
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.Toast
import com.example.myApp.databinding.FragmentLogInPhoneBinding
import com.google.firebase.FirebaseException
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.PhoneAuthCredential
import com.google.firebase.auth.PhoneAuthOptions
import com.google.firebase.auth.PhoneAuthProvider
import kotlinx.android.synthetic.main.fragment_log_in_phone.*
import java.util.concurrent.TimeUnit
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class LogInPhone : Fragment() {
private lateinit var binding: FragmentLogInPhoneBinding
lateinit var auth: FirebaseAuth
lateinit var storedVerificationId:String
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentLogInPhoneBinding.inflate(layoutInflater, container, false)
binding.loginButtonPhone.setOnClickListener {
login()
}
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
startActivity(Intent(getActivity()?.applicationContext, MainScreen::class.java))
getActivity()?.finish()
}
override fun onVerificationFailed(e: FirebaseException) {
Toast.makeText(getActivity()?.applicationContext, "Failed", Toast.LENGTH_LONG).show()
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
Log.d("TAG","onCodeSent:$verificationId")
storedVerificationId = verificationId
resendToken = token
var intent = Intent(getActivity()?.applicationContext,OTPVerificationPhone::class.java)
intent.putExtra("storedVerificationId",storedVerificationId)
startActivity(intent)
}
}
return binding.root
}
private fun login() {
var number=binding.loginPhoneFragment.text
if(!number.isNullOrEmpty()){
sendVerificationcode (number)
}else{
login_phone_fragment_layout.setError("Masukkan nomor ponsel anda")
}
}
private fun sendVerificationcode(number: Editable?) {
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(number.toString()) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this.requireActivity()) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
companion object {
fun newInstance(param1: String, param2: String) =
LogInPhone().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
顺便说一句,这是原始的 Activity 源代码:https://blog.codestormx.in/#/blog/Surya%20VMDS#OAZIadP0VivRQTzAuwrb
这是崩溃日志:
2022-02-15 15:13:40.592 7134-7134/com.example.myApp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myApp, PID: 7134
kotlin.UninitializedPropertyAccessException: lateinit property auth has not been initialized
at com.example.myApp.LogInPhone.getAuth(LogInPhone.kt:29)
at com.example.myApp.LogInPhone.sendVerificationcode(LogInPhone.kt:107)
at com.example.myApp.LogInPhone.login(LogInPhone.kt:101)
at com.example.myApp.LogInPhone.onCreateView$lambda-3(LogInPhone.kt:63)
at com.example.myApp.LogInPhone.$r8$lambdaagyy8FyIIE4Tmrzi_lrnbT4nrs(Unknown Source:0)
at com.example.myApp.LogInPhone$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7792)
at android.widget.TextView.performClick(TextView.java:16045)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1131)
at android.view.View.performClickInternal(View.java:7769)
at android.view.View.access00(View.java:910)
at android.view.View$PerformClick.run(View.java:30184)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8582)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1133)
2022-02-15 15:13:40.626 7134-7134/com.example.myApp I/Process: Sending signal. PID: 7134 SIG: 9
lateinit var auth: FirebaseAuth
auth变量未初始化,调用sendVerificationcode()方法时,
PhoneAuthOptions.newBuilder(auth)
auth 为空,因此出现 UninitializedPropertyAccessException
您可以通过初始化 auth 变量 onCreate 或 onCreateView 来解决这个问题
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
auth = FirebaseAuth.getInstance(); // initialized
}
感谢阅读本文 post。我目前正在片段中为我在 Kotlin 中的应用程序实施 phone OTP。由于没有资源可用于 Fragment,主要用于 Activity,因此,我将 Activity OTP 应用到我的片段中,正如预期的那样,一旦我在那里输入手机号码并输入登录名,它就会崩溃按钮。一旦按下登录按钮并插入手机号码,它就会转到 OTP activity。
你能从我下面的代码中找到它崩溃一次的原因吗?非常感谢。
package com.example.myApp
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.Toast
import com.example.myApp.databinding.FragmentLogInPhoneBinding
import com.google.firebase.FirebaseException
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.PhoneAuthCredential
import com.google.firebase.auth.PhoneAuthOptions
import com.google.firebase.auth.PhoneAuthProvider
import kotlinx.android.synthetic.main.fragment_log_in_phone.*
import java.util.concurrent.TimeUnit
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class LogInPhone : Fragment() {
private lateinit var binding: FragmentLogInPhoneBinding
lateinit var auth: FirebaseAuth
lateinit var storedVerificationId:String
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentLogInPhoneBinding.inflate(layoutInflater, container, false)
binding.loginButtonPhone.setOnClickListener {
login()
}
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
startActivity(Intent(getActivity()?.applicationContext, MainScreen::class.java))
getActivity()?.finish()
}
override fun onVerificationFailed(e: FirebaseException) {
Toast.makeText(getActivity()?.applicationContext, "Failed", Toast.LENGTH_LONG).show()
}
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken
) {
Log.d("TAG","onCodeSent:$verificationId")
storedVerificationId = verificationId
resendToken = token
var intent = Intent(getActivity()?.applicationContext,OTPVerificationPhone::class.java)
intent.putExtra("storedVerificationId",storedVerificationId)
startActivity(intent)
}
}
return binding.root
}
private fun login() {
var number=binding.loginPhoneFragment.text
if(!number.isNullOrEmpty()){
sendVerificationcode (number)
}else{
login_phone_fragment_layout.setError("Masukkan nomor ponsel anda")
}
}
private fun sendVerificationcode(number: Editable?) {
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(number.toString()) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(this.requireActivity()) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
companion object {
fun newInstance(param1: String, param2: String) =
LogInPhone().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
顺便说一句,这是原始的 Activity 源代码:https://blog.codestormx.in/#/blog/Surya%20VMDS#OAZIadP0VivRQTzAuwrb
这是崩溃日志:
2022-02-15 15:13:40.592 7134-7134/com.example.myApp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myApp, PID: 7134
kotlin.UninitializedPropertyAccessException: lateinit property auth has not been initialized
at com.example.myApp.LogInPhone.getAuth(LogInPhone.kt:29)
at com.example.myApp.LogInPhone.sendVerificationcode(LogInPhone.kt:107)
at com.example.myApp.LogInPhone.login(LogInPhone.kt:101)
at com.example.myApp.LogInPhone.onCreateView$lambda-3(LogInPhone.kt:63)
at com.example.myApp.LogInPhone.$r8$lambdaagyy8FyIIE4Tmrzi_lrnbT4nrs(Unknown Source:0)
at com.example.myApp.LogInPhone$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7792)
at android.widget.TextView.performClick(TextView.java:16045)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1131)
at android.view.View.performClickInternal(View.java:7769)
at android.view.View.access00(View.java:910)
at android.view.View$PerformClick.run(View.java:30184)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8582)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:563)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1133)
2022-02-15 15:13:40.626 7134-7134/com.example.myApp I/Process: Sending signal. PID: 7134 SIG: 9
lateinit var auth: FirebaseAuth
auth变量未初始化,调用sendVerificationcode()方法时,
PhoneAuthOptions.newBuilder(auth)
auth 为空,因此出现 UninitializedPropertyAccessException
您可以通过初始化 auth 变量 onCreate 或 onCreateView 来解决这个问题
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
auth = FirebaseAuth.getInstance(); // initialized
}