This article was updated in September 2020.

Firebase Authentication provides backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to your app. It supports authentication using passwords, phone numbers, popular federated identity providers like Google, Facebook and Twitter, and more.

In this article, I will be showing how to set up Flutter app and implement Google sign-in using Firebase authentication.

The sample app is tested on Flutter 1.20 (stable) and using all the latest versions of the plugins.

In this article you will learn how to:

So let's get started.

Google sign-in using Flutter

There are a few new steps you have to do in order to use Google sign-in in your app. Without completing all these steps, if you try to use Google sign in, your app will just crash. Let's see how to set up Google sign-in from scratch using Firebase.

App screenshots

Our final app will look like this:

Final design

Implementation

Before diving into the real coding part, let's see what are the plugins and assets required in this project.

Plugins

The plugins needed for this project are:

firebase_core (for initializing Firebase) firebase_auth (for Firebase authentication) google_sign_in (to implement Google Sign-In)

You will need to include the firebase_core plugin for using any other firebase related plugins as it is used for initializing the FirebaseApp() . This is required due to the recent updates on Flutter and Firebase, check this article for more details.

Assets

Only one image is needed for this project. We will be requiring it when designing the Google sign-in button in our app.

You can get the image from here.

Creating a new Flutter project

Let's create a new Flutter project with AndroidX compatibility.

Open Terminal or use the terminal in your code editor. If necessary, you can check your current Flutter version with the command: flutter --version If you are on Flutter 1.12 or above, AndroidX compatibility is added to the project by default. Just navigate to the folder where you want to create the project and use the following command: flutter create sign_in_flutter If you are using an older Flutter version, you can add the --androidx flag.

Importing packages

Add the following packages to your pubspec.yaml file: firebase_core: ^ 0.5 .0 firebase_auth: ^ 0.18 .0 +1 google_sign_in: ^ 4.5 .3 Save it to run flutter packages get .

Also, create a new folder called assets in your project directory and insert the image ( google_logo.png ) that you downloaded.

Now, add the assets folder in your pubspec.yaml file.

Building the UI

Just delete everything from the main.dart file and paste the boilerplate code given below.

import ' package:flutter/material.dart ' ; import ' login_page.dart ' ; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @ override Widget build(BuildContext context) { return MaterialApp( title: ' Flutter Login ' , theme: ThemeData( primarySwatch: Colors.blue, ), home: LoginPage(), ); } }

Let's build the UI for LoginPage .

Create a new dart file called login_page.dart inside the lib folder.

The LoginPage design would look like this:

Login page design

This screen contains the two main components:

Flutter Logo Sign in with Google button

LoginPage should be a Stateful Widget because we will be making some changes to the UI later which will need the widgets to be redrawn.

The code for the LoginPage UI:

import ' package:flutter/material.dart ' ; class LoginPage extends StatefulWidget { @ override _LoginPageState createState() = > _LoginPageState(); } class _LoginPageState extends State < LoginPage > { @ override Widget build(BuildContext context) { return Scaffold( body: Container( color: Colors.white, child: Center( child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, children: < Widget > [ FlutterLogo(size: 150 ), SizedBox(height: 50 ), _signInButton(), ], ), ), ), ); } Widget _signInButton() {} }

Now we have to design the Sign in with Google button inside the function _signInButton .

The code for button design:

Widget _signInButton() { return OutlineButton( splashColor: Colors.grey, onPressed: () {}, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular( 40 )), highlightElevation: 0 , borderSide: BorderSide(color: Colors.grey), child: Padding( padding: const EdgeInsets.fromLTRB( 0 , 10 , 0 , 10 ), child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: < Widget > [ Image(image: AssetImage( " assets/google_logo.png " ), height: 35.0 ), Padding( padding: const EdgeInsets.only(left: 10 ), child: Text( ' Sign in with Google ' , style: TextStyle( fontSize: 20 , color: Colors.grey, ), ), ) ], ), ), ); }

We will fill up the onPressed method later.

Firebase authentication

Create a new dart file sign_in.dart where we will set up the Firebase authentication and Google sign-in.

First of all, import the three packages:

firebase_core firebase_auth google_sign_in

import ' package:firebase_core/firebase_core.dart ' ; import ' package:firebase_auth/firebase_auth.dart ' ; import ' package:google_sign_in/google_sign_in.dart ' ;

Now, we will need to create an instance of FirebaseAuth & GoogleSignIn .

final FirebaseAuth _auth = FirebaseAuth.instance; final GoogleSignIn googleSignIn = GoogleSignIn();

