Flutter Firebase phone auth SMS message with OTP not being received

79 Views Asked by At

I'm facing issues with the phone authentication process in my Flutter app. Despite following the phone auth documentation, configuring SHA-1 and SHA-256 fingerprints, and enabling phone auth in Firebase, I'm not receiving the SMS message containing the OTP.

Here is my code :

-> Login screen

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:google_maps/bussiness_logic/cubit/phone_auth_cubit/phone_auth_cubit.dart';
import 'package:google_maps/constants/strings.dart';
import 'package:google_maps/functions.dart';
import 'package:google_maps/presentation/widgets/intro_text.dart';
import 'package:google_maps/presentation/widgets/custom_button.dart';
import 'package:google_maps/presentation/widgets/phone_form_field.dart';

class LoginScreenBody extends StatelessWidget {
  final GlobalKey<FormState> _phoneFormKey = GlobalKey<FormState>();
  TextEditingController phoneFieldController = TextEditingController();

  LoginScreenBody({
    super.key,
  });

  PhoneAuthCubit phoneAuthCubit = PhoneAuthCubit();

  @override
  Widget build(BuildContext context) {
    return BlocProvider<PhoneAuthCubit>(
      create: (context) => phoneAuthCubit,
      child: BlocListener<PhoneAuthCubit, PhoneAuthState>(
        listenWhen: (previous, current) => previous != current,
        listener: (context, state) {
          if (state is LoadingState) {
            showProgressIndicator(context);
          } else if (state is ErrorState) {
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text(state.errorMsg),
              backgroundColor: Colors.black,
              duration: const Duration(seconds: 15),
            ));
          } else if (state is PhoneNumberSubmitedState) {
            Navigator.pop(context);
            GoRouter.of(context)
                .push(Strings.kOtpView, extra: phoneFieldController.text);
          } else if (state is ExitLoadingState) {
            Navigator.pop(context);
          }
        },
        child: Form(
          key: _phoneFormKey,
          child: Padding(
            padding: const EdgeInsets.all(10.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                const IntroText(),
                const SizedBox(
                  height: 90,
                ),
                PhoneFormField(
                  phoneFieldController: phoneFieldController,
                ),
                const SizedBox(
                  height: 60,
                ),
                CustomButton(
                  buttonTextValue: "Next",
                  onPressedAction: () {
                    phoneAuthCubit.tapNextButton(
                      context,
                      _phoneFormKey,
                      phoneFieldController,
                    );
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

-> OTP screen

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:google_maps/bussiness_logic/cubit/phone_auth_cubit/phone_auth_cubit.dart';
import 'package:google_maps/constants/strings.dart';
import 'package:google_maps/functions.dart';
import 'package:google_maps/presentation/widgets/custom_button.dart';
import 'package:google_maps/presentation/widgets/otp_texts.dart';
import 'package:google_maps/presentation/widgets/pin_code_digits.dart';

class OtpScreenBody extends StatelessWidget {
  OtpScreenBody({super.key, required this.phoneNumber});

  PhoneAuthCubit phoneAuthCubit = PhoneAuthCubit();
  final String phoneNumber;

  late String otpCode;

  @override
  Widget build(BuildContext context) {
    return BlocProvider<PhoneAuthCubit>(
      create: (context) => phoneAuthCubit,
      child: BlocListener<PhoneAuthCubit, PhoneAuthState>(
        listenWhen: (previous, current) => previous != current,
        listener: (context, state) {
          if (state is LoadingState) {
            showProgressIndicator(context);
          } else if (state is ErrorState) {
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text(state.errorMsg),
              backgroundColor: Colors.black,
              duration: const Duration(seconds: 5),
            ));
          } else if (state is OtpVerifiedState) {
            GoRouter.of(context).pushReplacementNamed(Strings.kMapScreen);
          }
        },
        child: Padding(
          padding: const EdgeInsets.all(10.0),
          child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                OtpTexts(
                  phoneNumber: phoneNumber,
                ),
                const SizedBox(
                  height: 88,
                ),
                PinCodeDigits(phoneAuthCubit: phoneAuthCubit),
                const SizedBox(
                  height: 60,
                ),
                CustomButton(
                  buttonTextValue: 'Submit',
                  onPressedAction: () {
                    phoneAuthCubit.tapSubmitButton();
                  },
                )
              ]),
        ),
      ),
    );
  }
}
import 'package:flutter/material.dart';
import 'package:google_maps/constants/my_colors.dart';

class OtpTexts extends StatelessWidget {
  const OtpTexts({super.key, required this.phoneNumber});

  final String phoneNumber;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const Text(
          'Verify your phone numberr',
          style: TextStyle(
            fontSize: 24,
            fontWeight: FontWeight.bold,
            color: Colors.black,
          ),
        ),
        const SizedBox(
          height: 20,
        ),
        Container(
          margin: const EdgeInsets.symmetric(horizontal: 2),
          child: RichText(
            text: TextSpan(
                text: 'Enter your 6 digits code numbers sent to you at ',
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.w500,
                  color: Colors.black,
                ),
                children: <TextSpan>[
                  TextSpan(
                      text: '+2$phoneNumber',
                      style:
                          const TextStyle(color: MyColors.blue, fontSize: 16))
                ]),
          ),
        ),
      ],
    );
  }
}
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

