Firebase Phone Auth on Android - firebase

I have implemented the Firebase email and Google Signin correctly and it works fine on both iOS and Android.
Then I've tried to implement the Over the Phone Auth and first it doesn't work on iPhone but then I did some research and it seems I had to upload some APNs and finally I set it up correctly and now it works on iPhone, but when I try to send SMS to Android it doesn't receive it but sends me the message that indicates the code was sent just like on iPhone.
The strangest thing is if I put the iPhone's mobile number it gets the SMS code. So I wonder if I have to enable some type of Push notifications on Android like I did on iPhone or if I have to set up some real developer account, cause right now I don't have the Google's one or there's is something else I'm missing.
Can anyone help me with this, please?
The auth method I'm using is the one of the Flutter example:
class _PhoneSignInSection extends StatefulWidget {
_PhoneSignInSection(this._scaffold);
final ScaffoldState _scaffold;
#override
State<StatefulWidget> createState() => _PhoneSignInSectionState();
}
class _PhoneSignInSectionState extends State<_PhoneSignInSection> {
final TextEditingController _phoneNumberController = TextEditingController();
final TextEditingController _smsController = TextEditingController();
String _message = '';
String _verificationId;
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: const Text('Test sign in with phone number'),
padding: const EdgeInsets.all(16),
alignment: Alignment.center,
),
TextFormField(
controller: _phoneNumberController,
decoration:
InputDecoration(labelText: 'Phone number (+x xxx-xxx-xxxx)'),
validator: (String value) {
if (value.isEmpty) {
return 'Phone number (+x xxx-xxx-xxxx)';
}
return null;
},
),
Container(
padding: const EdgeInsets.symmetric(vertical: 16.0),
alignment: Alignment.center,
child: RaisedButton(
onPressed: () async {
_verifyPhoneNumber();
},
child: const Text('Verify phone number'),
),
),
TextField(
controller: _smsController,
decoration: InputDecoration(labelText: 'Verification code'),
),
Container(
padding: const EdgeInsets.symmetric(vertical: 16.0),
alignment: Alignment.center,
child: RaisedButton(
onPressed: () async {
_signInWithPhoneNumber();
},
child: const Text('Sign in with phone number'),
),
),
Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
_message,
style: TextStyle(color: Colors.red),
),
)
],
);
}
// Example code of how to verify phone number
void _verifyPhoneNumber() async {
setState(() {
_message = '';
});
final PhoneVerificationCompleted verificationCompleted =
(AuthCredential phoneAuthCredential) {
_auth.signInWithCredential(phoneAuthCredential);
setState(() {
_message = 'Received phone auth credential: $phoneAuthCredential';
});
};
final PhoneVerificationFailed verificationFailed =
(AuthException authException) {
setState(() {
_message =
'Phone number verification failed. Code: ${authException.code}. Message: ${authException.message}';
});
};
final PhoneCodeSent codeSent =
(String verificationId, [int forceResendingToken]) async {
widget._scaffold.showSnackBar(SnackBar(
content:
const Text('Please check your phone for the verification code.'),
));
_verificationId = verificationId;
};
final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
(String verificationId) {
_verificationId = verificationId;
};
await _auth.verifyPhoneNumber(
phoneNumber: _phoneNumberController.text,
timeout: const Duration(seconds: 5),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
}
// Example code of how to sign in with phone.
void _signInWithPhoneNumber() async {
final AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: _verificationId,
smsCode: _smsController.text,
);
final FirebaseUser user =
(await _auth.signInWithCredential(credential));
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
setState(() {
if (user != null) {
_message = 'Successfully signed in, uid: ' + user.uid;
} else {
_message = 'Sign in failed';
}
});
}
}
And my App level build.gradle have this dependencies:
dependencies {
implementation 'com.google.firebase:firebase-auth:19.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
As the guide says:
Add the dependency for the Firebase Authentication Android library to
your module (app-level) Gradle file (usually app/build.gradle):
implementation 'com.google.firebase:firebase-auth:19.0.0'
And of course I have apply plugin: 'com.google.gms.google-services' in the same build.gradle
EDIT: When it test with whitelisted phone numbers, I'm successfully signing in on Android.

Phone number in iPhone is receiving SMS successfully from both Android and iOS Apps.
Phone number in Android is not receiving in any SMS from either Android or iOS App.
So the problem is not really with the App but with Phone Number/SIM in Android phone. This can happen if the Phone is in roadming or if there are any restrictions no the Phone numbers, then Firebase might not send SMS. Apparantly this is what happening. To make sure this is the problem, better to test with another phone Number. If its working with the new phone number, we can conclude its problem with a particular Phone number but not with your phone.
You might want to re-write following code (in those lines):
_auth.signInWithCredential(phoneAuthCredential);
setState(() {
_message = 'Received phone auth credential: $phoneAuthCredential';
});
to
_auth.signInWithCredential(phoneAuthCredential)
.then((user) {setState(){
_message = 'Received phone auth credential: $phoneAuthCredential';
}})
.catchError((error) {
_message = 'Something went wrong: $error';
});
So that you are sure making sure _auth.signInWithCredential is successful before informing user.

Related

Firebase Phone Auth: some users don't receive OTP

I am facing a strange issue of some phone numbers do not receive OTP without receiving any errors, just nothing happens. Almost all the users are receiving the OTP just fine, except for only very few. How can I debug the issue? Does Firebase Auth have some log with any errors? Is my code missing something?
Here is the code (in Flutter) for sending the OTP
sendOtp(String number, BuildContext context) async {
print("Sending OTp");
state = ViewState.Busy;
await auth.verifyPhoneNumber(
phoneNumber: '+966$number',
timeout: Duration(seconds: 30),
verificationCompleted: (AuthCredential credential) {
print("Verified");
signInWCredential(credential, context, number);
},
verificationFailed: (FirebaseAuthException e) {
print("verification error code is: ${e.code}");
print("verification error message is: ${e.message}");
if (e.code == "too-many-requests") {
Dialogs.dialog(
context,
"${Localization.of(context).error}!",
Localization.of(context).tooManyOtpRequestsError,
Localization.of(context).ok,
isDoublePop: true)
.then((value) {
if (value == ConfirmAction.ACCEPT) {
Navigator.of(context).pop();
}
});
} else {
FirebaseCrashlytics.instance.recordError(e, StackTrace.current);
print("Error is: $e");
Dialogs.dialog(
context,
"${Localization.of(context).error}!",
Localization.of(context).errorSendingOtp,
Localization.of(context).ok,
isDoublePop: true);
}
},
codeSent: (String verificationId, [int resendToken]) {
print("Code sent");
print("verification ID is: $verificationId");
setVerificationId(verificationId);
print("Resend token is: $resendToken");
state = ViewState.Idle;
},
codeAutoRetrievalTimeout: (String verificationId) {},
);
}
I have contacted GCP support to investigate this issue. They reported to me that the SMS delivery in my customers' region has 85%-90% success rate. They are working with SMS providers to solve that issue.
I made a new feature request to return an error message if the SMS delivery fails. Meanwhile, I solved this issue by creating my own custom authentication API and sending SMS through another service provider.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
TextEditingController _controller = TextEditingController();
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('AlertDialog Title'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('This is a demo alert dialog.'),
TextField(
controller: _controller,
)
],
),
),
actions: <Widget>[
TextButton(
child: Text('Approve'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
void sendOTP() async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: "your number",
verificationCompleted: (PhoneAuthCredential credential) async {
print("verificationCompleted");
await FirebaseAuth.instance.signInWithCredential(credential);
},
verificationFailed: (FirebaseAuthException e) {
print("FirebaseAuthException");
print(e.code);
},
codeSent: (String verificationID, int token) async {
print("codeSent");
await _showMyDialog();
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.credential(
verificationId: verificationID, smsCode: _controller.text);
await FirebaseAuth.instance.signInWithCredential(phoneAuthCredential);
print("completed");
},
codeAutoRetrievalTimeout: (String verificationID) {
print("$verificationID");
},
timeout: const Duration(seconds: 60),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FlatButton(
child: Text(
"send otp"),
onPressed: sendOTP,
),
),
);
}
}
this is my Code for Phone Authentication using firebase and it is working fine for many mobile numbers
I faced this issue and found out from searching the internet that Firebase's Phone Authentication does not work for users who ported their number from one network to another network. I also found out that other phone authentication SDKS (other than Firebase) has the same issue. The only solution is to give your users the option to sign in with email and password or another sign-in method other than phone authentication. Offering both options will guarantee that user can sign in.

