본문 바로가기

개발하자

플러터 시 Firebase Auth 예외 처리 방법

반응형

플러터 시 Firebase Auth 예외 처리 방법

플레어 시 파이어베이스 인증 예외를 포착하여 표시하는 방법을 아는 사람이 있습니까?

참고: 저는 콘솔에 관심이 없습니다(캐처 오류(e) 인쇄(e))

"사용자가 존재하지 않습니다."와 같이 더 효과적인 것이 필요합니다. 그러면 문자열로 전달하고 표시할 수 있습니다.

몇 달 동안 이 일을 처리했어요.

잘 부탁드립니다.

나는 print(e)를 // errorMessage=e.toString()으로 대체하려고 시도했지만, 그것을 함수에 전달하는 모든 노력이 헛수고였다.

    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);

예외 메시지를 추출하여 사용자에게 표시할 수 있는 대화 상자에 예외 메시지를 전달할 수 있어야 합니다.




(21/02/20) 편집: 이 답변은 오래되었고 다른 답변에는 교차 플랫폼 솔루션이 포함되어 있으므로 먼저 해당 솔루션을 살펴보고 이를 폴백 솔루션으로 처리해야 합니다.

파이어베이스 인증 플러그인은 아직 제대로 된 크로스 플랫폼 오류 코드 시스템이 없기 때문에 안드로이드와 iOS의 오류를 독립적으로 처리해야 한다.

나는 현재 이 github 이슈의 임시 수정을 사용하고 있다:

수정 사항이므로 영구적인 해결책으로 완전히 신뢰할 수 있을 것으로 기대하지 마십시오.

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 yet implemented');
    }
  }
  print('The error is $errorType');
}



firebase_auth: ^0.18.0을 사용하는 경우 오류 코드가 변경되었습니다! 다음 답을 확인하세요.

플랫폼 종속 코드 없이 이 작업을 수행할 수 있는 방법을 코딩했습니다:

이는 .signInWithEmailAndPassword가 정의된 코드와 함께 오류를 올바르게 발생시켜 오류를 식별하고 처리해야 하는 방식으로 작업을 처리할 수 있기 때문에 가능합니다.

다음 예제에서는 오류가 발생할 경우 새로운 Future.error를 생성한 다음 해당 데이터를 위젯으로 이동하도록 블록을 구성합니다.

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;
}



수락된 답변을 확장하면서 다음과 같이 언급할 가치가 있다고 생각했습니다:

  1. 플러그인에 가 있습니다.
  2. 여기서 지적했듯이 안드로이드와 iOS에 동일한 오류 코드가 있을 수 있습니다.
  3. 이 코드가 UI가 아닌 계층에 있는 경우 사용하거나 포맷된 예외를 사용하여 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;
}



나도 잠시 이것에 사로잡혔고, 나는 예시와 함께 이용 가능한 모든 오류로 이 요지를 만들었고, 모든 플랫폼 예외 코드를 다룬다

등록 예외 처리 예제

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;
}



다트에서 구문을 사용하여 다른 예외에 대응할 수 있습니다. 파이어베이스가 자체 플랫폼을 사용하기 때문에다음과 같은 예외 사항으로 쉽게 파악할 수 있습니다:

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

플랫폼예외는 코드와 함께 UI에 표시할 수 있는 메시지를 가져옵니다:

플랫폼예외(오류_EMAIL_ALREADY_IN_USE, 전자 메일 주소가 이미 다른 계정에서 사용되고 있습니다. null)



인증 클래스에는 다음과 같은 기능이 있습니다:

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 오류는 runTime을 반환합니다플랫폼 유형예외 및 플랫폼플러터의 예외에 속성 검사가 3개 있습니다!


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";
        });
    }
}



또한 최근에 이 오류가 발생했는데 콜백이 디버그 모드(즉, VSCode에서 버튼을 클릭할 때)에서 호출되지 않는다는 것을 알게 되었습니다.

그러나 flot run -d를 입력하면 디버그 모드가 아니기 때문에 메서드가 다시 호출됩니다.

선호하는 시뮬레이터의 코드를 가져오려면 다음 코드 줄을 터미널에 붙여넣으십시오:

instruments -s devices

그래도 문제가 해결되지 않으면 다음을 붙여넣을 수도 있습니다:

xcrun simctl list

이전과 달리 "etcatchError()" 메서드가 호출되고 내부 코드가 예상대로 실행됩니다!

또한 앱은 더 이상 와 충돌하지 않으며 대신 다음과 같은 로그가 표시됩니다:

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

나도 구글 사인인에서 이 문제에 직면해 있었는데, 그 문제는 호출되지 않았다!

결론적으로, Firebase Authentication에서 오류를 처리하는 데 약간의 오류가 있다면, 먼저 터미널을 통해 실행을 시도해야 합니다. 고마워요, 그리고 이게 도움이 되었으면 좋겠어요!




나는 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를 사용하여 처리할 수 있습니다AuthException 클래스입니다.

이메일과 암호를 사용하여 로그인하는 코드는 다음과 같습니다:

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!
}

자신의 논리를 사용하여 오류를 처리할 수 있습니다(예: 경고 대화 상자 표시 등). 사용자를 생성하는 경우에도 동일한 작업을 수행할 수 있습니다.