Then, create two methods:

signInWithGoogle signOutGoogle

Future < String > signInWithGoogle() async {} void signOutGoogle() async {}

In the signInWithGoogle method, we have to use the Google sign-in data to authenticate a FirebaseUser and then return that user.

In the signOutGoogle method, we have to just sign out of the current Google account.

The final methods will look like this:

import ' package:firebase_auth/firebase_auth.dart ' ; import ' package:firebase_core/firebase_core.dart ' ; import ' package:google_sign_in/google_sign_in.dart ' ; final FirebaseAuth _auth = FirebaseAuth.instance; final GoogleSignIn googleSignIn = GoogleSignIn(); Future < String > signInWithGoogle() async { await Firebase.initializeApp(); final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn(); final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication; final AuthCredential credential = GoogleAuthProvider.credential( accessToken: googleSignInAuthentication.accessToken, idToken: googleSignInAuthentication.idToken, ); final UserCredential authResult = await _auth.signInWithCredential(credential); final User user = authResult.user; if (user ! = null ) { assert ( ! user.isAnonymous); assert ( await user.getIdToken() ! = null ); final User currentUser = _auth.currentUser; assert (user.uid = = currentUser.uid); print( ' signInWithGoogle succeeded: $ user ' ); return ' $ user ' ; } return null ; } Future < void > signOutGoogle() async { await googleSignIn.signOut(); print( " User Signed Out " ); }

Now, we have to update the onPressed method of _signInButton inside the LoginPage class, so that the signInWithGoogle method gets called.

onPressed: () { signInWithGoogle().then((result) { if (result ! = null ) { Navigator.of(context).push( MaterialPageRoute( builder: (context) { return FirstScreen(); }, ), ); } }); },

If the Google Sign-In is successful, we will be taken to the FirstScreen which we will be implementing next.

For now, we will just add a Container with a light blue background in the FirstScreen to test the Google sign-in.

Test UI for FirstScreen :

import ' package:flutter/material.dart ' ; class FirstScreen extends StatelessWidget { @ override Widget build(BuildContext context) { return Scaffold( body: Container(color: Colors.blue[ 100 ]), ); } }

Set up a Firebase project

To create a new Firebase project, you will need to go here.

Click Add project to create a new project. Enter a Project name and click Continue. Turn off Google Analytics for this project and click Create project. Now wait for the creation to complete and then click Continue. This will lead you to the Project Overview. From here you will be able to add Firebase to your Flutter project.

Android setup

First, we will set up Firebase for the Android side.

Click on the Android icon. In this form, you have to first enter the Android package name. You can find this from your project directory → android → app → src → AndroidManifest.xml. On the second line, there will be your package name. Just copy & paste it in the form. Now you can choose an App nickname. It is optional and if you leave this field empty, an auto-generated app name will be used. Android Setup Now, you have to enter the SHA-1 hash. Just hover over the help (?) and click See this page. This will take you to the Authenticating Your Client page. Here you will get the command to generate the SHA-1 hash. Paste this in your IDE terminal to get the SHA-1 hash. Just copy & paste this in the form. Click Register App. This will take you to the second step. Download the google-services.json file and just drag & drop it in your project directory → android → app. Then, click Next. In the third step, just follow the instructions and add the code snippets in the desired position. Then, click Next. Click Continue to Console. Go to Authentication Page → Users tab and click Set up sign-in method. In the sign-in providers page, edit Google sign-in. Here, you have to enter the project name and support email. Enable this by clicking the toggle on the top-right corner. Then, click Save. Google sign-in edit page The Google sign-in setup is now complete. Run the app on your device to check if it is working properly.

Note: To get a functional Firebase app, make sure you follow all these steps properly without skipping any of them.

iOS setup

If you have skipped the Android setup and arrived directly at the iOS setup, then make sure that you check out the steps 9-12; otherwise, you might face errors later.