Flutter FirebaseAuth not sending verification code to phone

I'm trying to add a feature on my app that allows users to verify their phone number by sending a code to their phone numbers. I found that I can do that by using firebase. This is how I send verification code:
Future<void> verifyPhone() async {
void verificationCompleted(AuthCredential phoneAuthCredential) {
print('verificationCompleted $phoneAuthCredential');
_phoneAuthCredential = phoneAuthCredential;
_db.updateUserField(userUid, {
'isNumberConfirmed': true,
'linkedAccounts': FieldValue.arrayUnion(['P-$phoneAuthCredential'])
});
currentUser.isNumberConfirmed = true;
currentUser.linkedAccounts.add('P-$phoneAuthCredential');
worked = true;
}
void verificationFailed(FirebaseAuthException error) {
worked = false;
}
void codeSent(String verificationId, [int code]) {
_code = code;
_verificationId = verificationId;
print('Code: $code\t_verificationId: $_verificationId');
}
void codeAutoRetrievalTimeout(String verificationId) {
worked = false;
}
_auth.verifyPhoneNumber(
phoneNumber: '+1${currentUser.phone}',
timeout: Duration(milliseconds: 60000),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
}
but whenever this method get called, I get the following messages and no verification code is sent:
I/BiChannelGoogleApi(25924): [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzao#bafccce
W/DynamiteModule(25924): Local module descriptor class for com.google.firebase.auth not found.
I/FirebaseAuth(25924): [FirebaseAuth:] Preparing to create service connection to gms implementation
I'm not sure why it is not sending the code. Am I missing something?
I find your code hard to debug so I am sharing this :
First make sure you have enabled phone sign in method in firebase console ,
and added Firebase Authentication plugin and Firebase core plugin in pubspec.yaml
define your verify phone number button like this :
onPressed: (){
//code for sign in
final mobile = _phoneTextBoxController.text.trim();
registerUser(mobile, context);
}
Now define whole verifying process like this :
Future registerUser(String mobile, BuildContext context) async{
FirebaseAuth _auth = FirebaseAuth.instance;
_auth.verifyPhoneNumber(
phoneNumber: mobile,
timeout: Duration(seconds: 60),
verificationCompleted: (AuthCredential authCredential){
_auth.signInWithCredential(_credential).then((AuthResult result){
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => HomeScreen(result.user)
));
}).catchError((e){
print(e);
});
},
verificationFailed: (AuthException authException){
print(authException.message);
},
codeSent:(String verificationId, [int forceResendingToken]){
//show dialog to take input from the user
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text("Enter SMS Code"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
controller: _codeController,
),
],
),
actions: <Widget>[
FlatButton(
child: Text("Done"),
textColor: Colors.white,
color: Colors.redAccent,
onPressed: () {
FirebaseAuth auth = FirebaseAuth.instance;
smsCode = _codeController.text.trim();
_credential = PhoneAuthProvider.getCredential(verificationId: verificationId, smsCode: smsCode);
auth.signInWithCredential(_credential).then((AuthResult result){
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => HomeScreen(result.user)
));
}).catchError((e){
print(e);
});
},
)
],
)
);
},
codeAutoRetrievalTimeout: (String verificationId){
verificationId = verificationId;
print(verificationId);
print("Timout");
}
);
So what above code does ? First it sends the OTP code to user and try to sign in using this code :
verificationCompleted: (AuthCredential authCredential){
_auth.signInWithCredential(_credential).then((AuthResult result){
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => HomeScreen(result.user)
));
}).catchError((e){
print(e);
});
},
and pushes user to the home screen , you can change above code accordingly to match your app home screen . If auto retrieval fails then the codeSent : shows user a showDialog to manually enter the code . For more information visit this medium article and for complete code visit this github repository