나는 "Firebase auth"를 사용하여 flurter에서 "firebase platform exception:"과 동일한 오류를 가지고 있으며, 전달 인수에서 try catch 및 trim() 방법을 사용해도 해결되지 않았습니다.

문제는 main.dart에서 "실행" 버튼을 사용하여 앱을 실행할 때 다시 호출되지 않고 오류를 감지한다는 것입니다.

솔루션: Vscode 터미널에 "Flutter run"(디버깅 모드의 경우)을 입력합니다. 또는 "Flutter run --release"(릴리스 모드의 경우)를 선택하면 플랫폼 예외가 발생하지 않습니다.




새로운 답변(18/09/2020)

를 사용하는 경우 오류 코드가 변경되었습니다!

예: is now

나는 그것에 대한 어떤 문서도 찾을 수 없어서 소스 코드로 들어가 모든 오류 코드에 대한 코멘트를 읽었다.

앱에서 모든 오류 코드(예: 확인, 암호 재설정...)를 사용하지 않지만 다음 코드 조각에서 가장 일반적인 오류 코드를 찾을 수 있습니다:

(오래된 오류 코드와 새 오류 코드를 처리합니다

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;
    }
  }



   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();
            },
          ),
        ],
      );
    },
  );
}



그래서 나는 오늘 이 문제에 직면했고 표시할 오류 메시지를 하드 코딩하는 대신 문자열 조작을 사용하기로 결정했고 메시지를 간신히 받았다.

목표는 (이후의 모든 것을) 메시지를 받는 것이었다. 예: 이 =>에서 이 =>를 가져옵니다.

그래서 try-catch의 예외를 사용하여 먼저 문자열로 변환한 다음, 처음 14개의 문자('['에서 '/'로)를 아무 것도 사용하지 않고 바꾸었습니다.

그런 다음 '] 패턴을 사용하여 분할 함수를 사용하여 나머지 문자열에서 '] 기호를 검색하고 '] 기호의 인덱스를 피벗으로 하여 전체 문자열을 두 개로 분할합니다. 문자열이 두 개인 목록을 반환합니다. 인덱스 1을 사용하여 오류 메시지인 두 번째 문자열을 가져옵니다.

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



나는 "com.google"을 원하지 않는 문제가 있었다.화력 기지.파이어베이스예외: 내부 오류가 발생했습니다. [ "www.googleapis.com" 호스트를 확인할 수 없음:호스트 이름과 연결된 주소가 없음]"이(가) 사용자에게 사용 중인 백엔드가 Firebase임을 나타냅니다. 그래서 나는 그냥 String().replace All()을 사용했다

  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);
  }
}

} }

오류 메시지에서 너무 많은 정보를 노출하고 싶지 않을 경우를 대비하여.




이것을 시도해 보세요, 저는 같은 프로펠러를 가지고 있었고 이 코드는 저와 함께 작동했습니다

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



Firebase-Auth 최신 버전은 다음 try catch 문을 사용하여 오류 코드 및 오류 메시지를 가져오는 간단한 방법을 제공합니다:

try {
  await FirebaseAuth.instance.signInWithEmailAndPassword(
    email: "name@example.com",
    password: "SuperSecretPassword!"
  );
} on FirebaseAuthException catch  (e) {
  print('Failed with error code: ${e.code}');
  print(e.message);
}

출처:




버전의 예외 코드를 사용하여 Firebase 인증 예외를 관리합니다

firebase_auth: ^3.3.6
firebase_core: ^1.12.0

다음은 저에게 맞는 코드입니다:

Future<void> loginWithEmailAndPassword({
required String email,
required String password,
}) async {
try {
  await _firebaseAuth.signInWithEmailAndPassword(
      email: email, password: password);
} on firebase_auth.FirebaseAuthException catch (e) {
  switch (e.code) {
    case "invalid-email":
      //Thrown if the email address is not valid.
      throw InvalidEmailException();
    case "user-disabled":
      //Thrown if the user corresponding to the given email has been disabled.
      throw UserDisabledException();
    case "user-not-found":
      //Thrown if there is no user corresponding to the given email.
      throw UserNotFoundException();
    case "wrong-password":
      throw PasswordExceptions();
    //Thrown if the password is invalid for the given email, or the account corresponding to the email does not have a password set.
    default:
      throw UncknownAuthException();
  }
 }
}

나중에 UI에 표시할 메시지를 제어하기 위해 다음과 같은 예외를 만듭니다:

class AuthenticationException implements Exception {}
class InvalidEmailException extends AuthenticationException {}
class PasswordExceptions extends AuthenticationException {}
class UserNotFoundException extends AuthenticationException {}
class UserDisabledException extends AuthenticationException {}
class UncknownAuthException extends AuthenticationException {}

인증 예외를 처리하는 데 문제가 있는 사람에게 도움이 되기를 바랍니다!




이 코드는 "다른 계정에서 사용 중인 사용자"와 같은 예외 원인이 포함된 빨간색 스낵바를 표시합니다.

auth.createUserWithEmailAndPassword(
   email: email,
   password: password,
).onError((error,stackTrace){
   if(error.runtimeType == FirebaseAuthException) {
    ScaffoldMessenger.of(context).showSnackBar(
     SnackBar(
      content: Text(error.toString().replaceRange(0, 14, '').split(']')[1]),
      backgroundColor: Theme.of(context).colorScheme.error,
     ),
   );
  }
}

반응형