Flutter + Firebase phone OTP does not work for other countries - android

I am developing a mobile app for a Germany client. I am based in Sri Lanka. The OTP works well in my country but, not for other countries. I tried to enter the German phone number from Sri Lanka, it works fine. He gets the OTP code when I am trying to send OTP to his phone from Sri Lanka. But, when he tries in Germany, it does not work.
Then after that, I connected to a German VPN and tried, I am also failed to get OTP. Then, I connected with other countries' VPN and tried. It does not work. It only works when I am connected to Sri Lankan's network.
I am confused, Do I need to turn on anything in Firebase to send OTP globally. Please try to provide your answer to me.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("Login"),),
body: const MyApp(),
),
);
}
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var otpController = TextEditingController();
var numController = TextEditingController();
FirebaseAuth auth = FirebaseAuth.instance;
String verificationId = "";
void signInWithPhoneAuthCredential(
PhoneAuthCredential phoneAuthCredential) async {
try {
final authCredential =
await auth.signInWithCredential(phoneAuthCredential);
if (authCredential.user != null) {
print("Welcome");
Text("Welcome");
}
} on FirebaseAuthException catch (e) {
print("catch");
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(10),
child: TextField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Phone Number',
hintText: 'Enter valid number'
),
controller: numController,
),
),
Padding(
padding: EdgeInsets.all(10),
child: TextField(
obscureText: true,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
hintText: 'Enter valid password'
),
controller: otpController,
),
),
TextButton(onPressed: () {
fetchotp();
}, child: const Text("Fetch OTP"),),
TextButton(onPressed: () {
verify();
}, child: const Text("Send"))
],
),
);
}
Future<void> verify() async {
PhoneAuthCredential phoneAuthCredential =
PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: otpController.text);
signInWithPhoneAuthCredential(phoneAuthCredential);
}
Future<void> fetchotp() async {
await auth.verifyPhoneNumber(
phoneNumber: '+94769008291',
verificationCompleted: (PhoneAuthCredential credential) async {
await auth.signInWithCredential(credential);
},
verificationFailed: (FirebaseAuthException e) {
if (e.code == 'invalid-phone-number') {
print('The provided phone number is not valid.');
}
},
codeSent: (String verificationId, int? resendToken) async {
this.verificationId = verificationId;
},
codeAutoRetrievalTimeout: (String verificationId) {
},
);
}
}

I suggest that you reach out to the Firebase team via their Support Contact page. This should work in Germany given that it is what the documentation suggests.

Related

Flutter: TCP socket connection fails on real device

