How to use Firebase Phone Authentication with flutter?

I am trying to make an app using flutter and firebase. I am using FirebaseAuth for signup and signin. I am taking mobile number and password as input and creating a dummy email with phone number and signing in with firebase auth signInWithEmailPassword. What I want to do is first time user signup I want to send otp to that number and if number verified than I want to register with that dummy email and password. Any Idea how to achieve that. I tried something but user is registering even if the otp is wrong.

 String email = '';
 String password = '';
 String name = '';
 String contact = '';
 String error = '';
 String smsCode = '';
 String verificationId;
 bool loading = false;

 Future<void> verifyPhone() async {
print('Inside verify phone');
final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verId) {
  this.verificationId = verId;
};

final PhoneCodeSent smsCodeSent = (String verId, [int forceCodeResend]) {
  this.verificationId = verId;
  print('Inside code sent');
  smsCodeDialog(context).then((value) {
    print('Signed in');
  });
};

final PhoneVerificationCompleted verifiedSuccess =
    (AuthCredential credential) {
  print('verified');
};

final PhoneVerificationFailed verificationFailed =
    (AuthException exception) {
  print('${exception.message}');
};

if (_formKey.currentState.validate()) {
  await FirebaseAuth.instance.verifyPhoneNumber(
    phoneNumber: '+91 ' + contact,
    timeout: const Duration(seconds: 10),
    verificationCompleted: verifiedSuccess,
    verificationFailed: verificationFailed,
    codeSent: smsCodeSent,
    codeAutoRetrievalTimeout: autoRetrieve,
  );
}
 }

 Future<bool> smsCodeDialog(BuildContext context) {
return showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) {
      return new AlertDialog(
        title: Text('Enter SMS Code'),
        content: TextField(
          onChanged: (value) {
            this.smsCode = value;
          },
        ),
        contentPadding: EdgeInsets.all(10),
        actions: <Widget>[
          TextButton(
              onPressed: () async {
                dynamic result =
                    await _auth.register(email, password, name, contact);
                if (result == null) {
                  Navigator.pop(context);
                  setState(() {
                    loading = false;
                    error = "Already registered or Invalid Details.";
                  });
                } else {
                  Navigator.pop(context);
                  Navigator.pushNamedAndRemoveUntil(
                      context, '/', (Route<dynamic> route) => false);
                }
              },
              child: Text('Register',
                  style: GoogleFonts.abhayaLibre(
                      textStyle: TextStyle(
                          fontSize: 24, color: Colors.green[900]))))
        ],
      );
    });
 }

On form submission I am calling verifyPhone method.

Upvotes: 0

Views: 4534

Answers (2)

Adeel Nazim
Adeel Nazim

Reputation: 724

Here is the complete Answer to How to use Firebase Phone Authentication with flutter?

  • Enable Phone Number sign-in for your Firebase project.

Login / SignUp Screen

import 'package:flutter/material.dart';
import 'package: ../auth_provider.dart';
import 'package:provider/provider.dart';