part 'phone_auth_state.dart';

class PhoneAuthCubit extends Cubit<PhoneAuthState> {
  String verificationId = '';
  late String otpCode;
  final TextEditingController fieldOne = TextEditingController();
  final TextEditingController fieldTwo = TextEditingController();
  final TextEditingController fieldThree = TextEditingController();
  final TextEditingController fieldFour = TextEditingController();
  final TextEditingController fieldFive = TextEditingController();
  final TextEditingController fieldSex = TextEditingController();

  PhoneAuthCubit() : super(PhoneAuthInitial());

  Future<void> submitPhoneNumber(String phoneNumber) async {
    print(phoneNumber);
    emit(LoadingState());

    await FirebaseAuth.instance.verifyPhoneNumber(
      phoneNumber: '+2$phoneNumber',
      timeout: const Duration(seconds: 14),
      verificationCompleted: verificationCompleted,
      verificationFailed: verificationFailed,
      codeSent: codeSent,
      codeAutoRetrievalTimeout: codeAutoRetrievalTimeout,
    );
  }

  void verificationCompleted(PhoneAuthCredential credential) async {
    print('verificationCompleted');
    await signIn(credential);
  }

  void verificationFailed(FirebaseAuthException error) {
    print('verificationFailed : ${error.toString()}');
    emit(ErrorState(errorMsg: error.toString()));
  }

  void codeSent(String verificationId, int? resendToken) {
    print('codeSent');
    this.verificationId = verificationId;
    emit(PhoneNumberSubmitedState());
  }

  void codeAutoRetrievalTimeout(String verificationId) {
    print('codeAutoRetrievalTimeout');
  }

  Future<void> submitOTP(String otpCode) async {
    PhoneAuthCredential credential = PhoneAuthProvider.credential(
        verificationId: this.verificationId, smsCode: otpCode);

    await signIn(credential);
  }

  Future<void> signIn(PhoneAuthCredential credential) async {
    try {
      await FirebaseAuth.instance.signInWithCredential(credential);
      emit(OtpVerifiedState());
    } catch (error) {
      emit(ErrorState(errorMsg: error.toString()));
    }
  }

  Future<void> logOut() async {
    await FirebaseAuth.instance.signOut();
  }

  User getLoggedInUser() {
    User firebaseUser = FirebaseAuth.instance.currentUser!;
    return firebaseUser;
  }

  Future<void> tapNextButton(
      BuildContext context,
      GlobalKey<FormState> phoneFormKey,
      TextEditingController phoneController) async {
    emit(LoadingState());
    await Future.delayed(const Duration(seconds: 1));

    if (phoneFormKey.currentState!.validate()) {
      phoneFormKey.currentState!.save();
      submitPhoneNumber(phoneController.text);
      emit(
          PhoneNumberSubmitedState()); // fire bloc listener to handle that state
    } else {
      // entered unvalid phone number
      emit(ExitLoadingState());
    }
  }