I'm posting this even though I already solved the issue, because I spent more than an hour trying to figure out what was causing it, and might help someone else.
I have a simple application that connects to a server through a TCP socket. It works fine inside the debugger with the device emulator, but when I deploy it on a real device it fails to connect immediately.
Further investigations led me to finding out that the socket was actually throwing the following exception:
SocketException: Connection failed (OS Error: Operation not permitted, errno = 1), address = 192.168.1.46, port = 40001
Code sample
Connect button opens a socket on _host:_port
Send Radar Distance button sends a message formatted like {"distance": _distance, "angle": _angle} on the socket.
Status and Message fields show info about the socket status and eventually useful infos.
main.dart
import 'package:flutter/material.dart';
import 'views/view_test.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ViewTest(),
);
}
}
views/view_test.dart
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const List<String> materialTypes = <String>['PLASTIC', 'GLASS'];
class ViewTest extends StatefulWidget {
const ViewTest({Key? key}) : super(key: key);
#override
State<ViewTest> createState() => _ViewTestState();
}
class _ViewTestState extends State<ViewTest> {
String _distance = "";
String _angle = "";
String _status = "";
String _message = "";
Socket? _socket;
final String _host = "192.168.1.46";
final int _port = 4001;
Future<void> _sendMessage(String message) async {
print("Sent message $message");
_socket!.write(message);
await Future.delayed(const Duration(seconds: 1));
}
void _connect(String ip, int port) async {
Socket? sock;
try {
sock =
await Socket.connect(ip, port, timeout: const Duration(seconds: 3));
_socket = sock;
setState(() {
_status = "Connected to $ip:$port.";
_message = "";
});
// listen for responses from the server
_socket!.listen(
// handle data from the server
(Uint8List data) {
final serverResponse = String.fromCharCodes(data);
setState(() {
_message = serverResponse;
});
print(serverResponse);
},
// handle errors
onError: (error) {
setState(() {
_status = "Disconnected.";
_message = "Error: $error";
});
print("Error: $error");
_socket!.destroy();
_socket = null;
},
// handle server ending connection
onDone: () {
setState(() {
_status = "Disconnected.";
_message = 'Server left.';
});
print('Server left.');
_socket!.destroy();
_socket = null;
},
);
} catch (e) {
setState(() {
_status = "Connection failed.";
_message = e.toString();
});
print("Error: ${e.toString()}");
}
}
void _disconnect() {
if (_socket != null) _socket!.destroy();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text("Radar Test")),
),
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 50.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
_status = "";
_message = "";
});
_disconnect();
_connect(_host, _port);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
_socket == null ? 'Connect' : 'Reconnect',
style: const TextStyle(fontSize: 22.0),
),
),
),
const SizedBox(height: 50.0),
TextField(
onChanged: (text) {
_distance = text;
},
keyboardType:
const TextInputType.numberWithOptions(decimal: false),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'[0-9]+'), // this regex allows only decimal numbers
)
],
decoration: const InputDecoration(
hintText: '100',
border: UnderlineInputBorder(),
labelText: 'Distance',
),
),
TextField(
onChanged: (text) {
_angle = text;
},
keyboardType:
const TextInputType.numberWithOptions(decimal: false),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'[0-9]+'), // this regex allows only decimal numbers
)
],
decoration: const InputDecoration(
hintText: '90',
border: UnderlineInputBorder(),
labelText: 'Angle',
),
),
const SizedBox(height: 50.0),
Text("Status: $_status"),
Text("Message: $_message"),
],
),
),
),
floatingActionButton: ElevatedButton(
onPressed: _socket == null
? null
: () {
// test
_sendMessage(
'{"distance": ${_distance.isEmpty ? 100 : int.parse(_distance)}, "angle": ${_angle.isEmpty ? 90 : int.parse(_angle)}}');
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Send Radar Distance',
style: TextStyle(fontSize: 22.0),
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
Turns out I had to give the application Internet permissions, as stated in Flutter docs about Networking. So I added the following line to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
NB: AndroidManifest.xml manifest is located in the following location:
android > app > src > main > AndroidManifest.xml

Firebase auth not persisting on iOS or Android in Flutter

To start, I have gone through more than 20 different questions and solutions here on Stack Overflow about this topic (most of them are related to the web version), I have also tried twitter, and even the FlutterDev Discord server and cannot seem to find this issue.
I am using firebase for mobile authentication for my app, and no matter what I try, I cannot seem to get the persistent auth state to work on iOS or Android.
Here is my main:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
...
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
final const ColorScheme colorScheme = ColorScheme(
...
);
#override
Widget build(BuildContext context) {
bool isDebug = false;
if (Constants.DEBUG_BANNER == 'true') {
isDebug = true;
}
return MaterialApp(
theme: ThemeData(
...
),
routes: {
// This is a general layout of how all my routes are in case this is the issue
Screen.route: (BuildContext context) => const Screen(),
},
home: const HomeScreen(),
debugShowCheckModeBanner: isDebug,
);
}
}
the ... is just code that I think is unrelated to my question and so I am hiding it for brevity. Mostly themes, and private data
Let's just start with my google-sign-in-button and if necessary I can share others if it is important. We are using Facebook, Google, and Apple for iOS.
class GoogleSignInButton extends StatefulWidget {
const GoogleSignInButton({Key? key}) : super(key: key);
#override
_GoogleSignInButtonState createState() => _GoogleSignInButtonState();
}
class _GoogleSignInButtonState extends State<GoogleSignInButton> {
bool _isSigningIn = false;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: _isSigningIn
? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(MRRM.colorScheme.primary),
)
: OutlinedButton(
key: const Key('google_sign_in_button'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
),
),
onPressed: () async {
setState(() {
_isSigningIn = true;
});
context.read<Member>().signInWithGoogle(context: context).then<void>((void user) {
setState(() {
_isSigningIn = false;
});
Navigator.pushReplacementNamed(context, UserInfoScreen.route);
});
},
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Image(
image: AssetImage('assets/images/png/google_logo.png'),
height: 35.0,
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
'Sign in with Google',
style: TextStyle(
fontSize: 20,
color: MRRM.colorScheme.secondary,
fontWeight: FontWeight.w600,
),
))
],
),
),
),
);
}
}
I am using the provider pub, which is what context.read<Object?>() is from.
Here is the signInWithGoogle function;
Future<String> signInWithGoogle({required BuildContext context}) async {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
final GoogleSignInAccount? googleSignInAccount =
await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
try {
final UserCredential userCredential =
await _auth.signInWithCredential(credential);
_firebaseUser = userCredential.user!;
_authType = AuthType.Google;
_uuId = _firebaseUser.uid;
notifyListeners();
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'The account already exists with different credentials.',
),
);
} else if (e.code == 'invalid-credential') {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'Error occurred while accessing credentials. Try again.',
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'Error occurred using Google Sign-In. Try again.',
),
);
}
}
return getMemberLogin();
}
This is contained in my Member object, which just stores all of the Auth data as well as the Member specific data that comes from one of our internal API's, and the member data is stored as an App State object in provider, which is linked in the main.dart file
The getMemberLogin() function is just taking the UUID from the auth and sending it to an API and getting internal member data, I would hope that a simple post request isn't what is causing this. but if you think it might let me know and I will try to post it while obfuscating any NDA related data.
This is the home/splash Screen that handles the initial routing and goes to the loadingScreen that is supposed to be checking if there is a persisted login and going to the UserInfo screen instead of the Auth Screen.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static const String route = '/home';
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
key: const Key('Home'),
children: <Widget>[
Expanded(
child: Image.asset('assets/images/png/Retail_Rebel_Primary.png'),
),
BlinkingTextButton(
key: const Key('blinking_text_button'),
textButton: TextButton(
child: Text(
'Tap to continue',
style: TextStyle(
color: MRRM.colorScheme.primary,
fontSize: 16.0,
),
),
onPressed: () {
Navigator.of(context).pushReplacementNamed(LoadingScreen.route);
},
),
),
Container(
height: 8.0,
),
],
),
);
}
}
And lastly, this is the LoadingScreen that the HomeScreen navigates to:
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}
Not sure if possibly the way that I am handing routing may be the issue, but it is very common for me to use Navigator.of(context).pushReplacementNamed(); unless popping is necessary then I will typically just use Navigator.of(context).pop();. I usually only use .pop() for modals/alertDialogs, and for things like QR scanners to return to previous screen.
Sorry if this is too much info, or I forgot a ton of stuff. I have been working on trying to get this fixed for a little over a week now and am kind of getting frustrated.
Thank you for any and all responses.
Just because I think it is important to see what I have looked at already, here is a list of a couple of other questions I have looked through that did not help.
This one I believe is dated as of August 2020, especially considering that onAuthStateChanges has been changed to a stream authStateChanges().
I have also tried just implementing auth in the exact way described in the docs here but same issue.
I also tried just using:
FirebaseAuth.instance.authStateChanges().then((User? user) {
if (user != null) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
} else {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
}
Which didn't work. I have also attempted to just simply check if there is a current user with:
User user = FirebaseAuth.instance.currentUser;
if (user != null && user.uid != null) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
} else {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
}
which still always went to AuthScreen I have also tried all of these methods as asynchronous tasks to see if maybe it is just taking a second to load, and same issue. The weirdest one is with the current method if I take out the if(snapshot.connectionState == ConnectionState.waiting) from the LoadingScreen it will print out no user is logged in immediately followed by user is logged in and then no user is logged in again and then it will navigate to AuthScreen
If you follow what I have done up above, and make a single change, it will work with persisted logins.
change:
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}
to
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}

