DEV Community

Cover image for Flutter - Firebase Google Sign-in Auth + SplashScreen using updated API
Sumanth
Sumanth

Posted on • Updated on

Flutter - Firebase Google Sign-in Auth + SplashScreen using updated API

0.Introduction

Have you ever wanted to implement user authentication in your flutter Application? Well, you've come to the right place..!
Let's see how to add GoogleSignIn() auth using Firebase Authenticationn.

What you'll learn

  • Adding SplashScreen to your app
  • Navigating user from the SplashScreen to AuthScreen or HomeScreen
  • GoogleSignIn Authentication

Demo of the final implementation...
Flow Chart

What is Firebase? (quick intro..)

Firebase is Google's mobile platform with a variety of services to build & ship our apps quickly. It is categorized as a NoSQL database and stores data in JSON like documents.

I writ code

1.Setup Firebase Project

Head over to Firebase Console then add a new project.
To keep things simple and short I'm not explaining every step here. Trust me next steps are pretty clear to add your app to firebase.

  • Make sure to set up a sign-in method in the Authentication section of firebase console. Otherwise, things are not gonna work as expected.

At a particular step, it asks you to enter SHA-1 Key to complete the process. Run this command in your cmd to get the SHA-1 key.

keytool -list -v -alias androiddebugkey -keystore C:\Users\YOUR_USER_NAME_HERE\.android\debug.keystore
Enter fullscreen mode Exit fullscreen mode

2.Write some Code

Before writing code let's understand what we are going to build.

When the user opens app for the first time we should navigate user from SplashScreen to AuthScreen.
Next time when the user opens the app we should check if user is already logged in or not.
If user = loggedIn then navigate to HomeScreen by skipping AuthScreen. ELSE navigate user from SplashScreen to AuthScreen.

Flow Chart

Let's write some code🥳

I write code

Packages that we'll use:

  • firebase_auth: ^0.18.3
    • firebase_core: ^0.5.2
    • google_sign_in: ^4.5.6

Add the above 3 packages to your pubspec.yaml file
And for every flutter app using Firebase, we must use the firebase_core package. And then you must initialize the app.
await Firebase.initializeApp();
If you don't initialize the app you may get the below error.

[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()

  1. Fire-up your preferred code editor and open your main.dart file. Remove all the boiler-plate code in main.dart file and add the below code.
import 'package:YOUR_PROJECT_NAME/screens/splashscreen.dart';
import 'package:YOUR_PROJECT_NAME/screens/authscreen.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';

// Defining routes for navigation
var routes = <String, WidgetBuilder>{
  "/auth": (BuildContext context) => AuthScreen(),
};

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: 'FaceBase',
    routes: routes,
    home: SplashScreen(),
  ));
}

Enter fullscreen mode Exit fullscreen mode

2.Let's build UI for the remaining screens

  • SplashScreen UI and Logic

Create a new dart file named splashscreen.dart inside the lib/screens folder.
Your splashscreen.dart should look like this..

import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_gsignin/screens/homescreen.dart';
import 'package:flutter/material.dart';

class SplashScreen extends StatefulWidget {
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  User _user;
  @override
  void initState() {
    super.initState();
    initializeUser();
    navigateUser();
  }

  Future initializeUser() async {
    await Firebase.initializeApp();
    final User firebaseUser = await FirebaseAuth.instance.currentUser;
    await firebaseUser.reload();
    _user = await _auth.currentUser;
    // get User authentication status here
  }