  Future<void> tapSubmitButton() async {
    emit(LoadingState());

    if (fieldOne.text.isEmpty ||
        fieldTwo.text.isEmpty ||
        fieldThree.text.isEmpty ||
        fieldFour.text.isEmpty ||
        fieldFive.text.isEmpty ||
        fieldSex.text.isEmpty) {
      emit(ErrorState(errorMsg: "Please fill in all fields"));
      return;
    }

    otpCode = fieldOne.text +
        fieldTwo.text +
        fieldThree.text +
        fieldFour.text +
        fieldFive.text +
        fieldSex.text;

    submitOTP(otpCode);
  }
}`

loginBody --> where i enter the phone number .

log output:

Connecting to VM Service at ws://127.0.0.1:63570/wbNXq9n5oQ0=/ws
W/MIUIScout ANR( 5906): AnrScout only want msg within 20s, so stop here
D/MIUIScout ANR( 5906): get period history msg: (Current message:null)
D/MIUIScout ANR( 5906): get period history msg:execute time\>50ms (msgIndex=4seq=4 plan=١٣:٥٦:٥٤.١٦٥ late=53ms wall=118ms running=0ms h=android.app.ActivityThread$H w=159)
D/MIUIScout ANR( 5906): get period history msg:In recent 20s, total historyMsgCount=343
I/ple.google_map( 5906): Thread\[6,tid=5915,WaitingInMainSignalCatcherLoop,Thread\*=0xb400007cba832000,peer=0x12cc1768,"Signal Catcher"\]: reacting to signal 3
I/ple.google_map( 5906):
I/ple.google_map( 5906): Wrote stack traces to tombstoned
2
W/InputMethodManager( 5906): Ignoring showSoftInput() as view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F....ID 0,0-1080,2270 #1} is not served.
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus true
D/MIUIInput( 5906): \[KeyEvent\] ViewRootImpl KeyEvent { action=ACTION_UP, keyCode=KEYCODE_VOLUME_DOWN, scanCode=114, metaState=0, flags=0x8, repeatCount=0, eventTime=26582407, downTime=26582275, deviceId=2, source=0x101, displayId=-1 }
W/MIUIInput( 5906): AnrScout input event latency is 7119
W/MirrorManager( 5906): this model don't Support
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus false
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus true
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
I/flutter ( 5906): 01005355825
I/zzb     ( 5906): ForceRecaptchaFlow from phoneAuthOptions = false, ForceRecaptchaFlow from firebaseSettings = false
W/System  ( 5906): Ignoring header X-Firebase-Locale because its value was null.
2
D/InputMethodManager( 5906): showSoftInput() view=io.flutter.embedding.android.FlutterView{26421c9 VFE...... .F...... 0,0-1080,2270 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
D/InsetsController( 5906): show(ime(), fromIme=true)
I/AssistStructure( 5906): Flattened final assist data: 392 bytes, containing 1 windows, 3 views
D/InsetsController( 5906): show(ime(), fromIme=true)
I/PlayCore( 5906): UID: \[10261\]  PID: \[5906\] IntegrityService : requestIntegrityToken(IntegrityTokenRequest{nonce=7bXOSNhNlUgCWuHzy9mDBhQA9o0vfL5Z918aSxdmUDs, cloudProjectNumber=551503664846})
I/PlayCore( 5906): UID: \[10261\]  PID: \[5906\] IntegrityService : Initiate binding to the service.
I/PlayCore( 5906): UID: \[10261\]  PID: \[5906\] IntegrityService : ServiceConnectionImpl.onServiceConnected(ComponentInfo{com.android.vending/com.google.android.finsky.integrityservice.IntegrityService})
I/PlayCore( 5906): UID: \[10261\]  PID: \[5906\] IntegrityService : linkToDeath
I/PlayCore( 5906): UID: \[10261\]  PID: \[5906\] OnRequestIntegrityTokenCallback : onRequestIntegrityToken
I/PlayCore( 5906): UID: \[10261\]  PID: \[5906\] IntegrityService : Unbind from service.
W/System  ( 5906): Ignoring header X-Firebase-Locale because its value was null.
E/FirebaseAuth( 5906): \[SmsRetrieverHelper\] SMS verification code request failed: unknown status code: 18002 Invalid PlayIntegrity token; app not Recognized by Play Store.
D/FirebaseAuth( 5906): Re-triggering phone verification with Recaptcha flow forced for phone number +201005355825
I/zzb     ( 5906): ForceRecaptchaFlow from phoneAuthOptions = true, ForceRecaptchaFlow from firebaseSettings = false
D/IS_CTS_MODE( 5906): false
D/MULTI_WINDOW_SWITCH_ENABLED( 5906): false
D/DecorView\[\]( 5906): getWindowModeFromSystem  windowmode is 1
W/Activity( 5906): PerfMonitor: Slow Operation: Activity com.example.google_maps/com.google.firebase.auth.internal.RecaptchaActivity onResume took 666ms
W/System  ( 5906): Ignoring header X-Firebase-Locale because its value was null.
W/Looper  ( 5906): PerfMonitor looperActivity : package=com.example.google_maps/com.google.firebase.auth.internal.RecaptchaActivity time=0ms latency=687ms running=0ms  procState=-1  historyMsgCount=2 (msgIndex=2 wall=685ms seq=767 late=2ms h=android.app.ActivityThread$H w=159)
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus false
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus true
E/FirebaseAuth( 5906): \[GetAuthDomainTask\] Error getting project config. Failed with INVALID_CERT_HASH 400
E/zzb     ( 5906): Failed to get reCAPTCHA token with error \[There was an error while trying to get your package certificate hash.\]- calling backend without app verification
W/System  ( 5906): Ignoring header X-Firebase-Locale because its value was null.
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus false
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus true
E/FirebaseAuth( 5906): \[SmsRetrieverHelper\] SMS verification code request failed: unknown status code: 17093 null
I/flutter ( 5906): verificationFailed : \[firebase_auth/missing-client-identifier\] This request is missing a valid app identifier, meaning that Play Integrity checks, and reCAPTCHA checks were unsuccessful. Please try again, or check the logcat for more details.
D/DecorView\[\]( 5906): onWindowFocusChanged hasWindowFocus false
E/BLASTBufferQueue( 5906): \[ViewRootImpl\[MainActivity\]#0\](f:0,a:2) Applying pending transactions on dtor 1
W/ple.google_map( 5906): Cleared Reference was only reachable from finalizer (only reported once)
W/JavaBinder( 5906): BinderProxy is being destroyed but the application did not call unlinkToDeath to unlink all of its death recipients beforehand.  Releasing leaked death recipient: com.google.android.play.integrity.internal.n
I/BpBinder( 5906): onLastStrongRef automatically unlinking death recipients: \<uncached descriptor\>
W/System  ( 5906): A resource failed to call end
0

There are 0 best solutions below