Auto detect firebase Phone Auth sms code in Flutter

Please read properly and then comment, hope this help full for software community.
I unable to auto detect firebase phone auth sms, when i test in android it's work without doing anything, but when i tried it in flutter sms not detected automatically, require manually type sms code, I did not find any documentation to do this process automatically.
I wan't to know how to detect automatically that sms code from Firebase phone auth
Future<void> verifyPhone() async {
starTimer();
phoneNumber = contryCode+mobile_controller.text;
final PhoneCodeAutoRetrievalTimeout autoReRetrive = (String verId) {
this.verificationId = verId;
};
final PhoneCodeSent smsCodesent = (String verId, [int forceCodeResent]) {
this.verificationId = verId;
pageController.animateToPage(2, duration: Duration(milliseconds: 300), curve: Curves.easeInBack);
/*smsCodeDialog(context).then((value) {
print("VERIFY PHONE SIGN IN");
});
*/
};
final PhoneVerificationCompleted phoneVerificationCompleted =
(PhoneAuthCredential creditional) {
print("VERIFY PHONE AUTH SUCESS");
this.mPhoneCreditional=creditional;
//_controller.animateToPage(3, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
loginIn(creditional);
};
final PhoneVerificationFailed phoneVerificationFailed =
(FirebaseAuthException excepton) {
Fluttertoast.showToast(
msg: excepton.message,
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
);
print("VERIFY PHONE AUTH FAILED " + excepton.message);
};
FirebaseAuth mAuth=await FirebaseAuth.instance;
mAuth.setLanguageCode("en");
await mAuth.verifyPhoneNumber(
phoneNumber: phoneNumber,
timeout: const Duration(seconds: 45),
verificationCompleted: phoneVerificationCompleted,
verificationFailed: phoneVerificationFailed,
codeSent: smsCodesent,
codeAutoRetrievalTimeout: autoReRetrive);
}
Make sure you have added the debugging, release, sha1, sha256 keys to your firebase project.
Make sure you have enabled appcheck enabled on your firebase project.
Make sure you have enabled the Android Device Verification api on your google cloud console.
The below code is slightly modified from the example code given in firebase auth plugin, for my projects the detecion is working well.
Some devices may fail to detect the otp, but most of the devices will login automatically.
The code which detects the sms is highlighted in sendOtpFn()
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:projdebug/Widgets/Widgets.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => LoginPageState();
}
class LoginPageState extends State<LoginPage> {
final FirebaseAuth _auth = FirebaseAuth.instance;
final _phoneNumberController = TextEditingController();
final _smsController = TextEditingController();
String _message = '';
late String _verificationId;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
setState(() {});
}),
body: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
alignment: Alignment.center,
child: const Text(
'Test sign in with phone number',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
TextFormField(
controller: _phoneNumberController,
decoration: const 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),
alignment: Alignment.center,
child: Button(
icon: Icons.send,
buttonColor: Colors.deepOrangeAccent[700]!,
text: 'Send otp',
onPressed: sendOtpFn,
),
),
TextField(
controller: _smsController,
decoration:
const InputDecoration(labelText: 'Verification code'),
),
Container(
padding: const EdgeInsets.only(top: 16),
alignment: Alignment.center,
child: Button(
icon: Icons.done,
buttonColor: Colors.deepOrangeAccent[400]!,
onPressed: manualSignInFn,
text: 'Confirm otp',
),
),
CrossFade(
show: _auth.currentUser?.uid != null,
child: Button(
icon: Icons.logout,
buttonColor: Colors.deepOrangeAccent[400]!,
onPressed: () async{
await _auth.signOut();
setState(() {});
},
text: 'LogOut',
),
),
Visibility(
visible: _message.isNotEmpty,
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
_message,
style: const TextStyle(color: Colors.red),
),
),
)
],
),
),
),
);
}
// Example code of how to verify phone number
Future<void> sendOtpFn() async {
setState(() {
_message = '';
});
///This is the code snippet which [detects the code from sms automatically]
PhoneVerificationCompleted verificationCompleted =
(PhoneAuthCredential phoneAuthCredential) async {
setState(() {
_message = phoneAuthCredential.smsCode ?? "";
_smsController.text = _message;
});
await _auth.signInWithCredential(phoneAuthCredential);
Widgets.showToast(
'Phone number automatically verified and user signed in: $phoneAuthCredential');
setState(() {});
};
PhoneVerificationFailed verificationFailed =
(FirebaseAuthException authException) {
setState(() {
_message =
'Phone number verification failed. Code: ${authException.code}. '
'Message: ${authException.message}';
});
};
PhoneCodeSent codeSent =
(String verificationId, [int? forceResendingToken]) async {
Widgets.showToast('Please check your phone for the verification code.');
_verificationId = verificationId;
};
PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
(String verificationId) {
_verificationId = verificationId;
};
try {
await _auth.verifyPhoneNumber(
phoneNumber: _phoneNumberController.text,
timeout: const Duration(seconds: 120),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
} catch (e) {
Widgets.showToast('Time out to Verify Phone Number: $e');
}
}
///Code which will be executed only when a confirm otp button is pressed, ie both phoneNumber & otp is typed by the user manually.
Future<void> manualSignInFn() async {
try {
final PhoneAuthCredential credential = PhoneAuthProvider.credential(
verificationId: _verificationId,
smsCode: _smsController.text,
);
final User user = (await _auth.signInWithCredential(credential)).user!;
Widgets.showToast('Successfully signed in UID: ${user.uid}');
} catch (e) {
print(e);
Widgets.showToast('Failed to sign in');
}
}
}