class LoginScreen extends StatefulWidget {
  static const String id = 'Login-Screen';
  const LoginScreen({key}) : super(key: key);

  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {

  TextEditingController _phoneNumberController = TextEditingController();
  bool _validPhoneNumber = false;

  @override
  Widget build(BuildContext context) {
    final auth = Provider.of<AuthProvider>(context);
    return Scaffold(
     // resizeToAvoidBottomInset: false,
      body: SafeArea(
        child: Container(
          child: Padding(
            padding: const EdgeInsets.all(15.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Visibility(
                  visible: '${auth.error}Please Try Again' =='Invalid Code'? true:false,
                  child: Container(
                    child: Column(
                      children: [
                        Text(auth.error,
                          style: TextStyle(
                            color: Colors.red,
                            fontSize: 15,
                          ),
                        ),
                        SizedBox(height: 5,),
                      ],
                    ),
                  ),
                ),
                Text(
                  'Login',
                  style:
                  TextStyle(
                    fontWeight: FontWeight.bold,
                    fontSize: 25,
                  ),
                ), Text(
                  'Enter Your Phone Number',
                  style:
                  TextStyle(
                    fontWeight: FontWeight.bold,
                    fontSize: 15,
                  ),
                ),
                SizedBox(
                  height: 30,
                ),
                TextField(
                  style: TextStyle(color: Colors.black),
                  decoration: InputDecoration(
                    prefixText: '+92',
                    prefixStyle: TextStyle(color: Colors.black),
                    labelText: 'Enter Your Mobile Number',
                    labelStyle: TextStyle(
                        color: Colors.black,
                    ),
                  ),
                  autofocus: true,
                  keyboardType: TextInputType.phone,
                  maxLength: 11,
                  controller: _phoneNumberController,
                  onChanged: (value) {
                    if (value.length == 11) {
                      setState(() {
                        _validPhoneNumber = true;

                      });
                    } else {
                      setState(() {
                        _validPhoneNumber = false;
                      });
                    }
                  },
                ),
                SizedBox(
                  height: 10,
                ),
                Row(
                  children: [
                    Expanded(
                      child: AbsorbPointer(
                        absorbing: _validPhoneNumber ? false : true,
                        // ignore: deprecated_member_use
                        child: FlatButton(
                          onPressed: () {
                            String number =
                                '+92${_phoneNumberController.text}';
                            auth.verifyPhone(
                              context: context,
                              number: number,
                            ).then((value){
                              CircularProgressIndicator(
                                  valueColor: AlwaysStoppedAnimation<Color>(Colors.white)
                              );
                             // _phoneNumberController.clear();
                              setState(() {
                                auth.loading = false;
                              });
                            });
                          },
                          color: _validPhoneNumber
                              ? Colors.greenAccent
                              : Colors.grey,
                          child:
                          auth.loading ? CircularProgressIndicator(
                              valueColor: AlwaysStoppedAnimation<Color>(Colors.white)
                          ):
                          Text(
                            _validPhoneNumber
                                ? 'CONTINUE'
                                : 'ENTER PHONE NUMBER',
                            style: TextStyle(color: Colors.black),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Authentication codes

Future<void> verifyPhone({BuildContext context, String number}) async {
    this.loading = true;
    notifyListeners();
    final PhoneVerificationCompleted verificationCompleted =
        (PhoneAuthCredential credential) async {
      this.loading = false;
      notifyListeners();
      await _auth.signInWithCredential(credential);
    };

    final PhoneVerificationFailed verificationFailed =
        (FirebaseAuthException e) {
      this.loading = false;
      print(e.code);
      this.error = e.toString();
      notifyListeners();
    };

    final PhoneCodeSent smsOtpSend = (String verId, int resendToken) async {
      this.verificationId = verId;
      smsOtpDialog(context, number);

      //  smsOtpDialog(context, number);
    };

    try {
      _auth.verifyPhoneNumber(
        phoneNumber: number,
        verificationCompleted: verificationCompleted,
        verificationFailed: verificationFailed,
        codeSent: smsOtpSend,
        codeAutoRetrievalTimeout: (String verId) {
          this.verificationId = verId;
        },
      );
    } catch (e) {
      this.error = e.toString();
      this.loading = false;
      notifyListeners();
      print(e);
    }
  }

OPT Screen

Future<bool> smsOtpDialog(BuildContext context, String number) {
    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Column(
              children: [
                Text('Verification Code'),
                SizedBox(
                  height: 6,
                ),
                Text(
                  'Enter 6 digit Code received by SMS',
                  style: TextStyle(color: Colors.grey, fontSize: 12),
                )
              ],
            ),
            content: Container(
              height: 85,
              child: TextField(
                textAlign: TextAlign.center,
                keyboardType: TextInputType.number,
                maxLength: 6,
                onChanged: (value) {
                  this.smsOtp = value;
                },
              ),
            ),
            actions: [
              // ignore: deprecated_member_use
              FlatButton(
                onPressed: () async {
                  try {
                    PhoneAuthCredential phoneAuthCredential =
                        PhoneAuthProvider.credential(
                            verificationId: verificationId, smsCode: smsOtp);

                    final User user =
                        (await _auth.signInWithCredential(phoneAuthCredential))
                            .user;

                    if (user != null) {
                      this.loading = false;
                      notifyListeners();
                      _vendorServices.getVendorById(user.uid).then((snapShot) {
                        if (snapShot.exists) {
                          if (this.screen == 'Login') {
                            if(snapShot['address']!=null){
                              Navigator.pushReplacementNamed(context, HomeScreen.id);
                            }
                            Navigator.pushReplacementNamed(context, HomeScreen.id);
                          } else {
                            print(
                                '{$locationData.latitude} : $locationData.longitude}');
                            updateVendor(id: user.uid, number: user.phoneNumber, shopName: user.displayName);
                            Navigator.pushReplacementNamed(context, HomeScreen.id);
                          }
                        } else {
                          _createVendor(id: user.uid, number: user.phoneNumber, shopName: user.displayName);
                          Navigator.pushReplacementNamed(context, HomeScreen.id);
                        }
                      });
                    } else {
                      print('Login Failed');
                    }
                  } catch (e) {
                    this.error = 'Invalid Code';
                    notifyListeners();
                    print(e.toString());
                    Navigator.of(context).pop();
                  }
                },
                child:
                    Text('Done', style: TextStyle(color: Colors.greenAccent)),
              ),
            ],
          );
        }).whenComplete(() {
      this.loading = false;
      notifyListeners();
    });
  }

For more details check the official doc at https://firebase.google.com/docs/auth/android/phone-auth

Upvotes: 0

ahmetakil
ahmetakil

Reputation: 908

Future<bool> signIn() async {
try {
  final AuthCredential credential = PhoneAuthProvider.getCredential(
    verificationId: verificationId,
    smsCode: smsCode,
  );
  final AuthResult userResult =
      await _auth.signInWithCredential(credential);
  final FirebaseUser currentUser = await _auth.currentUser();

  final document =
      Firestore().collection("users").document(currentUser.uid);
  final documentSnapshot = await document.get();
  if (!documentSnapshot.exists) {
    await document.setData({
      "id": currentUser.uid,
      "number": phoneNumber,
    });
  }
  return true;
} catch (e) {
  return false;
}

}

  onPressed: () async {
                                      if (_smsController.text.isEmpty) {
                                        widget.scaffoldKey.currentState
                                            .showSnackBar(SnackBar(
                                          content: Text(
                                              "Please enter your SMS code"),
                                          duration: Duration(seconds: 2),
                                        ));
                                        return;
                                      }

                                      await _auth
                                          .currentUser()
                                          .then((user) async {
                                        await signIn()
                                            .then((bool isSignedIn) async {
                                          if (isSignedIn) {
                                            Navigator.of(context)
                                                .pushAndRemoveUntil();
                                          } else {
                                            widget.scaffoldKey.currentState
                                                .showSnackBar(SnackBar(
                                              content:
                                                  Text("Incorrect Code"),
                                              duration:
                                                  Duration(seconds: 2),
                                            ));
                                          }
                                        });
                                      });
                                    },

Here i can show you a minimal example that also uses firestore to store extra information for the user the onPressed is triggered whenever the SMS dialog's button is pressed

Upvotes: 0

Related Questions