Navigate to a page after user sign up in the android app in flutter using FirebaseAuth

I am working on phone authentication using flutter and firebase. So, when a user 'Register or Sign Up' for the app an OTP is received and then when he clicks the 'Login' button the phone number gets saved in the firebase but the page does not get loaded. After clicking the Login button, the account gets created but the page doesn't change and I have to close the app and open it again and the main page gets displayed. Please, tell me how to do it.
Code for "Class SignUpView" :
class SignUpView extends StatefulWidget {
#override
_SignUpViewState createState() => _SignUpViewState();
}
class _SignUpViewState extends State<SignUpView> {
final formKey = new GlobalKey<FormState>();
String phoneNo, verificationId, smsCode;
bool codeSent = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 25, right: 25),
child: TextFormField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(hintText: "Enter Phone Number"),
onChanged: (val) {
setState(() {
this.phoneNo = val;
});
},
),
),
codeSent ? Padding(
padding: EdgeInsets.only(left: 25, right: 25),
child: TextFormField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(hintText: "Enter OTP"),
onChanged: (val) {
setState(() {
this.smsCode = val;
});
},
),
): Container(),
Padding(
padding: EdgeInsets.only(left: 25, right: 25),
child: RaisedButton(
child: Center(
child: codeSent ? Text("Login") : Text("Login"),
),
onPressed: () {
codeSent? AuthService().signInWithOTP(smsCode, verificationId):verifyPhone(phoneNo);
},
),
),
],
),
),
);
}
Future<void> verifyPhone(phoneNo) async {
final PhoneVerificationCompleted verified = (AuthCredential authResult) {
AuthService().signIn(authResult);
};
final PhoneVerificationFailed verificationFailed = (
AuthException authException) {
print('${authException.message}');
};
final PhoneCodeSent smsSent = (String verId, [int forceResend]) {
this.verificationId = verId;
setState(() {
this.codeSent = true;
});
};
final PhoneCodeAutoRetrievalTimeout autoTimeOut = (String verId) {
this.verificationId = verId;
};
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: phoneNo,
timeout: const Duration(seconds: 5),
verificationCompleted: verified,
verificationFailed: verificationFailed,
codeSent: smsSent,
codeAutoRetrievalTimeout: autoTimeOut);
}
}
The part of code where I need to add the navigation is:
onPressed: () {
codeSent? AuthService().signInWithOTP(smsCode, verificationId):verifyPhone(phoneNo);
}
There is another part of code- Class AuthService:
class AuthService {
handleAuth() {
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if(snapshot.hasData) {
return Home_Page();
}
else {
return first_screen(); //Login();
}
},
);
}
signOut() {
FirebaseAuth.instance.signOut();
}
signIn(AuthCredential authCreds) {
if(authCreds != null){
FirebaseAuth.instance.signInWithCredential(authCreds);
}
}
signInWithOTP(smsCode, verId) {
AuthCredential authCreds = PhoneAuthProvider.getCredential(verificationId: verId, smsCode: smsCode);
signIn(authCreds);
}
}
I tried to add navigation inside:
onPressed: () {
codeSent? AuthService().signInWithOTP(smsCode, verificationId):verifyPhone(phoneNo);
Navigator.of(context).pushReplacementNamed('/create_account');
}
But this didn't worked as the above code would navigate to the page and the account won't be created.
I want that when the user type the OTP and then click the Login button, then his phone number should get verified and account should be created on firebase and then the user should be displayed another page. You can either use: Navigator.of(context).pushReplacementNamed('/create_account'); or Account_setup_page() for displaying the page.
I'd really be thankful for all the help I can get.
First of all you need to setup a stream for authentication changes in your AuthService class, i.e.
Stream<FirebaseUser> get user {
return _auth.onAuthStateChanged;
}
Then in your home screen (better in a wrapper widget) you could listen to that stream, so if the user is logged in, it will be redirected to the home screen, else it will be redirected to the sign in screen. This can be accomplished with the following code:
final user = Provider.of<FirebaseUser>(context); // listener for auth state
if (user == null) {
return SignUpView(); // or the sign in view
} else {
return Home(user: user,);
// home screen with the user as argument for easier access in the future
}
Maybe in the future when you will implement the sign out feature, this piece of code will automatically redirect the user to the sign in page