This happens because you used a `BuildContext` that does not include the provider of your choice

I am Working on Flutter App Both for web and mobile and stuck at the Following Error:
======== Exception caught by widgets library =======================================================
The following ProviderNotFoundException was thrown building Products(dirty):
Error: Could not find the correct Provider<List<ProductsModel>> above this Products Widget
This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- You added a new provider in your `main.dart` and performed a hot-reload.
To fix, perform a hot-restart.
- The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that Products is under your MultiProvider/Provider<List<ProductsModel>>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
```
consider using `builder` like so:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
```
The relevant error-causing widget was:
Products file:///E:/Flutter%20Projects/flutter_web_firebase_host/lib/screens/home/home.dart:37:63
When the exception was thrown, this was the stack:
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49 throw_
packages/provider/src/provider.dart 332:7 _inheritedElementOf
packages/provider/src/provider.dart 284:30 of
packages/flutter_web_firebase_host/screens/databaseScreens/products.dart 10:31 build
packages/flutter/src/widgets/framework.dart 4569:28 build
...
====================================================================================================
Main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:flutter_web_firebase_host/provider/product_provider.dart';
import 'package:flutter_web_firebase_host/screens/wrapper.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final firestoreServise = FirestoreService();
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
/* child: StreamProvider<Users>.value(
value: AuthService().user,
initialData: null*/
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Wrapper(),
),
);
// );
}
Product.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/edit_product.dart';
import 'package:provider/provider.dart';
class Products extends StatelessWidget {
#override
Widget build(BuildContext context) {
final products = Provider.of<List<ProductsModel>>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: Text('Products'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => EditProduct()));
}),
],
),
body: (products != null)
? ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(products[index].name),
trailing: Text(products[index].price.toString()),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditProduct(products[index])));
},
);
},
)
: Center(child: CircularProgressIndicator()));
}
}
Home.dart
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/products.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/shared/drawer.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
backgroundColor: Colors.brown[100],
appBar: AppBar(
title: Text('Brew Crew'),
backgroundColor: Colors.brown[100],
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person),
label: Text('logout'),
onPressed: () async {
await _auth.signOut();
},
),
IconButton(
icon: Icon(Icons.add, color: Colors.black),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Products()));
}),
],
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 50, 0, 0),
child: Container(
child: Text(
'Stock Market',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
)),
),
),
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Image.asset(
"assets/graph.jpg",
width: 500,
height: 600,
),
),
),
],
),
),
),
drawer: MyDrawer(),
),
);
}
}
product_provider.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:uuid/uuid.dart';
class ProductProvider with ChangeNotifier {
final firestoreService = FirestoreService();
String _name;
double _price;
String _productId;
var uuid = Uuid();
//Geters
String get name => _name;
double get price => _price;
//Seters
changeName(String value) {
_name = value;
notifyListeners();
}
changePrice(String value) {
_price = double.parse(value);
notifyListeners();
}
loadValues(ProductsModel product) {
_name=product.name;
_price=product.price;
_productId=product.productId;
}
saveProduct() {
print(_productId);
if (_productId == null) {
var newProduct = ProductsModel(name: name, price: price, productId: uuid.v4());
firestoreService.saveProduct(newProduct);
} else {
//Update
var updatedProduct =
ProductsModel(name: name, price: _price, productId: _productId);
firestoreService.saveProduct(updatedProduct);
}
}
}
Authservise.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on firebase user
Users _userFromFirebaseUser(User user) {
return user != null ? Users(uid: user.uid) : null;
}
// auth change user stream
Stream<Users> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
// sign in anon
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in with email and password
Future signInWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
User user = result.user;
return user;
} catch (error) {
print(error.toString());
return null;
}
}
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user;
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
}
//sign in with google
Future<bool> loginWithGoogle() async {
try {
GoogleSignIn googleSignIn = GoogleSignIn();
GoogleSignInAccount account = await googleSignIn.signIn();
if(account == null )
return false;
UserCredential res = await _auth.signInWithCredential(GoogleAuthProvider.credential(
idToken: (await account.authentication).idToken,
accessToken: (await account.authentication).accessToken,
));
if(res.user == null)
return false;
return true;
} catch (e) {
print(e.message);
print("Error logging with google");
return false;
}
}
}
Basically my app is connect to firebase both for web app and android app. Also i send data to firestore from my app but when i click the add button to go to textfield to send data it give the error as i mention it in start. I am using multiprovider as you can see my main.dart code
Is There anything I missing. I need Help.
the way to fix this is to put MultiProvider as parent of myApp in your main like this
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
child:MyApp(
));

