简体   繁体   中英

Phone authentication with firebase and flutter

I'm writing a flutter app that using phone authentication. I am runing the app currently on iPhone 12 simulator and when I testing the app and implement the phone number I am not receiving the 6 digit code from firebase as planed. I Think is because one of those mention resons.

    1. Firebase can't send the code to the simulator with fake number.
    1. I need to change some settings on firebase/flutter project so it will work as expected.
    1. I need to send the phone number with the area code as well.
    1. my code is wrong or not doing what I want it to do.

(I don't have an apple developer account yet, so I gave a test number and code to firebase so when I will put the fake number I will still get the code to the app (not as push notification)).

Some dots of the app:

I have no problem to test the app on real device if needed.
I don't need to get the push notification right now, I can just print the verification code to the console so I will see that the code work.
I want to start the verification process right after I sent the phone number to this page (verification page)
right now I am using a full number without the area code.

I can use a fake number for the simulator? or I need a real one?.

Thank you, and hope you can help e with my problem.

this is my code (only the verification part):

// imports are here

enum Status { waiting, error }

class VerificationCode extends StatefulWidget {
  const VerificationCode({Key? key, this.number}) : super(key: key);
  final number;
  @override
  _VerificationCodeState createState() => _VerificationCodeState(number);
}

class _VerificationCodeState extends State<VerificationCode> {
  late final phoneNumber;
  final _verKey = GlobalKey<FormState>();
  late String _verCode;
  late double _formHeight;
  final FirebaseAuth _auth = FirebaseAuth.instance;
  var _verificationId;
  var _status = Status.waiting;
  _VerificationCodeState(this.phoneNumber); // storing the phone number from other page

  @override
  void initState() {
    super.initState();
    _verifyPhoneNumber();
  }

  Future _verifyPhoneNumber() async {
    _auth.verifyPhoneNumber(
        phoneNumber: phoneNumber,
        verificationCompleted: (phonesAuthCredentials) async {},
        verificationFailed: (verificationFailed) async {},
        codeSent: (verificationId, reseningToken) async {
          setState(() {
            _verificationId = verificationId;
            print(_verificationId); // here I am printing the opt code so I will know what it is to use it
          });
        },
        codeAutoRetrievalTimeout: (verificationId) async {});
  }

  Future _sendCodeToFirebase({String? code}) async {
    if (_verificationId != null) {
      var credential = PhoneAuthProvider.credential(
        verificationId: _verificationId,
        smsCode: code!,
      );

      await _auth
          .signInWithCredential(credential)
          .then((value) {
            print("auth complete!");
          })
          .whenComplete(() {})
          .onError((error, stackTrace) {
            setState(() {
              _verKey.currentState!.reset();
              _status = Status.error;
            });
          });
    }
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    if (size.height <= 736) {
      _formHeight = (size.height * .05) + 6;
    } else {
      _formHeight = size.height * .048;
    }
    return Scaffold(
      body: SafeArea(
        child: GestureDetector(
          onTap: () => FocusScope.of(context).requestFocus(
            FocusNode(),
          ),
          child: SingleChildScrollView(
            child: ConstrainedBox(
              constraints: BoxConstraints(
                minHeight: size.height - 90,
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Stack(
                    alignment: Alignment.topLeft,
                    children: [
                      GestureDetector(
                        onTap: () {
                          Navigator.pop(context);
                        },
                        child: Padding(
                          padding: EdgeInsets.only(
                            top: size.height * .006,
                            left: size.width * .03,
                          ),
                          child: SvgPicture.asset(
                            "assets/arrow-back.svg",
                          ),
                        ),
                      ),
                    ],
                  ),
                  Padding(
                    padding: EdgeInsets.only(
                      top: size.height * .18,
                    ),
                    child: Center(
                      child: Text(
                        "AppName",
                        style: TextStyle(
                          fontSize: size.width * .096,
                          letterSpacing: size.width * .026,
                          fontWeight: FontWeight.w300,
                        ),
                      ),
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.only(top: size.height * .015),
                    child: Center(
                      child: Container(
                        margin: EdgeInsets.symmetric(
                          horizontal: size.width * .045,
                        ),
                        height: _formHeight,
                        child: Form(
                          key: _verKey,
                          child: TextFormField(
                            style: TextStyle(
                              fontSize: size.width * .035,
                            ),
                            decoration: InputDecoration(
                              counterText: "",
                              contentPadding:
                                  const EdgeInsets.fromLTRB(0, 10, 0, 0),
                              hintText: 'Verification Code',
                              enabledBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(7.0),
                                borderSide: const BorderSide(
                                  color: Colors.black,
                                  width: 1.25,
                                ),
                              ),
                              focusedBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(7.0),
                                borderSide: const BorderSide(
                                  color: Colors.black,
                                  width: 1.5,
                                ),
                              ),
                            ),
                            autofocus: false,
                            keyboardType: TextInputType.number,
                            cursorColor: Colors.black,
                            textAlign: TextAlign.center,
                            onChanged: (input) async {
                              if (input.length == 6) {
                                _verCode = input;
                                _sendCodeToFirebase(code: _verCode);
                              }
                            },
                            maxLength: 6,
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Firebase Phone Authentication on iOS requires some setup steps as mentioned in the docs . The step where it mentions you need to enable push notifications is required to verify that the request is coming from your app, it's called " Silent APNs notifications " because it happens silently without the user being aware of it, but in case of testing, the reCAPTCHA verification is used, read more on this step in the official Firebase iOS docs .

However, for the sake of testing on a simulator , you can indeed use a fake number and an SMS code that you have defined in Firebase console under Phone Authentication sign-in method.

First, you will need to setup reCAPTCHA verification for iOS as required by the Firebase SDK.

Second, add testing numbers testing Phone Auth locally :

  1. On the Firebase Console, select the "Phone" authentication provider and click on the "Phone numbers for testing" dropdown.
  2. Enter a new phone number (eg +44 7444 555666) and a test code (eg 123456).

Note the following on adding test numbers:

  1. Once you have added a number to your test list in Firebase Console, you won't receive SMS codes on them even they were real, you can use the code you already defined in the console.
  2. If you already have a registered account using the same phone number you're trying to add to test, it will give an error saying it can't be added, make sure to remove the account associated with the number or choose another one.

As for the format of phone numbers accepted by Firebase, it must have the country code, and follows the E.164 standard, starts with + followed by country code followed by the phone number.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM