如何处理扑扑的Firebase Auth异常

时间:2019-05-13 13:48:38

标签: firebase flutter firebase-authentication

请问有人知道如何在Flutter上捕获Firebase Auth异常并显示它们,

注意:我对控制台不感兴趣(catcherror((e)print(e))

我需要更有效的方法,例如“用户不存在”,这样我才能将其传递给字符串并显示出来。

处理这个问题几个月了。

预先感谢

我尝试用// errorMessage = e.toString();替换print(e);然后将其传递给函数,所有的努力都徒劳无功

    FirebaseAuth.instance
              .signInWithEmailAndPassword(email: emailController.text, password: passwordController.text)
              .then((FirebaseUser user) {
                _isInAsyncCall=false;
            Navigator.of(context).pushReplacementNamed("/TheNextPage");

          }).catchError((e) {
           // errorMessage=e.toString();
            print(e);
            _showDialog(errorMessage);

            //exceptionNotice();
            //print(e);

我希望能够提取异常消息并将异常消息传递给对话框,然后我可以将其显示给用户

15 个答案:

答案 0 :(得分:14)

新答案(2020年9月18日)

如果您使用的是firebase_auth: ^0.18.0,则错误代码已更改!

例如:ERROR_USER_NOT_FOUND现在为user-not-found

我找不到与此有关的任何文档,因此我进入了源代码并阅读了每个错误代码的注释。 (firebase_auth.dart)

我没有在我的应用程序中使用所有错误代码(例如,验证,密码重置...),但是您会在此代码段中找到最常见的错误代码:

(它处理旧的和新的错误代码)

String getMessageFromErrorCode() {
    switch (this.errorCode) {
      case "ERROR_EMAIL_ALREADY_IN_USE":
      case "account-exists-with-different-credential":
      case "email-already-in-use":
        return "Email already used. Go to login page.";
        break;
      case "ERROR_WRONG_PASSWORD":
      case "wrong-password":
        return "Wrong email/password combination.";
        break;
      case "ERROR_USER_NOT_FOUND":
      case "user-not-found":
        return "No user found with this email.";
        break;
      case "ERROR_USER_DISABLED":
      case "user-disabled":
        return "User disabled.";
        break;
      case "ERROR_TOO_MANY_REQUESTS":
      case "operation-not-allowed":
        return "Too many requests to log into this account.";
        break;
      case "ERROR_OPERATION_NOT_ALLOWED":
      case "operation-not-allowed":
        return "Server error, please try again later.";
        break;
      case "ERROR_INVALID_EMAIL":
      case "invalid-email":
        return "Email address is invalid.";
        break;
      default:
        return "Login failed. Please try again.";
        break;
    }
  }

答案 1 :(得分:6)

Auth类中的

具有此功能:

Future signUpWithEmailAndPassword(String email, String password) async {
    try {
      AuthResult result = await _auth.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );
      FirebaseUser user = result.user;
      return user;
    } catch (e) {
      return e;
    }
  }

上面的catch错误返回一个PlatformException的runTimeType,而flutter中的PlatformException具有3个属性检查here


在您的Dart文件中,在按钮侦听器上实施此操作:

String error = "";

dynamic result = await _auth.signUpWithEmailAndPassword(email, password);

if (result.runtimeType == PlatformException) {
    if (result.message != null) {
        setState(() {
            error = result.message;
        });
    } else {
        setState(() {
            error = "Unknown Error";
        });
    }
}

答案 2 :(得分:4)

在Dart中,您可以使用on语法对不同的异常做出反应。由于Firebase使用自己的PlatformException,因此您可以轻松地通过以下方式捕获它们:

  try {
      AuthResult result = await signUp(email, password);
  } on PlatformException catch (e) {
      print(e.message);
  } on Exception catch (e) {
      print(e);
  }

PlatformException带来了可以在UI中显示的代码和消息,即:

PlatformException(ERROR_EMAIL_ALREADY_IN_USE, The email address is already in use by another account., null)

答案 3 :(得分:2)

我在这个问题上也停留了一段时间,我创建了一个包含所有可用错误here的要点,并举例说明了所有平台异常代码

处理注册异常的示例

Future<String> signUp(String email, String password, String firstName) async {
  FirebaseUser user;

  try {
    AuthResult result = await _auth.createUserWithEmailAndPassword(
        email: email, password: password);
    user = result.user;
    name = user.displayName;
    email = user.email;

    Firestore.instance.collection('users').document(user.uid).setData({
      "uid": user.uid,
      "firstName": firstName,
      "email": email,
      "userImage": userImage,
    });
  } catch (error) {
    switch (error.code) {
      case "ERROR_OPERATION_NOT_ALLOWED":
        errorMessage = "Anonymous accounts are not enabled";
        break;
      case "ERROR_WEAK_PASSWORD":
        errorMessage = "Your password is too weak";
        break;
      case "ERROR_INVALID_EMAIL":
        errorMessage = "Your email is invalid";
        break;
      case "ERROR_EMAIL_ALREADY_IN_USE":
        errorMessage = "Email is already in use on different account";
        break;
      case "ERROR_INVALID_CREDENTIAL":
        errorMessage = "Your email is invalid";
        break;

      default:
        errorMessage = "An undefined Error happened.";
    }
  }
  if (errorMessage != null) {
    return Future.error(errorMessage);
  }

  return user.uid;
}

处理登录异常的示例

Future<String> signIn(String email, String password) async {
  FirebaseUser user;
  try {
    AuthResult result = await _auth.signInWithEmailAndPassword(
        email: email, password: password);
    user = result.user;
    name = user.displayName;
    email = user.email;
    userId = user.uid;
  } catch (error) {
    switch (error.code) {
      case "ERROR_INVALID_EMAIL":
        errorMessage = "Your email address appears to be malformed.";
        break;
      case "ERROR_WRONG_PASSWORD":
        errorMessage = "Your password is wrong.";
        break;
      case "ERROR_USER_NOT_FOUND":
        errorMessage = "User with this email doesn't exist.";
        break;
      case "ERROR_USER_DISABLED":
        errorMessage = "User with this email has been disabled.";
        break;
      case "ERROR_TOO_MANY_REQUESTS":
        errorMessage = "Too many requests. Try again later.";
        break;
      case "ERROR_OPERATION_NOT_ALLOWED":
        errorMessage = "Signing in with Email and Password is not enabled.";
        break;
      default:
        errorMessage = "An undefined Error happened.";
    }
  }
  if (errorMessage != null) {
    return Future.error(errorMessage);
  }

  return user.uid;
}

答案 4 :(得分:1)

firebase auth插件还没有真正的跨平台错误代码系统,因此您必须独立处理android和ios的错误。

我当前正在使用此github问题的临时修订:#20223

请注意,因为它已修复 temp ,所以不要指望它作为永久解决方案是完全可靠的。

enum authProblems { UserNotFound, PasswordNotValid, NetworkError }

try {
  FirebaseUser user = await FirebaseAuth.instance.signInWithEmailAndPassword(
      email: email,
      password: password,
  );
} catch (e) {
  authProblems errorType;
  if (Platform.isAndroid) {
    switch (e.message) {
      case 'There is no user record corresponding to this identifier. The user may have been deleted.':
        errorType = authProblems.UserNotFound;
        break;
      case 'The password is invalid or the user does not have a password.':
        errorType = authProblems.PasswordNotValid;
        break;
      case 'A network error (such as timeout, interrupted connection or unreachable host) has occurred.':
        errorType = authProblems.NetworkError;
        break;
      // ...
      default:
        print('Case ${e.message} is not yet implemented');
    }
  } else if (Platform.isIOS) {
    switch (e.code) {
      case 'Error 17011':
        errorType = authProblems.UserNotFound;
        break;
      case 'Error 17009':
        errorType = authProblems.PasswordNotValid;
        break;
      case 'Error 17020':
        errorType = authProblems.NetworkError;
        break;
      // ...
      default:
        print('Case ${e.message} is not jet implemented');
    }
  }
  print('The error is $errorType');
}

答案 5 :(得分:1)

我只是为自己编写了一种无需依赖平台的代码即可完成此操作的方法:

这是可能的,因为.signInWithEmailAndPassword正确地抛出了带有已定义代码的错误,我们可以抓住这些错误来识别错误并以应有的方式处理事情。

下面的示例创建一个新的Future.error(如果发生任何错误),然后将Bloc配置为将数据铲入Widget。

Future<String> signIn(String email, String password) async {
  FirebaseUser user;
  String errorMessage;

  try {
    AuthResult result = await _firebaseAuth.signInWithEmailAndPassword(email: email, password: password);
    user = result.user;
  } catch (error) {
    switch (error.code) {
      case "ERROR_INVALID_EMAIL":
        errorMessage = "Your email address appears to be malformed.";
        break;
      case "ERROR_WRONG_PASSWORD":
        errorMessage = "Your password is wrong.";
        break;
      case "ERROR_USER_NOT_FOUND":
        errorMessage = "User with this email doesn't exist.";
        break;
      case "ERROR_USER_DISABLED":
        errorMessage = "User with this email has been disabled.";
        break;
      case "ERROR_TOO_MANY_REQUESTS":
        errorMessage = "Too many requests. Try again later.";
        break;
      case "ERROR_OPERATION_NOT_ALLOWED":
        errorMessage = "Signing in with Email and Password is not enabled.";
        break;
      default:
        errorMessage = "An undefined Error happened.";
    }
  }

  if (errorMessage != null) {
    return Future.error(errorMessage);
  }

  return user.uid;
}

答案 6 :(得分:1)

扩大接受的答案,我认为值得一提:

  1. firebase_auth插件具有 AuthException
  2. 正如本Github issue post中所指出的,对于Android和iOS,您可以具有相同的错误代码。
  3. 如果您在非UI层中拥有此代码,则可以使用rethrow或更好地抛出自己格式化的异常,并在UI级别上捕获这些异常(您将在其中确切地知道错误的种类)得到)。

try {
  AuthResult authResult = await FirebaseAuth.instance.signInWithCredential(credential);
  // Your auth logic ...
} on AuthException catch (e) {
  print('''
    caught firebase auth exception\n
    ${e.code}\n
    ${e.message}
  ''');

  var message = 'Oops!'; // Default message
  switch (e.code) {
    case 'ERROR_WRONG_PASSWORD':
      message = 'The password you entered is totally wrong!';
      break;
    // More custom messages ...
  }
  throw Exception(message); // Or extend this with a custom exception class
} catch (e) {
  print('''
    caught exception\n
    $e
  ''');
  rethrow;
}

答案 7 :(得分:1)

我遇到了一个问题,我不希望出现“com.google.firebase.FirebaseException:发生内部错误。[无法解析主机“www.googleapis.com”:没有关联的地址 使用主机名 ]" 这将向用户表明正在使用的后端是 firebase。因此,我只使用了 toString().replaceAll()

  Future<void> signIn() async {
final formState = _formkey.currentState;
var _date = DateTime.now();

if (formState!.validate()) {
  emailFocus!.unfocus();
  passwordFocus!.unfocus();
  formState.save();
  setState(() {
    isloading = true;
    _errorMessage = '';
  });
  try {
    UserCredential user = await _firebaseAuth.signInWithEmailAndPassword(
        email: _email, password: _password!);

    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setString('email', _email);

    await FirebaseFirestore.instance
        .collection('Users Token Data')
        .doc(user.user!.uid)
        .set({'Email': _email, 'Token': _token, 'Date': _date});

    Navigator.pushNamedAndRemoveUntil(
        context, RouteNames.homePage, (e) => false);
  } on FirebaseAuthException catch (e) {
    setState(() {
      isloading = false;
      _errorMessage = e.message.toString().replaceAll(
          'com.google.firebase.FirebaseException: An internal error has' +
              ' occurred. [ Unable to resolve host "www.googleapis.com":' +
              "No address associated with hostname ]",
          "Please Check Network Connection");
    });
    print(e.message);
  }
}

} }

