Home > Back-end >  Phone OTP by using Kotlin in Fragment
Phone OTP by using Kotlin in Fragment

Time:02-20

Thanks for reading this post. I am currently implementing phone OTP for my app in Kotlin in fragment. Since there is no resource available for Fragment and mostly for Activity, therefore, I am applying Activity OTP into my fragment, and as expected, it is crashed once I am inputting a mobile number there and enter login button. It is intended to go to OTP activity once the login button is pressed and mobile number is inserted.

Can you find why it is crashed once from my code below? Thank you so much.

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)
                }
            }
    }
}

By the way this is the original Activity source code: https://blog.codestormx.in/#/blog/Surya VMDS#OAZIadP0VivRQTzAuwrb

Here is the crash log:

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$lambda$8agyy8FyIIE4Tmrzi_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.access$3800(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

CodePudding user response:

lateinit var auth: FirebaseAuth

the auth variable is not initialized, when you call the sendVerificationcode() method,

PhoneAuthOptions.newBuilder(auth)

the auth is null, hence the UninitializedPropertyAccessException

you can fix this by initializing auth variable onCreate or 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
}
  • Related