Go to Settings → General tab. Scroll down and click Add app. Now, select iOS. Enter the iOS bundle ID and your App nickname. Then, click Register app. You can find the Bundle ID inside ios → Runner.xcodeproj → project.pbxproj by searching for “PRODUCT_BUNDLE_IDENTIFIER” with Ctrl + F . iOS Bundle ID In the second step, download the GoogleService-Info.plist file. Open the ios folder of the project directory in Xcode by right-clicking and selecting Open in Xcode. Xcode Now, drag & drop the file that you downloaded into the Runner subfolder. When a dialog box appears, make sure that Runner is selected in “Add to targets” box. Then click Finish. Close Xcode. In your IDE go to ios → Runner → Info.plist. Here, you have to add something. Open this google_sign_in flutter package page. Inside iOS integration you will find a code snippet. Just copy & paste it inside the Info.plist file and save it, like this: Info.plist Here, you will see that there is a TODO written to replace the value within the string tag with REVERSED_CLIENT_ID. You will find the REVERSED_CLIENT_ID in the file GoogleService-Info.plist. GoogleService-Info.plist We reached the third step. You don't need to change anything in this step because we are using the Flutter Firebase plugin which takes care of all these things. You will only need to do this step if you are building a standalone iOS app. So just click Next. Add Firebase SDK In the fourth step, you also do not need to do anything. Just click Next. Now, run the app on your iOS device and attempt a Google sign-in to complete the fifth step. After completing this step, click Continue to console.

Finally, this completes the whole setup process for Sign in with Google using Firebase for both Android and iOS. If you follow the described steps properly, you should get past the setup pretty quickly.

Subscribe to our newsletter

Improving the UI

Let's complete our FirstScreen UI. The final UI will look like this:

FirstScreen UI

I will not go deep into this UI coding part. You have to include some lines of code within the sign_in.dart file to retrieve the image URL, name & email of the user.

Thus, you have to add the following in sign_in.dart :

// Add these three variables to store the info // retrieved from the FirebaseUser String name; String email; String imageUrl; Future < String > signInWithGoogle() async { // ... final UserCredential authResult = await _auth.signInWithCredential(credential); final User user = authResult.user; if (user ! = null ) { // Add the following lines after getting the user // Checking if email and name is null assert (user.email ! = null ); assert (user.displayName ! = null ); assert (user.photoURL ! = null ); // Store the retrieved data name = user.displayName; email = user.email; imageUrl = user.photoURL; // Only taking the first part of the name, i.e., First Name if (name.contains( " " )) { name = name.substring( 0 , name.indexOf( " " )); } // ... return ' $ user ' ; } return null ; }

The full UI code for FirstScreen is given below:

import ' package:flutter/material.dart ' ; import ' package:sign_in_flutter/login_page.dart ' ; import ' package:sign_in_flutter/sign_in.dart ' ; class FirstScreen extends StatelessWidget { @ override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [Colors.blue[ 100 ], Colors.blue[ 400 ]], ), ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, children: < Widget > [ CircleAvatar( backgroundImage: NetworkImage( imageUrl, ), radius: 60 , backgroundColor: Colors.transparent, ), SizedBox(height: 40 ), Text( ' NAME ' , style: TextStyle( fontSize: 15 , fontWeight: FontWeight.bold, color: Colors.black54), ), Text( name, style: TextStyle( fontSize: 25 , color: Colors.deepPurple, fontWeight: FontWeight.bold), ), SizedBox(height: 20 ), Text( ' EMAIL ' , style: TextStyle( fontSize: 15 , fontWeight: FontWeight.bold, color: Colors.black54), ), Text( email, style: TextStyle( fontSize: 25 , color: Colors.deepPurple, fontWeight: FontWeight.bold), ), SizedBox(height: 40 ), RaisedButton( onPressed: () { signOutGoogle(); Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) { return LoginPage();}), ModalRoute.withName( ' / ' )); }, color: Colors.deepPurple, child: Padding( padding: const EdgeInsets.all( 8.0 ), child: Text( ' Sign Out ' , style: TextStyle(fontSize: 25 , color: Colors.white), ), ), elevation: 5 , shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 40 )), ) ], ), ), ), ); } }

Configuring Firebase on Codemagic

In our local configuration, we have downloaded the google-services.json and GoogleService-Info.plist files and kept it in the android & ios directory of the Flutter app respectively. These files contain sensitive data, like the API key and information about the app. These files shouldn't be checked in to version control or exposed to the world. We have to take certain steps to secure our sensitive data.

Ignore the files in the version control system

First of all, we have to list the two private files, google-services.json (present in the folder android/app/ ) and GoogleService-Info.plist (present in the folder ios/Runner/ ) in the .gitignore file, to avoid them being checked into version control, such as Git.

Once you have added the two files into .gitignore , commit the .gitignore file.

Encode the files

At this stage, we have ensured that we won't commit the sensitive files to the version control system. However, the continuous integration server will expect to find this file in order to successfully build the Flutter app.

To encode the files, run the following two commands from your terminal in the project directory:

