'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 1:[1]

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!

Solution 2:[2]

In my case I solved allowing Outgoing Connections on the Xcode's Runner.xcworkspace

enter image description here

Solution 3:[3]

In my case, my VPN was causing the problem. Disabling the VPN and testing it again solved the error. I hope it helps.

Solution 4:[4]

if you are trying this out in a simulator, then this error may pop up as the internet of your simulator is not connected. To solve this you can run your app on a physical device and it will work!

Solution 5:[5]

Normally when the emulator is doing a lot of work on the thread, it tends to misbehave, such a losing internet connectivity even if your PC is well connected. My suggestion(Which worked for me) is you kill the emulator, and go to Android Studio AVD Manager and Wipe Data for that Emulator, then restart the Emulator, it worked for me.The circled in red are the key points to click Kindly find below the image screenshot

Solution 6:[6]

Open Terminal in the project folder, run the following two commands:

adb kill-server
    
adb start-server

If adb is not recognized, add C:\Users\USERNAME\AppData\Local\Android\Sdk\platform-tools to environement variables.

Solution 7:[7]

I am late to the party but I found another solution.

If using an android emulator, disabling the Android Studio HTTP proxy settings can restore the network connection.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dominik
Solution 2 Fran Fox
Solution 3 NBM
Solution 4 Abhiraj Ghosh
Solution 5
Solution 6 TiyebM
Solution 7 MaximeBeasse