Firebase Phone Authentication using Flutter

Hi Im new in flutter and trying to use firebase phone authentication by using flutter. however, when I try to press the button, I get the following error.
I am using AndroidStudio.
Xcode build done. 21.5s
path: satisfied (Path is satisfied), interface: en0
Configuring the default Firebase app...
Configured the default Firebase app __FIRAPP_DEFAULT.
path: satisfied (Path is satisfied), interface: en0
Syncing files to device iPhone 11 Pro Max...
*** First throw call stack:
(
0 CoreFoundation 0x00007fff23c7127e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x00007fff513fbb20 objc_exception_throw + 48
2 CoreFoundation 0x00007fff23c710bc +[NSException raise:format:] + 188
3 Runner 0x0000000103e97d81 -[FIRPhoneAuthProvider verifyPhoneNumber:UIDelegate:completion:] + 193
4 Runner 0x000000010440dc3d -[FLTFirebaseAuthPlugin handleMethodCall:result:] + 18109
5 Flutter 0x000000010600ddb5 __45-[FlutterMethodChannel setMethodCallHandler:]_block_invoke + 104
6 Flutter 0x0000000105fa1ba0 _ZNK7flutter21PlatformMessageRouter21HandlePlatf<…>
Lost connection to device.
This is my code. Please someone help me
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
// initialRoute: '/',
// routes: {
// '/' : (context) => WelcomeClass(),
// '/LoginClass' : (context) => LoginClass(),
// '/SignUpClass' : (context) => SignUpClass(),
// },
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String phoneNo;
String smsCode;
String verificationId;
Future<void> verifyPhone() async {
final PhoneCodeAutoRetrievalTimeout autoRetrieve = (String verId) {
this.verificationId = verId;
};
final PhoneCodeSent smsCodeSent = (String verId, [int forceCodeResend]) {
this.verificationId = verId;
smsCodeDialog(context).then((value){
print('signed in');
});
};
final PhoneVerificationCompleted verificationSuccess = (AuthCredential user){
print('Phone Verification Completed');
};
final PhoneVerificationFailed verificationFailed =
(AuthException exception) {
print('${exception.message}');
};
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: this.phoneNo,
codeAutoRetrievalTimeout: autoRetrieve,
codeSent: smsCodeSent,
timeout: const Duration(seconds: 60),
verificationCompleted: verificationSuccess,
verificationFailed: verificationFailed,
);
}
Future<bool> smsCodeDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return new AlertDialog(
title: Text('Enter sms code'),
content: TextField(
onChanged: (value) {
this.smsCode = value;
},
),
contentPadding: EdgeInsets.all(10),
actions: <Widget>[
FlatButton(
child: Text('Done'),
onPressed: () {
FirebaseAuth.instance.currentUser().then((user) {
if (user != null) {
Navigator.of(context).pop();
Navigator.of(context)
.pushReplacementNamed('/SignUpClass');
} else {
Navigator.of(context).pop();
signIn();
}
});
},
)
],
);
});
}
signIn() {
final AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId, smsCode: smsCode);
FirebaseAuth.instance.signInWithCredential(credential).then((user) {
Navigator.of(context).pushReplacementNamed('/homepage');
}).catchError((e) {
print('Auth Credential Error : $e');
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(38.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
onChanged: (value) {
this.phoneNo = value;
},
),
SizedBox(
height: 40,
),
FlatButton(
child: Text("Send code"),
onPressed: verifyPhone,
), //FlatButton
], // Widget
),
), // Column
);
}
}
I feel that there is something wrong with the flutter I installed.
Ive also tried to run on my real phone but it crashed too.

Categories

Resources