以防万一,如果您不想从错误消息中透露太多信息。

答案 8 :(得分:0)

我最近也遇到了此错误,并且我发现在调试模式下(即单击VSCode中的.catchError()按钮时)没有调用Run->Start Debugging回调。

但是,当您输入flutter run -d时,.catchError()方法将被回调,因为它不在调试模式下。

要获取您首选的模拟器代码,请将以下代码行粘贴到终端中:

instruments -s devices

如果这不起作用,您也可以尝试粘贴以下内容:

xcrun simctl list

.catchError()方法将被调用,与之前不同,其中的代码将按预期执行!

此外,该应用程序不会再因PlatformException()而崩溃,而是会显示类似以下的日志:

[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The getter 'uid' was called on null.
Receiver: null

我也曾在Google登录中遇到过此问题,其中没有调用.catchError()

最后,如果您在处理Firebase身份验证时遇到一些错误,则应首先尝试首先通过终端运行。谢谢,希望对您有所帮助!

答案 9 :(得分:0)

我更喜欢创建api层响应和错误模型,并将firebase插件错误和响应对象包装在其中。要使用电子邮件和密码登录,我有这个

@override
  Future<dynamic> loginWithEmailAndPassword(String email, String password) async {
    try {
      await _firebaseAuth.signInWithEmailAndPassword(
          email: email, password: password);
      return FirebaseSignInWithEmailResponse();
    } catch (exception) {
      return _mapLoginWithEmailError(exception);
    }
  }

  ApiError _mapLoginWithEmailError(PlatformException error) {
    final code = error.code;
    if (code == 'ERROR_INVALID_EMAIL') {
      return FirebaseSignInWithEmailError(
          message: 'Your email is not valid. Please enter a valid email',
          type: FirebaseSignInWithEmailErrorType.INVALID_EMAIL);
    } else if (code == 'ERROR_WRONG_PASSWORD') {
      return FirebaseSignInWithEmailError(
          message: 'Your password is incorrect',
          type: FirebaseSignInWithEmailErrorType.WRONG_PASSWORD);
    } else if (code == 'ERROR_USER_NOT_FOUND') {
      return FirebaseSignInWithEmailError(
          message: 'You do not have an account. Please Sign Up to'
              'proceed',
          type: FirebaseSignInWithEmailErrorType.USER_NOT_FOUND);
    } else if (code == 'ERROR_TOO_MANY_REQUESTS') {
      return FirebaseSignInWithEmailError(
          message: 'Did you forget your credentials? Reset your password',
          type: FirebaseSignInWithEmailErrorType.TOO_MANY_REQUESTS);
    } else if (code == 'ERROR_USER_DISABLED') {
      return FirebaseSignInWithEmailError(
          message: 'Your account has been disabled. Please contact support',
          type: FirebaseSignInWithEmailErrorType.USER_DISABLED);
    } else if (code == 'ERROR_OPERATION_NOT_ALLOWED') {
      throw 'Email and Password accounts are disabled. Enable them in the '
          'firebase console?';
    } else {
      return FirebaseSignInWithEmailError(
          message: 'Make sure you have a stable connection and try again'
          type: FirebaseSignInWithEmailErrorType.CONNECTIVITY);
    }
  }

我从不从Firebase返回AuthResult。相反,我听onAuthStateChanged流,并在发生更改时做出相应的反应。

答案 10 :(得分:0)

可以使用FirebaseAuthException类处理异常。

以下是使用电子邮件和密码登录的代码:

void loginUser(String email, String password) async {
    try {
      await _auth.signInWithEmailAndPassword(email: email, password:password);
    } on FirebaseAuthException catch (e) {
      // Your logic for Firebase related exceptions
    } catch (e) {
    // your logic for other exceptions!
}

您可以使用自己的逻辑来处理错误,例如显示警报对话框等。 创建用户也可以这样做。

答案 11 :(得分:0)

在使用“ Firebase身份验证”时,我在“ firebse平台例外:”中出现了相同的错误 而且即使在传递参数时使用try catch和trim()方法也无法解决问题。

问题是,当您使用main.dart中的“运行”按钮运行应用程序时,它不会回调并捕获错误。

解决方案:在Vscode终端中,键入“ Flutter run”(用于调试模式)。或“ Flutter run --release”(用于发布模式),现在您将不会遇到平台异常。

答案 12 :(得分:0)

   try {
  final newuser = await _auth.createUserWithEmailAndPassword(
      email: emailController.text, password: passwordController.text);
  // print("Done");
} catch (e) {
  print(e);
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: new Text(e.message),
        actions: <Widget>[
          FlatButton(
            child: new Text("OK"),
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
        ],
      );
    },
  );
}

答案 13 :(得分:0)

所以我今天遇到了这个问题,而不是硬编码要显示的错误消息,我决定使用字符串操作并设法获取消息。

目标是获取消息(] 之后的所有内容)。 示例:获取此 => 密码应至少为 6 个字符 from this => [firebase_auth/weak-password] 密码应至少为 6 个字符

因此,使用 try-catch 中的异常,我先将其转换为字符串,然后将前 14 个字符(从“[”到“/”)替换为空,因此只剩下 弱密码] 密码应至少为 6 个字符

然后使用']'模式的split函数在剩余的字符串中搜索']'符号,并将整个字符串以']'符号的索引为支点分割成两个。这将返回一个包含两个字符串的列表; '弱密码''密码应至少为 6 个字符'。使用索引 1 获取第二个字符串,即错误消息。

e.toString().replaceRange(0, 14, '').split(']')[1]

答案 14 :(得分:0)

试试这个,我有同样的问题,这段代码对我有用

catch (e) {
                        ScaffoldMessenger.of(context)
                            .showSnackBar(SnackBar(content: Text('Wrong UserName or Password')));
                      }