Chirag
Chirag

Reputation: 98

Using Firebase phone authentication inside Fragment android

I am making an android app where the only user sign in and register method is via phone authentication. I'm having a single activity and making use of fragments.

I want to add firebase phone authentication inside the SignInFragment and make use of Firebase PhoneAuthProvider.However, this is only for activities I suppose, because I tried implementing inside my fragment and my app was crashing.

This is the code of SignInFragment.java

package com.example.XX;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.FirebaseException;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

public class SignInFragment extends Fragment {

    private static final String TAG ="INSIDE_SIGN_IN_FRAGMENT" ;
    FirebaseAuth mAuth;
    EditText xPhone;
    EditText xOTP;
    String codeSent;

    public SignInFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_sign_in, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Button getOTP=view.findViewById(R.id.button_xOTP);
        Button submitButton=view.findViewById(R.id.signInbutton);
        xPhone=view.findViewById(R.id.editText_xMobile);
        xOTP=view.findViewById(R.id.editText_xOTP);

        mAuth=FirebaseAuth.getInstance();




        getOTP.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendVerificationCode();
            }
        });

        submitButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                verifyOTP();
            }
        });
    }

    private void verifyOTP(){
        String tOTP=xOTP.getText().toString().trim();

        if(tOTP.isEmpty()){
            xOTP.setError("OTP is required!");
            xOTP.requestFocus();
            return;
        }

        if(tOTP.length()<6){
            xOTP.setError("Please enter a valid OTP!");
            xOTP.requestFocus();
            return;
        }
        PhoneAuthCredential credential = PhoneAuthProvider.getCredential(codeSent, tOTP);
        signInWithPhoneAuthCredential(credential);
    }

    private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener((Executor) this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {
                            // Sign in success, update UI with the signed-in user's information
                            Log.d(TAG, "signInWithCredential:success");

                            FirebaseUser user = task.getResult().getUser();
                            // ...
                        } else {
                            // Sign in failed, display a message and update the UI
                            Log.w(TAG, "signInWithCredential:failure", task.getException());
                            if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                                // The verification code entered was invalid
                            }
                        }
                    }
                });
    }

    private void sendVerificationCode() {

        String xMobileNumber=xPhone.getText().toString().trim();

        if(xMobileNumber.isEmpty()){
            xPhone.setError("Phone number is required!");
            xPhone.requestFocus();
            return;
        }

        if(xMobileNumber.length()<10){
            xPhone.setError("Please enter a valid phone number!");
            xPhone.requestFocus();
            return;
        }
        PhoneAuthProvider.getInstance().verifyPhoneNumber(
                xMobileNumber,        // Phone number to verify
                60,                 // Timeout duration
                TimeUnit.SECONDS,   // Unit of timeout
                (Executor) this,               // Activity (for callback binding) //NOT SURE ABOUT THIS
                mCallbacks);        // OnVerificationStateChangedCallbacks

    }

    PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks=new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
        @Override
        public void onVerificationCompleted(@NonNull PhoneAuthCredential phoneAuthCredential) {

        }

        @Override
        public void onVerificationFailed(@NonNull FirebaseException e) {

        }

        @Override
        public void onCodeSent(@NonNull String s, @NonNull PhoneAuthProvider.ForceResendingToken forceResendingToken) {
            super.onCodeSent(s, forceResendingToken);
            codeSent=s;
        }
    };


}

My Logcat

LOGCAT:2020-06-10 03:59:44.148 16491-16491/com.example.XX
 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.XX, PID: 16491
    java.lang.ClassCastException: com.example.XX.SignInFragment cannot be cast to java.util.concurrent.Executor
        at com.example.XX.SignInFragment.sendVerificationCode(SignInFragment.java:132)
        at com.example.XX.SignInFragment.access$000(SignInFragment.java:29)
        at com.example.XX.SignInFragment$1.onClick(SignInFragment.java:65)
        at android.view.View.performClick(View.java:7201)
        at android.view.View.performClickInternal(View.java:7170)
        at android.view.View.access$3500(View.java:806)
        at android.view.View$PerformClick.run(View.java:27582)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7695)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

I know the problem is at the executor portion, it was suggested by the IDE to make use of executor at two places. Maybe the PhoneAuth method is not for fragments. Can anyone review this or tell an alternate way to implement Firebase Phone Authentication inside a Fragment ONLY.

Upvotes: 1

Views: 2042

Answers (1)

Marsad
Marsad

Reputation: 921

this keyword is used in activity.

In fragment use getActivity() instead of this

Replace

 PhoneAuthProvider.getInstance().verifyPhoneNumber(
                xMobileNumber,        // Phone number to verify
                60,                   // Timeout duration
                TimeUnit.SECONDS,     // Unit of timeout
                (Executor) this,      // Activity (for callback binding)
                mCallbacks);          // OnVerificationStateChangedCallbacks

 }

with

 PhoneAuthProvider.getInstance().verifyPhoneNumber(
                xMobileNumber,        // Phone number to verify
                60,                   // Timeout duration
                TimeUnit.SECONDS,     // Unit of timeout
                getActivity(),        // Activity (for callback binding)
                mCallbacks);          // OnVerificationStateChangedCallbacks

 }

UPDATE

To avoid app crash check:

if (codeSent == null || TextUtils.isEmpty(codeSent)) {
    Toast.makeText(this, "Please wait until code received", Toast.LENGTH_SHORT).show();

    return;
}

PhoneAuthCredential credential = PhoneAuthProvider.getCredential(codeSent, tOTP);

signInWithPhoneAuthCredential(credential);

Upvotes: 2

Related Questions