'Auto detect firebase Phone Auth sms code in Flutter

Please read properly and then comment, hope this help full for software community.

I unable to auto detect firebase phone auth sms, when i test in android it's work without doing anything, but when i tried it in flutter sms not detected automatically, require manually type sms code, I did not find any documentation to do this process automatically. I wan't to know how to detect automatically that sms code from Firebase phone auth

Future<void> verifyPhone() async {

starTimer();
phoneNumber = contryCode+mobile_controller.text;

final PhoneCodeAutoRetrievalTimeout autoReRetrive = (String verId) {
  this.verificationId = verId;

};

final PhoneCodeSent smsCodesent = (String verId, [int forceCodeResent]) {
  this.verificationId = verId;


  pageController.animateToPage(2, duration: Duration(milliseconds: 300), curve: Curves.easeInBack);
  /*smsCodeDialog(context).then((value) {
    print("VERIFY PHONE SIGN IN");
  });
  */

};
final PhoneVerificationCompleted phoneVerificationCompleted =
    (PhoneAuthCredential creditional) {
  print("VERIFY PHONE AUTH SUCESS");
  this.mPhoneCreditional=creditional;
  //_controller.animateToPage(3, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
  loginIn(creditional);
};
final PhoneVerificationFailed phoneVerificationFailed =
    (FirebaseAuthException excepton) {
  Fluttertoast.showToast(
      msg: excepton.message,
      toastLength: Toast.LENGTH_LONG,
      gravity: ToastGravity.CENTER,
      timeInSecForIosWeb: 1,
      backgroundColor: Colors.red,
      textColor: Colors.white,
      fontSize: 16.0
  );
  print("VERIFY PHONE AUTH FAILED " + excepton.message);
};
FirebaseAuth mAuth=await FirebaseAuth.instance;
mAuth.setLanguageCode("en");
await mAuth.verifyPhoneNumber(
    phoneNumber: phoneNumber,
    timeout: const Duration(seconds: 45),
    verificationCompleted: phoneVerificationCompleted,
    verificationFailed: phoneVerificationFailed,
    codeSent: smsCodesent,
    codeAutoRetrievalTimeout: autoReRetrive);


}


Solution 1:[1]

  1. Make sure you have added the debugging, release, sha1, sha256 keys to your firebase project.

  2. Make sure you have enabled appcheck enabled on your firebase project.

  3. Make sure you have enabled the Android Device Verification api on your google cloud console.

The below code is slightly modified from the example code given in firebase auth plugin, for my projects the detecion is working well. Some devices may fail to detect the otp, but most of the devices will login automatically.

The code which detects the sms is highlighted in sendOtpFn()

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:projdebug/Widgets/Widgets.dart';

class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => LoginPageState();
}

class LoginPageState extends State<LoginPage> {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final _phoneNumberController = TextEditingController();
  final _smsController = TextEditingController();

  String _message = '';
  late String _verificationId;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(onPressed: () {
        setState(() {});
      }),
      body: Card(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Container(
                alignment: Alignment.center,
                child: const Text(
                  'Test sign in with phone number',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
              ),
              TextFormField(
                controller: _phoneNumberController,
                decoration: const InputDecoration(
                  labelText: 'Phone number (+x xxx-xxx-xxxx)',
                ),
                validator: (String? value) {
                  if (value!.isEmpty) {
                    return 'Phone number (+x xxx-xxx-xxxx)';
                  }
                  return null;
                },
              ),
              Container(
                padding: const EdgeInsets.symmetric(vertical: 16),
                alignment: Alignment.center,
                child: Button(
                  icon: Icons.send,
                  buttonColor: Colors.deepOrangeAccent[700]!,
                  text: 'Send otp',
                  onPressed: sendOtpFn,
                ),
              ),
              TextField(
                controller: _smsController,
                decoration:
                    const InputDecoration(labelText: 'Verification code'),
              ),
              Container(
                padding: const EdgeInsets.only(top: 16),
                alignment: Alignment.center,
                child: Button(
                  icon: Icons.done,
                  buttonColor: Colors.deepOrangeAccent[400]!,
                  onPressed: manualSignInFn,
                  text: 'Confirm otp',
                ),
              ),
              CrossFade(
                show: _auth.currentUser?.uid != null,
                child: Button(
                  icon: Icons.logout,
                  buttonColor: Colors.deepOrangeAccent[400]!,
                  onPressed: () async{
                    await _auth.signOut();
                    setState(() {});
                  },
                  text: 'LogOut',
                ),
              ),
              Visibility(
                visible: _message.isNotEmpty,
                child: Container(
                  alignment: Alignment.center,
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  child: Text(
                    _message,
                    style: const TextStyle(color: Colors.red),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }

  // Example code of how to verify phone number
  Future<void> sendOtpFn() async {
    setState(() {
      _message = '';
    });

///This is the code snippet which [detects the code from sms automatically]
    PhoneVerificationCompleted verificationCompleted =
        (PhoneAuthCredential phoneAuthCredential) async {
      setState(() {
        _message = phoneAuthCredential.smsCode ?? "";
        _smsController.text = _message;
      });
      await _auth.signInWithCredential(phoneAuthCredential);
      Widgets.showToast(
          'Phone number automatically verified and user signed in: $phoneAuthCredential');
          setState(() {});
    };

    PhoneVerificationFailed verificationFailed =
        (FirebaseAuthException authException) {
      setState(() {
        _message =
            'Phone number verification failed. Code: ${authException.code}. '
            'Message: ${authException.message}';
      });
    };

    PhoneCodeSent codeSent =
        (String verificationId, [int? forceResendingToken]) async {
      Widgets.showToast('Please check your phone for the verification code.');

      _verificationId = verificationId;
    };

    PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
        (String verificationId) {
      _verificationId = verificationId;
    };

    try {
      await _auth.verifyPhoneNumber(
          phoneNumber: _phoneNumberController.text,
          timeout: const Duration(seconds: 120),
          verificationCompleted: verificationCompleted,
          verificationFailed: verificationFailed,
          codeSent: codeSent,
          codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
    } catch (e) {
      Widgets.showToast('Time out to Verify Phone Number: $e');
    }
  }

  ///Code which will be executed only when a confirm otp button is pressed, ie both phoneNumber & otp is typed by the user manually.
  Future<void> manualSignInFn() async {
    try {
      final PhoneAuthCredential credential = PhoneAuthProvider.credential(
        verificationId: _verificationId,
        smsCode: _smsController.text,
      );
      final User user = (await _auth.signInWithCredential(credential)).user!;
      Widgets.showToast('Successfully signed in UID: ${user.uid}');
    } catch (e) {
      print(e);
      Widgets.showToast('Failed to sign in');
    }
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1