  navigateUser() async {
    // checking whether user already loggedIn or not
    if (_auth.currentUser != null) {
      // &&  FirebaseAuth.instance.currentUser.reload() != null
      Timer(
        Duration(seconds: 3),
        () => Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(
                builder: (context) =>
                    HomeScreen(username: _auth.currentUser.displayName)),
            (Route<dynamic> route) => false),
      );
    } else {
      Timer(Duration(seconds: 4),
          () => Navigator.pushReplacementNamed(context, "/auth"));
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: Text("Design Your splash screen"),
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Create a another dart file named homescreen.dart inside the lib/screens folder.
And paste the below code into your homescreen

import 'package:firebase_gsignin/screens/authscreen.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';

class HomeScreen extends StatefulWidget {
 final String username;
  HomeScreen({Key key, @required this.username}) : super(key: key);
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Hello "+ widget.username),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.exit_to_app),
            onPressed: () async {
              await FirebaseAuth.instance.signOut();
              await googleSignIn.disconnect();
              await googleSignIn.signOut();
              Navigator.of(context).pushAndRemoveUntil(
                  MaterialPageRoute(builder: (context) => AuthScreen()),
                  (Route<dynamic> route) => false);
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              onPressed: () async {
                await FirebaseAuth.instance.signOut();
                await googleSignIn.disconnect();
                await googleSignIn.signOut();
                Navigator.of(context).pushAndRemoveUntil(
                    MaterialPageRoute(builder: (context) => AuthScreen()),
                    (Route<dynamic> route) => false);
              },
              child: Text("Log Out"),
              color: Colors.redAccent,
            ),
            SizedBox(
              height: 10.0,
            ),
          ],
        ),
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

Let's implement Firebase Authentication

Create a new file named authscreen.dart inside lib/screens folder in which we'll set up google sign in and AuthScreen UI.