openssl base64 -in android/app/google-services.json openssl base64 -in ios/Runner/GoogleService-Info.plist

This command will print the encoded content which we need to paste into the Codemagic environment variable.

Adding the environment variable in Codemagic

Log in in to your Codemagic account using GitHub, GitLab or Bitbucket. Find your project in your Applications list. Click the Settings button to go to the app settings. Expand the Environment variables tab. Add the two encoded content strings generated from the terminal as: ANDROID_FIREBASE_JSON (Variable name) -> encoded string from google-services.json (Variable value)

(Variable name) -> encoded string from (Variable value) IOS_FIREBASE_JSON (Variable name) -> encoded string from GoogleService-Info.plist (Variable value) Don't forget to check the Secure checkbox to ensure that the values won't be displayed in the build logs. Click Save.

Adding a pre-build script

In the Codemagic app settings, click on the + button before the Build stage. Pre-build Add the following Pre-build script. #!/bin/sh echo $ANDROID_FIREBASE_JSON | base64 --decode > $FCI_BUILD_DIR/android/app/google-services.json echo "Listing android Directory to confirm the google-services.json is there! " ls android/app/ echo $IOS_FIREBASE_JSON | base64 --decode > $FCI_BUILD_DIR/ios/Runner/GoogleService-Info.plist echo "

Listing iOS Directory to confirm the GoogleService-Info.plist is there! " ls ios/Runner/ Click Save Pre-build script

Start building

Click the Start new build button to start the build process.

While the build process is running, you can click the Pre-build tab to see the output of the code we added to the pre-build script. You can see that both files, google-services.json and GoogleService-Info.plist , are present, although we did not add them to the version-control system. They are generated from the encoded strings.

Pre-build tab

After the build is finished successfully, you can also download the artifacts to test it on a real device.

Build successful

If you want to generate a release build of your app, then check out the following articles:

Dependency caching

Firebase dependencies take longer to build, in order to prevent this you can use dependency caching on Codemagic to lower the build time.

To cache your Gradle and CocoaPods, enable dependency caching and include the following two paths to the Dependency caching section in your Codemagic project settings:

$HOME/.gradle/caches $HOME/Library/Caches/CocoaPods

Build without caching

Build with caching

Troubleshooting some common issues

Some of the common issues that people face while working with a project containing Firebase:

Releasing to Play Store

Having a completely configured app with Firebase doesn't mean it is ready to be published in Play Store. The biggest mistake done by people while generating a release build of an app containing Firebase, is not updating the google-services.json file.

After creating a new project in Play Console, a new SHA-1 key is generated. Copy the new SHA-1 and go your Firebase project -> Project settings -> Add fingerprint to add the new key.

Download the latest google-services.json file and replace with this in your Flutter project.

iOS Podfile issue

The Podfile format is changed in Flutter version 1.20, more about it here. If you have created your Flutter project post v1.20 then you might face Podfile is out of date warning or something related to this.

If you do not have any custom configuration changes to the default Podfile generated by Flutter, it is pretty easy to fix.

Just follow these steps:

Run Flutter clean: flutter clean

Run the following from the ios/ folder: pod repo update

Delete ios/Pods/ , ios/Podfile.lock & /ios/Podfile

Then again run the Flutter build, this should fix the issue

If you are having custom configurations in Podfile , then follow the above steps and then include the custom changes again.

Xcode signing identifier error

If you have not set the organization (using --org flag) while creating the Flutter project, it will be set to the default. But, for running the project on an iOS device you will need to use an unique signing identifier. Otherwise, you will get the following error:

Open the ios/ folder in Xcode by right-clicking and selecting Open in Xcode . Now, select Runner, under General tab set an unique Bundle Identifier .

Also, go to the Signing & Capabilities tab and select your Team & check if the Bundle Identifier is correct.

If you now close Xcode and build your Flutter app again, the issue should be solved.

Conclusion

Our Log-in Demo app is now completed and we have successfully tested it with Codemagic by setting up Firebase with encoded files. I hope that you found some useful information from this article.

You can find the GitHub repo for this project HERE.

More articles about Firebase:

This article is written by Souvik Biswas. He is a passionate Mobile App Developer (Android and Flutter) and has worked on a number of mobile apps throughout his journey. Loves open source contribution on GitHub. He is currently pursuing a B.Tech degree in Computer Science and Engineering from Indian Institute of Information Technology Kalyani. He also writes Flutter articles on Medium - Flutter Community.