In our previous tutorial we have learn about Online User Registration functionality. This tutorial is the second part of User Registration tutorial. In this tutorial we would perform Login functionality in Flutter mobile app. Login is basically used to perform authentication of app using via Email and Password. If app user dose not register himself then he did not access the Profile area. App user should have to login before accessing the Profile page. We are using MySQL database in our tutorial to storing the user registration records and also we are matching the Login details like Email and Password. We are using PHP(Hyper text pre processor) scripting language. So in this tutorial we would create Flutter Online User Login using PHP MySQL API iOS Android Tutorial.
What we are doing in current tutorial:
In this tutorial we’re performing user login functionality using online PHP MySQL server and if the entered email and password matched then the user will redirect to profile activity screen. If the Login details is not matched then it would show us a Error message response coming from server in Alert dialog message.
Read our Online User Registration Tutorial First Before Getting Started.
Contents in this project Flutter Online User Login using PHP MySQL API iOS Android Example Tutorial:
1. Configure http.dart package for Flutter App:
1. We are using http.dart package in our both tutorials. This package is used to transfer data between client and server in JSON form. The http package did not come inbuilt with flutter project. We have to manually configure it into our Flutter project. So open your project’s pubspec.yaml file.
1 2 3 4 |
dependencies: http: ^0.12.0 flutter: sdk: flutter |
3. Complete Source code for pubspec.yaml file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
name: app description: A new Flutter project. version: 1.0.0+1 environment: sdk: ">=2.1.0 <3.0.0" dependencies: http: ^0.12.0 flutter: sdk: flutter cupertino_icons: ^0.1.2 dev_dependencies: flutter_test: sdk: flutter flutter: uses-material-design: true |
4. After saving the pubspec.yaml file we have to open our Flutter project root folder in command prompt or Terminal and execute flutter pub get command. This command would download and install the added library package in your flutter project.
2. Creating PHP Script to Receive the Sent Email and Password From Flutter App:
1. We have to create a .php extension file named as login_user.php and put all the below code inside the file. Using this file we would first match the entered Email and Password and If entered details is correct then send a Login Matched text to app user so according to that user can navigate to profile screen. If the entered details is incorrect then it will send the app user a error response message.
Source code for login_user.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
<?php //Define your Server host name here. $HostName = "localhost"; //Define your MySQL Database Name here. $DatabaseName = "id11189654_flutter_db"; //Define your Database User Name here. $HostUser = "id11189654_root"; //Define your Database Password here. $HostPass = "1234567890"; // Creating MySQL Connection. $con = mysqli_connect($HostName,$HostUser,$HostPass,$DatabaseName); // Getting the received JSON into $json variable. $json = file_get_contents('php://input'); // Decoding the received JSON and store into $obj variable. $obj = json_decode($json,true); // Getting User email from JSON $obj array and store into $email. $email = $obj['email']; // Getting Password from JSON $obj array and store into $password. $password = $obj['password']; //Applying User Login query with email and password. $loginQuery = "select * from user_registration where email = '$email' and password = '$password' "; // Executing SQL Query. $check = mysqli_fetch_array(mysqli_query($con,$loginQuery)); if(isset($check)){ // Successfully Login Message. $onLoginSuccess = 'Login Matched'; // Converting the message into JSON format. $SuccessMSG = json_encode($onLoginSuccess); // Echo the message. echo $SuccessMSG ; } else{ // If Email and Password did not Matched. $InvalidMSG = 'Invalid Username or Password Please Try Again' ; // Converting the message into JSON format. $InvalidMSGJSon = json_encode($InvalidMSG); // Echo the message. echo $InvalidMSGJSon ; } mysqli_close($con); ?> |
2. We would upload this file to our online hosting server. We have a testing sub domain named as https://flutter-examples.000webhostapp.com/ connecting with Web hosting. We would upload this file to our hosting using File manger. After uploading the file to our server the API url will look like this: https://flutter-examples.000webhostapp.com/login_user.php . We would use this complete URL in our flutter app.
3. Start Coding for App:
1. Import material.dart, Convert and http.dart package in your flutter project’s main.dart file.
1 2 3 |
import 'package:flutter/material.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; |
2. Create our void main runApp() method and call our First MyApp screen class using home property.
1 2 3 4 5 |
void main() => runApp( MaterialApp( home: MyApp(), ) ); |
3. Create our main root class named as MyApp extends with State less widget. In this class we would call the LoginUser() class.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('User Login Form')), body: Center( child: LoginUser() ) ) ); } } |
4. Create a class named as LoginUser extends with State full widget. In this class we would make the createState() method and pass the LoginUserState class. This method would enable the mutable state management in given class tree.
1 2 3 4 5 |
class LoginUser extends StatefulWidget { LoginUserState createState() => LoginUserState(); } |
5. Create our main class named as LoginUserState extends with State. In this class we would make all the Text Field widgets and the Login form is created in this class.
1 2 3 4 |
class LoginUserState extends State { } |
5. Create a Boolean variable named as visible with default false value. We would use this boolean variable to show and hide the Circular Progress Indicator in LoginUserState class.
1 2 |
// For CircularProgressIndicator. bool visible = false ; |
6. Creating two TextEditingController() object with final data type. We would use these objects to retrieve the entered text in Text Field widget in LoginUserState class.
1 2 3 |
// Getting value from TextField widget. final emailController = TextEditingController(); final passwordController = TextEditingController(); |
7. Creating a Future type Async function named as userLogin() in LoginUserState class. We would perform the API web call using this method. We would call this function on button onPress event. In this function first we would perform the Web call and if the response coming from server is same as Login Matched then it would login the user and navigate to Profile activity screen. We would also send the Entered email address to profile activity on Success login.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
Future userLogin() async{ // Showing CircularProgressIndicator. setState(() { visible = true ; }); // Getting value from Controller String email = emailController.text; String password = passwordController.text; // SERVER LOGIN API URL var url = 'https://flutter-examples.000webhostapp.com/login_user.php'; // Store all data with Param Name. var data = {'email': email, 'password' : password}; // Starting Web API Call. var response = await http.post(url, body: json.encode(data)); // Getting Server response into variable. var message = jsonDecode(response.body); // If the Response Message is Matched. if(message == 'Login Matched') { // Hiding the CircularProgressIndicator. setState(() { visible = false; }); // Navigate to Profile Screen & Sending Email to Next Screen. Navigator.push( context, MaterialPageRoute(builder: (context) => ProfileScreen(email : emailController.text)) ); }else{ // If Email or Password did not Matched. // Hiding the CircularProgressIndicator. setState(() { visible = false; }); // Showing Alert Dialog with Response JSON Message. showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: new Text(message), actions: <Widget>[ FlatButton( child: new Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, );} } |
8. Creating 2 Text Input Text Field widget with 1 Raised button in Widget build area in LoginUserState class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( child: Center( child: Column( children: <Widget>[ Padding( padding: const EdgeInsets.all(12.0), child: Text('User Login Form', style: TextStyle(fontSize: 21))), Divider(), Container( width: 280, padding: EdgeInsets.all(10.0), child: TextField( controller: emailController, autocorrect: true, decoration: InputDecoration(hintText: 'Enter Your Email Here'), ) ), Container( width: 280, padding: EdgeInsets.all(10.0), child: TextField( controller: passwordController, autocorrect: true, obscureText: true, decoration: InputDecoration(hintText: 'Enter Your Password Here'), ) ), RaisedButton( onPressed: userLogin, color: Colors.green, textColor: Colors.white, padding: EdgeInsets.fromLTRB(9, 9, 9, 9), child: Text('Click Here To Login'), ), Visibility( visible: visible, child: Container( margin: EdgeInsets.only(bottom: 30), child: CircularProgressIndicator() ) ), ], ), ))); } |
Complete Source Code for LoginUserState class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
class LoginUserState extends State { // For CircularProgressIndicator. bool visible = false ; // Getting value from TextField widget. final emailController = TextEditingController(); final passwordController = TextEditingController(); Future userLogin() async{ // Showing CircularProgressIndicator. setState(() { visible = true ; }); // Getting value from Controller String email = emailController.text; String password = passwordController.text; // SERVER LOGIN API URL var url = 'https://flutter-examples.000webhostapp.com/login_user.php'; // Store all data with Param Name. var data = {'email': email, 'password' : password}; // Starting Web API Call. var response = await http.post(url, body: json.encode(data)); // Getting Server response into variable. var message = jsonDecode(response.body); // If the Response Message is Matched. if(message == 'Login Matched') { // Hiding the CircularProgressIndicator. setState(() { visible = false; }); // Navigate to Profile Screen & Sending Email to Next Screen. Navigator.push( context, MaterialPageRoute(builder: (context) => ProfileScreen(email : emailController.text)) ); }else{ // If Email or Password did not Matched. // Hiding the CircularProgressIndicator. setState(() { visible = false; }); // Showing Alert Dialog with Response JSON Message. showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: new Text(message), actions: <Widget>[ FlatButton( child: new Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, );} } @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( child: Center( child: Column( children: <Widget>[ Padding( padding: const EdgeInsets.all(12.0), child: Text('User Login Form', style: TextStyle(fontSize: 21))), Divider(), Container( width: 280, padding: EdgeInsets.all(10.0), child: TextField( controller: emailController, autocorrect: true, decoration: InputDecoration(hintText: 'Enter Your Email Here'), ) ), Container( width: 280, padding: EdgeInsets.all(10.0), child: TextField( controller: passwordController, autocorrect: true, obscureText: true, decoration: InputDecoration(hintText: 'Enter Your Password Here'), ) ), RaisedButton( onPressed: userLogin, color: Colors.green, textColor: Colors.white, padding: EdgeInsets.fromLTRB(9, 9, 9, 9), child: Text('Click Here To Login'), ), Visibility( visible: visible, child: Container( margin: EdgeInsets.only(bottom: 30), child: CircularProgressIndicator() ) ), ], ), ))); } } |
Screenshot:
9. Create another class named as ProfileScreen extends StatelessWidget. This screen will only be show if user successfully logged in.
1 2 3 4 |
class ProfileScreen extends StatelessWidget { } |
10. Create a String variable named as email in ProfileScreen class.
1 2 |
// Creating String Var to Hold sent Email. final String email; |
11. Creating constructor() in ProfileScreen class and receive the sent email in email string variable.
1 2 |
/ Receiving Email using Constructor. ProfileScreen({Key key, @required this.email}) : super(key: key); |
12. Creating a function named as logout(). We would call this function on Button onPress.
1 2 3 4 5 6 |
// User Logout Function. logout(BuildContext context){ Navigator.pop(context); } |
13. Creating 1 Text widget and 1 Raised button widget in Widget build area in ProfileScreen class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Profile Screen'), automaticallyImplyLeading: false), body: Center( child: Column(children: <Widget>[ Container( width: 280, padding: EdgeInsets.all(10.0), child: Text('Email = ' + '\n' + email, style: TextStyle(fontSize: 20)) ), RaisedButton( onPressed: () { logout(context); }, color: Colors.red, textColor: Colors.white, child: Text('Click Here To Logout'), ), ],) ) ) ); } |
Screenshot:
14. Complete source code for main.dart file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
import 'package:flutter/material.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; void main() => runApp( MaterialApp( home: MyApp(), ) ); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('User Login Form')), body: Center( child: LoginUser() ) ) ); } } class LoginUser extends StatefulWidget { LoginUserState createState() => LoginUserState(); } class LoginUserState extends State { // For CircularProgressIndicator. bool visible = false ; // Getting value from TextField widget. final emailController = TextEditingController(); final passwordController = TextEditingController(); Future userLogin() async{ // Showing CircularProgressIndicator. setState(() { visible = true ; }); // Getting value from Controller String email = emailController.text; String password = passwordController.text; // SERVER LOGIN API URL var url = 'https://flutter-examples.000webhostapp.com/login_user.php'; // Store all data with Param Name. var data = {'email': email, 'password' : password}; // Starting Web API Call. var response = await http.post(url, body: json.encode(data)); // Getting Server response into variable. var message = jsonDecode(response.body); // If the Response Message is Matched. if(message == 'Login Matched') { // Hiding the CircularProgressIndicator. setState(() { visible = false; }); // Navigate to Profile Screen & Sending Email to Next Screen. Navigator.push( context, MaterialPageRoute(builder: (context) => ProfileScreen(email : emailController.text)) ); }else{ // If Email or Password did not Matched. // Hiding the CircularProgressIndicator. setState(() { visible = false; }); // Showing Alert Dialog with Response JSON Message. showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: new Text(message), actions: <Widget>[ FlatButton( child: new Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, );} } @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( child: Center( child: Column( children: <Widget>[ Padding( padding: const EdgeInsets.all(12.0), child: Text('User Login Form', style: TextStyle(fontSize: 21))), Divider(), Container( width: 280, padding: EdgeInsets.all(10.0), child: TextField( controller: emailController, autocorrect: true, decoration: InputDecoration(hintText: 'Enter Your Email Here'), ) ), Container( width: 280, padding: EdgeInsets.all(10.0), child: TextField( controller: passwordController, autocorrect: true, obscureText: true, decoration: InputDecoration(hintText: 'Enter Your Password Here'), ) ), RaisedButton( onPressed: userLogin, color: Colors.green, textColor: Colors.white, padding: EdgeInsets.fromLTRB(9, 9, 9, 9), child: Text('Click Here To Login'), ), Visibility( visible: visible, child: Container( margin: EdgeInsets.only(bottom: 30), child: CircularProgressIndicator() ) ), ], ), ))); } } class ProfileScreen extends StatelessWidget { // Creating String Var to Hold sent Email. final String email; // Receiving Email using Constructor. ProfileScreen({Key key, @required this.email}) : super(key: key); // User Logout Function. logout(BuildContext context){ Navigator.pop(context); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Profile Screen'), automaticallyImplyLeading: false), body: Center( child: Column(children: <Widget>[ Container( width: 280, padding: EdgeInsets.all(10.0), child: Text('Email = ' + '\n' + email, style: TextStyle(fontSize: 20)) ), RaisedButton( onPressed: () { logout(context); }, color: Colors.red, textColor: Colors.white, child: Text('Click Here To Logout'), ), ],) ) ) ); } } |
Screenshots:
Thanks for sharing suhch a nice thought, piece of writing is nice, thats
why i have read it fully
No code this project can download, it’s very difficult to understand
Rizki i have explained every line of project. At last all you have to do id copy and paste the source code.
You are love
Thank you so much. This is exactly what I’ve been looking for.
Welcome Kiet 🙂 .
I have copied the source code and changed the server login api url, but it doesn’t work. Its just keep loading
Antonio you have to make changes in server API also like pass the same param name after login send the response again.
You have to add internet permission in manifest
Même problème que moi monsieur Antoine
I have created the login_user.php. file and then copied the source code with my server login api. How i can make changes in server API ?
You forgot to do a widget n alert for if password n email not match.
Brandon alert is showing on screen if email and password not matched. We are printing response coming from server in Alert. If server sends us email and password not matched then it will show us that in alert.
Tested on Laptop , it is working fine.
Installed on phone it is going round and round and round
Not sure what is happening
Laiq it is working correctly please tell me in which device you are checking it ?
Please gibe us the github link of this project
Mubasher i have not uploaded project on GitHub, All the main files is present here on, Please ask what you need ?
hi sir, does your login has session?
No Dio, It dose not have Login season yet but i will soon post a new tutorial with Season login.
do you have a tutorials for flutter sessions sir?
No Dio not yet, but i will post a new tutorial with season soon.
Thanks a lot for this, it works fine after some tweaking!
However I have the following issue:
Typed password is being compared to the HASHED password stored in the database therefore it gives me a login error. When I manually edit the password in the table by typing something easy then when I test the login function works fine. So there has something to be done in the login_user.php to compare the typed password against the real password that corresponds to the hashed on.
Thanks for your comment Stelios, I will make a new tutorial regarding to your query soon 🙂 .
Idk if iam late, but do you have a new tutorial already ? 🙂
HI Mohit! Great tutorial man! Thanks for sharing and answering all the questions. I have a question for you.. : have you faced any problem maintaining users logged in while using flutter web with your approach? How do you keep users logged in while using flutter web? In our app when they close browser and open again the browser they have to login again but we need them to be able to go directly to their profile page.. Thanks in advance for your help!
Abel you want to automatically logged into browser if they did not log out before ?
Yes.. that’s what we want to accomplish.. automatically login..
Abel you can do this easily by saving fix value in app and each time when you successfully login or log-out change the value. On app start time check the value if the value is found then automatically logged in because on log-out the value will be deleted.
hi i tried this, when i run the app in debug mode it shows this error Exception has occurred.
FormatException (FormatException: Unexpected character (at character 1)
^ at var message = jsonDecode(response.body);
Seb the code is working fine i have just tested the code, Did you put your own server details like database name, password, host name and username ?
i checked again and had a typo error in the php script, thank you so much for this tutorial it has helped me a lot, i was wondering if i need to insert data into another table which has a foreign key, how do i do it using the logged in users id as the foreign key of the table i need to fill in with data, tyvm
Oui Admin, j’ai mes propres détails de serveur avec un notre nom de la base de données, mot de passe, nom d’utilisateur et le nom d’hôte. Ma base de données est hébergé ailleurs.
Please change your php file as given below– just count whether user exist or not in table of BD.
0){
// Successfully Login Message.
$onLoginSuccess = ‘Login Matched’;
// echo $check[‘UN’];
// Converting the message into JSON format.
$SuccessMSG = json_encode($onLoginSuccess);
// Echo the message.
echo $SuccessMSG ;
}
else{
// If Email and Password did not Matched.
$InvalidMSG = ‘Invalid Username or Password Please Try Again’ ;
// Converting the message into JSON format.
$InvalidMSGJSon = json_encode($InvalidMSG);
// Echo the message.
echo $InvalidMSGJSon ;
}
?>
hey i’m getting an error, it always return try again, everything is corret, can you help me?
its from register_user.php, posted wrong
I works in Android and ios but it doesn’t work in flutter web.
Harsh it is working fine could you tell me on which platform you are testing this ?
I can just login when i don’t type any email and password,
Is this normal?
(It works fine when i type email and password. Also i get a alert when password is wrong. But i can just login when the email and password is empty)
This code wasn’t working for me, then I removed the circular indicator and then it worked, i was redirected to my profile screen
Thanks for telling us this 🙂 .
Hello, this code has really helped me in my project. Please I would like to know how to keep user logged in, even when the app is re-started. Thanks in advance! (Flutter & PHP MySql)
this was soo helpful sir but i also want (change password) code in php mysql like this…(I’m confuse in change password through php script).
Hello, thank you the tutorial is really helpful! Unfortunately, I have changed all the parameters, but the screen keeps loading and this error comes up: [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: FormatException: Unexpected character (at character 1)
Hi Sir, your backend code should be rewritten because is very unsafe. First of all you didn’t hash the password, and secondly you didn’t sanitize the input.
Also you didn’t check that the post is coming from the app.
This code is useful only for teching purposes
Thanks for giving me your opinion. This code is for teaching purpose but in the future I’ll make the backend code with your given suggestion 🙂 .
In the login_user.php file, in line 19, what is ‘php://input’?
is it a path? or a file? if it is a file, it is not given to us. and what does it do?
Merci infiniment pour ce tutoriel malgré ça ne fonctionne pas encore chez moi, je reçois le message d’erreur dans l’émulateur : “XMLHTttpRequest error” quand je valide mon formulaire. Pourriez-vous nous présenter le même tutoriel qui est à jour ?