2

我正在尝试使用 firebase 验证电话号码。但是从异步函数中得到了意想不到的结果。这是我的代码:

  bool isVerificationSuccess = false;

  Future<bool> verifyUserPhoneNumber(String phoneNumber) async {
    await FirebaseAuth.instance.verifyPhoneNumber(
      phoneNumber: phoneNumber,
      timeout: Duration(seconds: 60),
      verificationCompleted: (credential) => verificationComplete(credential),
      verificationFailed: (authException) => verificationFailed(authException),
      codeAutoRetrievalTimeout: (verificationId) =>
          codeAutoRetrievalTimeout(verificationId),
      codeSent: (verificationId, [code]) => smsCodeSent(verificationId, [code]),
    );
    print("Status from service : $isVerificationSuccess");
    return isVerificationSuccess;
  }

  verificationComplete(AuthCredential credential) async {
    FirebaseUser user = await FirebaseAuth.instance.currentUser();

    user.linkWithCredential(credential).then((_) {
      print("User Successfully Linked");
      isVerificationSuccess = true;
    }).catchError((e) {
      print("Linking Error : ${e.toString()}");
    });
  }

这是输出:

 Status from service : false
 User Successfully Linked

所以这里verifyUserPhoneNumber的函数甚至在完成之前就返回了,所以即使验证成功FirebaseAuth.instance.verifyPhoneNumber(),它也不会返回预期的数据(总是)。false这里有什么问题?

4

3 回答 3

1

如果你可以放在isVerificationSuccess = true;内部函数中,verificationComplete(credential)那么你可能会获得true价值

于 2020-04-06T14:58:10.780 回答
1

因此,这里的 verifyUserPhoneNumber 函数甚至在 FirebaseAuth.instance.verifyPhoneNumber() 完成之前返回,因此即使验证成功,它也不会返回预期的数据(始终为 false)。这里有什么问题?

FirebaseAuth.instance.verifyPhoneNumber使用方法通道plugins.flutter.io/firebase_auth并调用本机方法进行身份验证。

verificationCompleted一旦验证完成,它就会使用参数中指定的回调。但是,从函数定义来看,似乎FirebaseAuth.instance.verifyPhoneNumber需要一个 type void Function(AuthCredential)。但是,您提供Future<void> Function(AuthCredential)

这里有什么问题?

似乎错误的是期望FirebaseAuth.instance.verifyPhoneNumberFuture<void> Function(AuthCredential)期望void Function (AuthCredential).

所以它只是调用你的verificationComplete(AuthCredential credential) async实现,它返回一个Future<void>. 此刻,FirebaseAuth.instance.verifyPhoneNumber完成,控制前进到printreturn isVerificationSuccess仍然false作为返回的未来verificationComplete(AuthCredential credential) async还没有解决。

所以,

  1. 返回一个Future<void>verifyUserPhoneNumber
  2. 在您分配后使用setState内部更新应用程序的状态以在成功验证后重建您的应用程序verificationCompleteisVerificationSuccess = true;
于 2020-04-12T20:16:51.017 回答
1

问题是这一行中的函数调用:

verificationCompleted: (credential) => verificationComplete(credential),

不等待,即使函数本身是异步的。所以会发生什么:

  1. verifyUserPhoneNumber从某处被调用
  2. FirebaseAuth.instance.verifyPhoneNumber正在等待
  3. 在这个调用中,verificationComplete(credential)被调用,因为它本身包含一个 await 语句,它将被 Dart 事件循环排队。所以之后发生的任何事情都会FirebaseUser user = await FirebaseAuth.instance.currentUser();被延迟!
  4. verifyUserPhoneNumber现在继续执行并返回false
  5. 在已经返回一个值之后,现在verificationComplete轮到处理了。它将更改布尔值,然后退出。

我这里的建议是不要使用全局变量,而是例如 call verificationComplete after FirebaseAuth.instance.verifyPhoneNumber已经完全完成处理并返回。

编辑:这是理论上解决问题的方法,尽管我承认它不是特别漂亮:

  Future<bool> verifyUserPhoneNumber(String phoneNumber) async {
    final completer = Completer<AuthCredential>();
    await FirebaseAuth.instance.verifyPhoneNumber(
      phoneNumber: phoneNumber,
      timeout: Duration(seconds: 60),
      verificationCompleted: completer.complete,
      verificationFailed: completer.completeError,
      codeAutoRetrievalTimeout: (verificationId) =>
          codeAutoRetrievalTimeout(verificationId),
      codeSent: (verificationId, [code]) => smsCodeSent(verificationId, [code]),
    );
    try {
      final credential = await completer.future;
      return await verificationComplete(credential);
    } catch (e) {
      verificationFailed(e);
      return false;
    }
  }

  Future<bool> verificationComplete(AuthCredential credential) async {
    FirebaseUser user = await FirebaseAuth.instance.currentUser();
    try {
      await user.linkWithCredential(credential);
      print("User Successfully Linked");
      return true;
    } catch (e) {
      print("Linking Error : ${e.toString()}");
      return false;
    }
  }
于 2020-03-26T13:26:37.763 回答