Firebase phone login verify using Flutter

I've managed to send an OTP using Firebase. The number also shows up under Authentication -> Users in Firebase Console. What I need to do is that if the number was verified, I want to navigate to next page. How do I do that?
One more thing is that when I enter the number and tap the button 'Verify', it just sends me an OTP message. The app doesn't prompt for the second TextFormField - "Enter OTP". Why is it doing that?
main.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Authenticate().handleAuth(),
);
}
}
authenticate.dart
class Authenticate {
//to handle auth
handleAuth() {
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
return DashBoard();
} else {
return SignIn();
}
},
);
}
//for signin
signIn(AuthCredential authCreds) {
FirebaseAuth.instance.signInWithCredential(authCreds);
}
//for manual otp entry
signInViaOTP(smsCode, verId) {
AuthCredential authCredential = PhoneAuthProvider.getCredential(
verificationId: verId, smsCode: smsCode);
signIn(authCredential);
}
signInViaOTPT(smsCode, verId) {
AuthCredential authCredential = PhoneAuthProvider.getCredential(
verificationId: verId, smsCode: smsCode);
signIn(authCredential);
}
//for signout
signout() {
FirebaseAuth.instance.signOut();
}
}
sign_in.dart
class SignIn extends StatefulWidget {
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final formKey = new GlobalKey<FormState>();
String phoneNo, verId, smsCode;
bool codeSent = false;
Future<void> verifyNum(num) async{
final PhoneVerificationCompleted verified = (AuthCredential authRes){
Authenticate().signIn(authRes);
};
final PhoneVerificationFailed failed = (AuthException authExcep){
};
final PhoneCodeSent smsSent = (String verId, [int forceResend]){
this.verId = verId;
setState(() {
this.codeSent = true;
});
};
final PhoneCodeAutoRetrievalTimeout autoTimeOut = (String verId){
this.verId = verId;
};
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: num,
timeout: const Duration(seconds: 5),
verificationCompleted: verified,
verificationFailed: failed,
codeSent: smsSent,
codeAutoRetrievalTimeout: autoTimeOut
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(hintText: "Enter Phone Number"),
onChanged: (val) {
setState(() {
this.phoneNo = val;
});
},
),
),
codeSent ? Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: TextFormField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(hintText: "Enter OTP"),
onChanged: (val) {
setState(() {
this.smsCode = val;
});
},
),
) : Container(),
Padding(
padding: EdgeInsets.only(left: 25.0, right: 25.0),
child: RaisedButton(
child: Center(
child: codeSent ? Text("Login") : Text("Verify"),
),
onPressed: (){
codeSent? Authenticate().signInViaOTP(smsCode, verId) : verifyNum(phoneNo);
},
),
)
],
),
),
);
}
}
What I need to do is that if the number was verified, I want to navigate to next page. How do I do that?
You'd need to listen for a successful user authentication, then let the user proceed to the next page.
handlePhoneAuth(phoneNumber).then((User user) {
if(user != null) {
NavigateToNextPage();
} else {
// Display errors
}
});
when I enter the number and tap the button 'Verify', it just sends me an OTP message. The app doesn't prompt for the second TextFormField - "Enter OTP". Why is it doing that?
You need to build your own UI for handling the OTP sent to the user's phone number. Related to the above code snippet, here's an example on how you can handle phone authentication using firebase_auth.
Future<User> handlePhoneAuth(String userPhoneNumber) async {
var auth = FirebaseAuth.instance;
auth.verifyPhoneNumber(
phoneNumber: userPhoneNumber,
codeSent: (String verificationId, int resendToken) async {
// Update the UI - wait for the user to enter the SMS code
String smsCode = 'xxxx';
// Create a PhoneAuthCredential with the code
PhoneAuthCredential credential = PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: smsCode);
// Sign the user in (or link) with the credential
var userCredential = await auth.signInWithCredential(credential);
return userCredential.user;
},
verificationFailed: (FirebaseAuthException error) {
debugPrint('Phone Auth failed $error');
return null;
},
verificationCompleted: (PhoneAuthCredential phoneAuthCredential) {
// only available for Android
},
codeAutoRetrievalTimeout: (String verificationId) {
return null;
},
);
}

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;
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"/>
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.
How can I eliminate this error?
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';
}
}
In my case I solved allowing Outgoing Connections on the Xcode's Runner.xcworkspace
In my case, my VPN was causing the problem. Disabling the VPN and testing it again solved the error. I hope it helps.
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!
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.
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.
Kindly find below the image screenshot
"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." - MaximeBeasse
This network error has stopped me too and I have been seeking an answer ... After reading MaximeBeasse's response above and trying it out, I found that it worked : ) Authentication now works! Finally I can move on!
Many thanks #MaximeBeasse -- salute his answer please
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.
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!

Resources