使用 firebase 和 flutter 进行电话身份验证

roe*_*ias 1 ios-simulator dart firebase firebase-authentication flutter

我正在编写一个使用电话身份验证的 flutter 应用程序。我目前正在 iPhone 12 模拟器上运行该应用程序,当我测试该应用程序并实现电话号码时,我没有按计划从 firebase 收到 6 位数代码。我认为是因为其中提到的一个引起了共鸣。

    1. Firebase 无法使用假号码将代码发送到模拟器。
    1. 我需要更改 firebase/flutter 项目的一些设置,以便它能够按预期工作。
    1. 我还需要发送带有区号的电话号码。
    1. 我的代码是错误的或者没有做我想要它做的事情。

(我还没有苹果开发者帐户,所以我给了 firebase 一个测试号码和代码,这样当我输入假号码时,我仍然可以将代码发送到应用程序(不是作为推送通知))。

该应用程序的一些要点:

如果需要的话,我可以在真实设备上测试该应用程序。
我现在不需要获取推送通知,我只需将验证码打印到控制台,这样我就会看到代码是否有效。
我想在将电话号码发送到此页面(验证页面)后立即开始验证过程,
现在我使用的是不带区号的完整号码。

我可以为模拟器使用假号码吗?或者我需要一个真正的?

谢谢您,希望您能帮助解决我的问题。

这是我的代码(仅验证部分):

// 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,
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Mai*_*ais 8

iOS 上的 Firebase 电话身份验证需要一些设置步骤,如文档中所述。其中提到您需要启用推送通知的步骤需要验证请求是否来自您的应用程序,这称为“静默 APNs 通知”,因为它会在用户不知情的情况下悄然发生,但在测试时,使用reCAPTCHA 验证,请在官方 Firebase iOS 文档中阅读有关此步骤的更多信息。

但是,为了在模拟器上进行测试,您确实可以使用在 Firebase 控制台中的电话身份验证登录方法下定义的假号码和 SMS 代码。

首先,您需要按照 Firebase SDK 的要求为 iOS 设置 reCAPTCHA 验证。

其次,添加本地测试电话验证的测试号码

  1. 在 Firebase 控制台上,选择“电话”身份验证提供商,然后单击“用于测试的电话号码”下拉列表。
  2. 输入新的电话号码(例如+44 7444 555666)和测试代码(例如123456)。

添加测试编号时请注意以下事项:

  1. 在 Firebase 控制台中将号码添加到测试列表后,即使它们是真实的,您也不会收到短信代码,您可以使用已在控制台中定义的代码。
  2. 如果您已经有一个注册帐户,使用的电话号码与您尝试添加测试的电话号码相同,则会出现错误,提示无法添加该帐户,请确保删除与该号码关联的帐户或选择另一个帐户。

Firebase 接受的电话号码格式必须带有国家/地区代码,并遵循 E.164 标准,以+开头,后面是国家/地区代码,最后是电话号码。