Search code examples
firebaseflutterdartfirebase-authentication

Flutter Firebase Auth: A network error (such as timeout, interrupted connection or unreachable host) has occurred


I am trying to integrate authentication on Flutter using firebase_auth.

However, whenever I call the verifyPhoneNumber("+256XXXXXXXXXX") I get the error message A network error (such as timeout, interrupted connection or unreachable host) has occurred., that is from the PhoneVerificationFailed callback. An for that reason cannot get the SMS.

I have tried;

  1. Adding network permissions as seen below to my file (my internet connection works, as I am able to Google via the emulator)

    <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

  2. Checking the validity of my API keys

I am totally confused as to why Flutter is unable to communicate with firebase. I have two questions.

  1. How can I eliminate this error?
  2. What other cases might cause this error besides a lacking internet connection?

My implimentatioin is as below;

import 'package:firebase_auth/firebase_auth.dart';

FirebaseAuth auth = FirebaseAuth.instance;

var message;
// fire this when Phone verification is completed
 final PhoneVerificationCompleted verificationCompleted =
      (AuthCredential phoneAuthCredential) {
    auth.signInWithCredential(phoneAuthCredential);

    message = 'Received phone auth credential: $phoneAuthCredential';
    print(message);
  };

// fire this when Phone verification fails
  final PhoneVerificationFailed verificationFailed =
      (AuthException authException) {
    message =
        'Phone verification failed. Code: ${authException.code}. Message: ${authException.message}';
    print(message);
  };

  // fire this when SMS code is sent is sent.
  final PhoneCodeSent codeSent =
      (String verificationId, [int forceResendingToken]) async {
    verificationId = verificationId;
    print('Sent verification code');
  };


  // fire this when smsCode expires
  final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
      (String verificationId) {
    verificationId = verificationId;
    print('Auto retrival time-out');
  };

// verify phone number
verifyPhoneNumber(String phoneNumber) {
  auth.verifyPhoneNumber(
      phoneNumber: phoneNumber,
      timeout: const Duration(seconds: 30),
      verificationCompleted: verificationCompleted,
      verificationFailed: verificationFailed,
      codeSent: codeSent,
      codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
      print('Verification Initiated');
}

// sign in with phone.
signInWithPhoneNumber(String smsCode, String verificationId) async {
  final AuthCredential credential = PhoneAuthProvider.getCredential(
    verificationId: verificationId,
    smsCode: smsCode,
  );

  final FirebaseUser user = (await auth.signInWithCredential(credential)).user;
  final FirebaseUser currentUser = await auth.currentUser();

  assert(user.uid == currentUser.uid);

  if (user != null) {
    message = 'Successfully signed in, uid: ' + user.uid;
  } else {
    message = 'Sign in failed';
  }
}

Solution

  • import 'package:badam/varify.dart';
    import 'package:flutter/material.dart';
    import 'package:firebase_auth/firebase_auth.dart';
    import 'dart:async';
    
    import 'HomePage.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'FireBase Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new LoginPage(),
          routes: <String, WidgetBuilder>{
            '/loginpage' : (BuildContext context) => Dash(),
            '/landpage' : (BuildContext context) => LoginPage(),
        }
        );
      }
    }
    class LoginPage extends StatefulWidget {
      @override
      _LoginPageState createState() => _LoginPageState();
    }
    
    class _LoginPageState extends State<LoginPage> {
      String phoneNo, smsId, verificationId;
    
      Future<void> verifyPhone() async{
        final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verId){
          this.verificationId = verId;
        };
        final PhoneCodeSent smsCodeSent = (String verId, [int forceCodeResend]){
          this.verificationId = verId;
          smsCodeDialoge(context).then((value){
            print('Signed In');
          });
        };
        final PhoneVerificationCompleted verifiedSuccess = (AuthCredential auth){
          print('verified');
        };
        final PhoneVerificationFailed verifyFailed = (AuthException e) {
          print('${e.message}');
        };
        await FirebaseAuth.instance.verifyPhoneNumber(
          phoneNumber: phoneNo,
          timeout: const Duration(seconds: 5),
          verificationCompleted: verifiedSuccess,
          verificationFailed: verifyFailed,
          codeSent: smsCodeSent,
          codeAutoRetrievalTimeout: autoRetrieve,
        );
      }
      Future<bool> smsCodeDialoge(BuildContext context){
        return showDialog(context: context,
          barrierDismissible: false,
          builder: (BuildContext context) {
            return new AlertDialog(
              title: Text('Enter OTP'),
              content: TextField(
                onChanged: (value)  {
                  this.smsId  = value;
                },
              ),
              contentPadding: EdgeInsets.all(10.0),
              actions: <Widget>[
                new FlatButton(
                    onPressed: (){
                      FirebaseAuth.instance.currentUser().then((user){
                        if(user != null){
                          Navigator.of(context).pop();
                          Navigator.push(
                            context,
                            MaterialPageRoute(builder: (context) => Dash()),
                          );
    
                        }
                        else{
                          Navigator.of(context).pop();
                          signIn(smsId);
                        }
    
                      }
                      );
                    },
                    child: Text('Done', style: TextStyle( color: Colors.blue),))
              ],
            );
          },
        );
      }
    
      Future<void> signIn(String smsCode) async {
        final AuthCredential credential = PhoneAuthProvider.getCredential(
          verificationId: verificationId,
          smsCode: smsCode,
        );
         await FirebaseAuth.instance.signInWithCredential(credential)
            .then((user){
          Navigator.of(context).pushReplacementNamed('/loginpage');
        }).catchError((e){
          print(e);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
              title: Text('Sign In')
          ),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
    
            children: <Widget>[
              Text('Phone Auth',style: TextStyle(fontSize: 20,color: Colors.blue),),
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: TextField(
                  decoration: InputDecoration(
                    hintText: 'Enter your phone number',
                  ),
                  onChanged: (value){
                    this.phoneNo = value;
                  },
                ),
              ),
              SizedBox(height: 10.0),
              RaisedButton(
                onPressed: verifyPhone,
                child: Text('Verify', style: TextStyle(color: Colors.white),),
                elevation: 7.0,
                color: Colors.blue,
    
              )
            ],
          ),
        );
      }
    }
    

    It worked for me, hope this helps you!