Функция Asyn c не возвращает ожидаемые данные в Flutter - PullRequest
1 голос
/ 26 марта 2020

Я пытаюсь подтвердить номер телефона с помощью firebase. Но получение неожиданного результата от функции asyn c. Вот мой код:

  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), даже если проверка прошла успешно. Что здесь не так?

Ответы [ 3 ]

1 голос
/ 06 апреля 2020

если вы можете поместить в isVerificationSuccess = true; внутри функции verificationComplete(credential), тогда вы можете получить true значение

1 голос
/ 12 апреля 2020

Так что здесь функция verifyUserPhoneNumber возвращает еще до завершения FirebaseAuth.instance.verifyPhoneNumber (), поэтому она не возвращает ожидаемые данные (всегда ложные), даже если проверка прошла успешно. Что здесь не так?

FirebaseAuth.instance.verifyPhoneNumber использует метод канала plugins.flutter.io/firebase_auth и вызывает собственный метод для аутентификации.

Используется обратный вызов, указанный в аргументе verificationCompleted после завершения проверки. Однако из определений функций кажется, что FirebaseAuth.instance.verifyPhoneNumber ожидает тип void Function(AuthCredential). Тем не менее, вы предоставляете Future<void> Function(AuthCredential)

Что здесь не так?

Похоже, что неправильно ожидать, что FirebaseAuth.instance.verifyPhoneNumber будет ждать асин c перезвоните Future<void> Function(AuthCredential) для завершения, когда он ожидает void Function (AuthCredential).

Так что он просто вызывает вашу реализацию verificationComplete(AuthCredential credential) async, которая возвращает Future<void>. В этот момент FirebaseAuth.instance.verifyPhoneNumber завершено, и элемент управления переходит к print и return isVerificationSuccess, которые все еще равны false, поскольку будущее, возвращаемое verificationComplete(AuthCredential credential) async, еще не разрешено.

Итак,

  1. Возвращает Future<void> из verifyUserPhoneNumber
  2. Обновите состояние приложения, используя setState внутри verificationComplete после назначения isVerificationSuccess = true; для восстановления приложения после успешной проверки
1 голос
/ 26 марта 2020

Проблема заключается в том, что вызов функции в этой строке:

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

не ожидается, хотя сама функция является асинхронной. Итак, что происходит:

  1. verifyUserPhoneNumber вызывается откуда-то
  2. FirebaseAuth.instance.verifyPhoneNumber ожидается
  3. В этом вызове verificationComplete(credential) вызывается и, потому что он сам содержит оператор await, он будет поставлен в очередь событием Dart l oop. Поэтому, что бы ни случилось после задержки FirebaseUser user = await FirebaseAuth.instance.currentUser();!
  4. verifyUserPhoneNumber теперь продолжает выполняться и возвращает false.
  5. После того, как значение уже возвращено, оно теперь равно verificationComplete. обратиться к процессу. Это изменит логическое значение и затем завершится.

Моя рекомендация здесь не в том, чтобы использовать глобальную переменную, а вместо этого, например, вызвать verificationComplete после 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;
    }
  }
...