  • Code for the authscreen.dart UI and logic:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_gsignin/screens/homescreen.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';

String name;
String email;
String imageUrl;
final FirebaseAuth auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
class AuthScreen extends StatefulWidget {
  @override
  _AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
  bool isVisible = false;
  Future<User> _signIn() async {
    await Firebase.initializeApp();
    final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
    final GoogleSignInAuthentication googleSignInAuthentication =
        await googleSignInAccount.authentication;
    final AuthCredential credential = GoogleAuthProvider.credential(
      idToken: googleSignInAuthentication.idToken,
      accessToken: googleSignInAuthentication.accessToken,
    );
    // final AuthResult authResult = await auth.signInWithCredential(credential);
    // final User user = authResult.user;

    User user = (await auth.signInWithCredential(credential)).user;
    if (user != null) {
      name = user.displayName;
      email = user.email;
      imageUrl = user.photoURL;
    }
    return user;
  }
  @override
  Widget build(BuildContext context) {
    var swidth = MediaQuery.of(context).size.width;
    return Scaffold(
      body: Stack(
        children: <Widget>[
          Container(
            decoration: BoxDecoration(
                image: DecorationImage(
                    image: AssetImage("assets/images/bg.png"),
                    fit: BoxFit.cover)),
          ),
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Visibility(
                child: CircularProgressIndicator(
                  valueColor: AlwaysStoppedAnimation<Color>(Color(0xFFB2F2D52)),
                ),
                visible: isVisible,
              )
            ],
          ),
          Container(
            margin: const EdgeInsets.only(
              bottom: 60.0,
            ),
            child: Align(
              alignment: Alignment.bottomCenter,
              child: SizedBox(
                height: 54.0,
                width: swidth / 1.45,
                child: RaisedButton(
                  onPressed: () {
                    setState(() {
                      this.isVisible = true;
                    });
                    _signIn().whenComplete(() {
                      Navigator.of(context).pushAndRemoveUntil(
                          MaterialPageRoute(
                              builder: (context) => HomeScreen(username: name)),
                          (Route<dynamic> route) => false);
                    }).catchError((onError) {
                      Navigator.pushReplacementNamed(context, "/auth");
                    });
                  },
                  child: Text(
                    ' Continue With Google',
                    style: TextStyle(fontSize: 16),
                  ),
                  shape: RoundedRectangleBorder(
                    borderRadius: new BorderRadius.circular(30.0),
                  ),
                  elevation: 5,
                  color: Color(0XFFF7C88C),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

3.Conclusion

Well, we've successfully implemented authentication in our flutter app.
congrats gif
If you've any doubts, you can find the GitHub repo of this super simple project in the following link:

App ScreenShots

screenshots

keep Fluttering!

Thank you for reading, if you found the article useful make sure to show some love.
-Moving Melody
Let's catch up on Twitter!

Top comments (14)

Collapse
 
iamnikhilpardeshi profile image
Nikhil Pardeshi

Sir, first time the program is run without error. Bt second time I open this app show error In home screen. Invalid arguments. What to do??

Collapse
 
sai7xp profile image
Sumanth

Hey Nikhil, thank you for noticing and pointing out the error. (fixed error now)
Cause for error : When the user enters home screen second time it fails to retrieve the name,imageUrl some other details because we haven't stored user details globally.
Anyway, I've fixed the issue and updated the article.
If you found this article useful sharing is highly appreciated. Twitter : @movingmelody :)

Collapse
 
iamnikhilpardeshi profile image
Nikhil Pardeshi

Sir how to resolve these error. Becz I'm beginner in Flutter.

Thread Thread
 
sai7xp profile image
Sumanth

I've updated the code in the article or you can find the code in GitHub repo. Go through the code again. Your error will solve.

Thread Thread
 
iamnikhilpardeshi profile image
Nikhil Pardeshi

Ok sir.

Collapse
 
sai7xp profile image
Sumanth

Still, If you find any issues comment the error. And let me know if error is solved

Collapse
 
laersel2 profile image
laersel2

Invalid argument(s)

The relevant error-causing widget was
HomeScreen
lib\screens\authscreen.dart:79
When the exception was thrown, this was the stack

0 _StringBase.+ (dart:core-patch/string_patch.dart:262:57)

1 _HomeScreenState.build

package:firebase_gsignin/screens/homescreen.dart:17

2 StatefulElement.build

package:flutter/…/widgets/framework.dart:4619

3 ComponentElement.performRebuild

package:flutter/…/widgets/framework.dart:4502

4 StatefulElement.performRebuild

Collapse
 
laersel2 profile image
laersel2

Sir kindly help

Collapse
 
sai7xp profile image
Sumanth

Check the updated code and article

Collapse
 
mikulina profile image
Miku

Were you able to find a solution to this? I'm having the same problem right now. :/

Collapse
 
sai7xp profile image
Sumanth

Actually, that was because the null value is passed to the homescreen from the splashscreen(username). Fixed ✅✅ the error now. You can update the code as i updated the article.
Or else simply store the user details in localstorage using the SharedPreferences. It enables you to access the details even in offline mode.
I have commited the new changes to github. If you stuck anywhere look over github repo.

Collapse
 
iamnikhilpardeshi profile image
Nikhil Pardeshi

Hello Sir, last time the program is run Perfectly. Bt now in AuthScreen
=> Error in following lines
1) final AuthResult authResult = await auth.signInWithCredential(credential);
2) final FirebaseUser currentUser = await auth.currentUser();
assert(firebaseUser.uid == currentUser.uid);
return firebaseUser;

& in Splash Screen has returned error.
=> Error in following lines
1) FirebaseAuth.instance.currentUser().then((currentUser) {
if (currentUser == null) {
Timer(Duration(seconds: 2),
() => Navigator.pushReplacementNamed(context, "/auth"));
} else {
Timer(
Duration(seconds: 2),
() => Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
HomeScreen(username: currentUser.displayName)),
(Route route) => false),
);
}
});
What to do, please help me to find these issue??

Collapse
 
feisalfahmi profile image
Feisal Fahmi • Edited

Sir, how to call username, imageUrl and Email in another page ?
I have a problem when i close my app ,then error

Collapse
 
sai7xp profile image
Sumanth

Store the user details locally in your phone using SharedPreferences when user signup. Then simply retrieve the user details in the page you want to use them. Additionally it enables offline access 🦸‍♀️