Introduction
This blog post is about android firebase authentication tutorial using firebaseui. In a web and app world, user authentication is gradually becoming more and more complex in its server side design and implementation. At the same time, stress on simpler and seamless user experience (UX) is getting more importance. This seemingly simple principle is a huge challenge to achieve. Every app developer need to re-engineer it in every implementation.
Firebase brilliantly addressed this core issue with a combination of firbase authentication and firebase ui offerings. As an app developer, you just hook onto this beautiful feature/framework and you are saved from writing and testing hundreds of lines of code.
However, if you would still like to write your own code, take a good look at below authentication workflow and you may consider changing your decision! š
Firebase Authentication Workflow
Firebase has put together a very complex authentication workflow in their product offering. Take a look at the below diagram from firebase authentication github page.

Firebase Authentication Workflow
Thanks to the wonderful products from firebase, we are abstracted from these complexities. You just add the relevant dependencies and write some code to orchestrate these features. That’s it! You are done. No hassle of hosting your own infrastructure, database, writing MBaaS (mobile backend as a service) etc.
So, let’s get started. In the next sections, we will go step by step to implement an authentication module in our android app.
Tech Stack
Following are the tech stack used in this app development. We have used Mike Penz’s material design navigation drawer for its simplicity and ease of implementation. I will definitely encourage you to take look in his github page.
1 2 3 4 5 |
Android Studio 3.0 JAVA for Android programming Mike Penz's material navigation drawer Firebase UI for Authentication Firebase Authentication module |
You will see it’s super simple and extremely useful. Brilliant stuff!
Demo of the App
In this case, we have two GIFs.
- First one to demo the user sign up/registration process and
- Second one where user uses the same credential to login.
User Signs up first
Post Sign up, user logs in
Create an empty app
- Launch Android Studio and click:Ā FileĀ ā>Ā NewĀ ā>Ā New Projectā¦
- A āCreate New Projectā dialog box will open; weāll provide the app name and company domain. I have entered following details, you can provide the name/domain as per your choice and preference.
- Application Name:-Ā ItcMyFirebaseAuth
- Company Domain:-Ā iteritory.com
- Click onĀ NextĀ button. In the next window, select the minimum SDK version; you can choose as per your preference. In this case, I have chosenĀ API 16: Android 4.1 (Jelly Bean).Ā ClickĀ NextĀ button.
- In the next window, select āEmpty Activityā. ClickĀ NextĀ button.
- In the next window,Ā letās keep the Activity Name and Layout Name to default. ClickĀ FinishĀ button.
- Iāll change the app name a bit here, traverse and openĀ resā>Ā valuesĀ ā>Ā strings.xml. Find the line with app_name attribute. Change the value to ā“My FairebaseAuth App”.
Add navigation drawer dependency
- Now, open up the build.gradle file (app level) and in the dependencies section add –
123implementation("com.mikepenz:materialdrawer:6.0.1@aar") {transitive = true}
- Ensure that there are other dependencies declared as per the official github page.
- Post modification, the dependency section of build.gradle (App level) looks like below –
12345678910111213141516dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.support.constraint:constraint-layout:1.0.2'testImplementation 'junit:junit:4.12'androidTestImplementation 'com.android.support.test:runner:1.0.1'androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'implementation("com.mikepenz:materialdrawer:6.0.1@aar") {transitive = true}//required support lib modulesimplementation 'com.android.support:appcompat-v7:26.1.0'implementation 'com.android.support:recyclerview-v7:26.1.0'implementation 'com.android.support:support-annotations:26.1.0'implementation 'com.android.support:design:26.1.0'}
Theme Modification
- Traverse and open app–>res –> values –>styles.xml
- We’ll change the default parent attribute value from “Theme.AppCompat.Light.DarkActionBar”Ā with “Theme.AppCompat.Light.NoActionBar“.
- Then we’ll create a new backward compatible custom theme with name “FirebaseMaterialDesignTheme” that will inherit default AppTheme. Post modification, my default styles.xml looks like –
1234567891011<resources><style name="FirebaseMaterialDesignTheme" parent="AppTheme"></style><!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item></style></resources>
- Right click on res folder and click New –> Android Resource File. A new dialog box will open up. Provide the File name as styles.xml and Directory name asĀ values-v21. A new file will be created; populate the file with below content –
123456<?xml version="1.0" encoding="utf-8"?><resources><style name="FirebaseMaterialDesignTheme" parent="AppTheme"><!-- customize theme for newer device --></style></resources>
- Now, traverse and open app –> manifests –> AndroidManifest.xml.
- Replace the value ofĀ android:theme withĀ “@style/FirebaseMaterialDesignTheme”. Post modificaton, the file will look like –
123456789101112131415161718192021<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.iteritory.itcmyfirebaseauth"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/FirebaseMaterialDesignTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest> - This modification is for material design theme’s backward compatibility.
- Now, if you run the app, you will see an app with “Hello World!”
- Cool, so good so far, let’s move forward
Add some string constants
Traverse and open res –> values –> strings.xml and add some required strings. Post modification, the file will look like –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<resources> <string name="app_name">My FairebaseAuth App</string> <string name="login_menu_item">Log in</string> <string name="verified_profile">My Profile</string> <string name="home">Home</string> <string name="unverified_profile">My Profile (Unverified)</string> <string name="settings">Settings</string> <string name="logout_menu_item">Sign out</string> <string name="welcome_on_signin">Congratulations! you have successfully signed in.</string> <string name="default_nouser_signin">No user signed in currently.</string> <string name="login_failed">Log in cancelled!</string> <string name="login_success">Log in successful.</string> <string name="logout_success">Successfully logged out</string> <string name="logout_failed">Failed to log out</string> <string name="login_unknown_Error">Unknown error while logging in. Please Try again</string> <string name="no_connectivity">There is no internet connection. Please try again</string> </resources> |
Download required icon
As part of this app’s development, we will need few icons. Let’s download those –
- Verified User 24dp
- Unverified User 24dp
- Log in 48dpĀ
- Log Out 48p
- Home 48dp
- Settings 48dp
- Account 48dp
Ensure you have selected Project view from the explorer. Please check the yellow highlighted area in the below picture if you are not sure from where to go to Project view.
Now, extract the downloaded zip files and traverse toĀ androidĀ subfolder for each of these. You will see multiple folders named like ādrawable-hdpiā etc. In each of this folder, there is one version of the icon. Weāll copy each icon from each folder individually and paste toĀ resā>mipmapĀ folder in the studio. While pasting, ensure that you are selecting the right size subfolder inside mipmap folder. That means, if you are copying icon from drawable-hdpi, you will paste it to mipmap-hdpi folder.
Add toolbar
- In order to add toolbar, we will make some changes in res –> layout –> activity_main.xml file. Change the layout to relative layout, add toolbar and modify the text view. Post modification, the file content will be like –
123456789101112131415161718192021222324<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.iteritory.itcmyfirebaseauth.MainActivity"><android.support.v7.widget.Toolbarandroid:layout_width="match_parent"android:layout_height="?android:attr/actionBarSize"android:background="@color/primary"android:id="@+id/toolbarMain"/><TextViewandroid:id="@+id/content"android:text="@string/default_nouser_signin"android:textSize="23dp"android:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_marginTop="?attr/actionBarSize"android:layout_height="wrap_content" /></RelativeLayout>
- We’ll add a toolbar to our app using following function. We’ll call this function from onCreate() –
1234private void setupToolbar(){mToolbar = (Toolbar) findViewById(R.id.toolbarMain);setSupportActionBar(mToolbar);}
Add Mike Penz’s Navigation Drawer
- Let’s download a background picture from Mike’s github page and place it in res –> drawable folder.
- We’ll instantiate required navigation drawer menu items using another functionĀ instantiateMenuItems().
- While using many apps, you must have noticed that after logging in, the user name and some other information along profile picture is set on top of the navigation drawer. In order to achieve similar feature, we’ll first create a Profile Drawer.
- Next, we will use this Profile Drawer object to create an account header.
- Now, we will setup the navigation drawer with Account Header. We’ll also need execute some actions when user clicks on each of these menu items.
- So stitching it all together, the MainActivity.java looks like –
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113package com.iteritory.itcmyfirebaseauth;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.Toolbar;import android.view.View;import android.widget.Toast;import com.mikepenz.materialdrawer.AccountHeader;import com.mikepenz.materialdrawer.AccountHeaderBuilder;import com.mikepenz.materialdrawer.Drawer;import com.mikepenz.materialdrawer.DrawerBuilder;import com.mikepenz.materialdrawer.model.DividerDrawerItem;import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;import com.mikepenz.materialdrawer.model.ProfileDrawerItem;import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;import com.mikepenz.materialdrawer.model.interfaces.IProfile;import java.util.Arrays;public class MainActivity extends AppCompatActivity {Toolbar mToolbar;Drawer mDrawerResult;AccountHeader mHeaderResult;ProfileDrawerItem mProfileDrawerItem;PrimaryDrawerItem mItemLogin, mItemLogout, mItemVerifiedProfile, mItemHome, mItemSettings, mItemUnverifiedProfile, mCurrentProfile;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setupToolbar();instantiateMenuItems();setupProfileDrawer();setupNavigationDrawerWithHeader();}private void setupToolbar(){mToolbar = (Toolbar) findViewById(R.id.toolbarMain);setSupportActionBar(mToolbar);}private void instantiateMenuItems(){mItemVerifiedProfile = new PrimaryDrawerItem().withIdentifier(1).withName(R.string.verified_profile).withIcon(getResources().getDrawable(R.mipmap.ic_verified_user_black_24dp));mItemUnverifiedProfile = new PrimaryDrawerItem().withIdentifier(2).withName(R.string.unverified_profile).withIcon(getResources().getDrawable(R.mipmap.ic_report_problem_black_24dp));mItemLogin = new PrimaryDrawerItem().withIdentifier(3).withName(R.string.login_menu_item).withIcon(getResources().getDrawable(R.mipmap.ic_login_black_48dp));mItemLogout = new PrimaryDrawerItem().withIdentifier(4).withName(R.string.logout_menu_item).withIcon(getResources().getDrawable(R.mipmap.ic_logout_black_48dp));;mItemHome = new PrimaryDrawerItem().withIdentifier(5).withName(R.string.home).withIcon(getResources().getDrawable(R.mipmap.ic_home_black_48dp));mItemSettings = new PrimaryDrawerItem().withIdentifier(6).withName(R.string.settings).withIcon(getResources().getDrawable(R.mipmap.ic_settings_black_48dp));}private void setupProfileDrawer() {mProfileDrawerItem = new ProfileDrawerItem().withIcon(getResources().getDrawable(R.mipmap.ic_account_circle_black_48dp));}private AccountHeader setupAccountHeader(){mHeaderResult = new AccountHeaderBuilder().withActivity(this).withHeaderBackground(R.drawable.header).addProfiles(mProfileDrawerItem).withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {@Overridepublic boolean onProfileChanged(View view, IProfile profile, boolean currentProfile) {return false;}}).withSelectionListEnabledForSingleProfile(false).build();return mHeaderResult;}private void setupNavigationDrawerWithHeader(){mDrawerResult = new DrawerBuilder().withActivity(this).withAccountHeader(setupAccountHeader()).withToolbar(mToolbar).addDrawerItems(mItemLogin, new DividerDrawerItem(), mItemHome,mItemSettings).withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {@Overridepublic boolean onItemClick(View view, int position, IDrawerItem drawerItem) {onNavDrawerItemSelected((int)drawerItem.getIdentifier());return true;}}).build();mDrawerResult.deselect(mItemLogin.getIdentifier());}private void onNavDrawerItemSelected(int drawerItemIdentifier){switch (drawerItemIdentifier){//Sign Incase 3:Toast.makeText(this, "Login menu selected", Toast.LENGTH_LONG).show();break;//Sign Outcase 4:Toast.makeText(this, "Logout menu selected", Toast.LENGTH_LONG).show();break;//Homecase 5:Toast.makeText(this, "Home menu selected", Toast.LENGTH_LONG).show();break;//Settingscase 6:Toast.makeText(this, "Settings menu selected", Toast.LENGTH_LONG).show();break;}}}
- At this point, if you execute the app, it will be something like below –
Setup Firebase project
As we’ll use Firebase Authentication, we first need to setup a project in the firebase console –
- Use your gmail id to login toĀ Firebase Console
- In the console, you will see an “Add Project” button, let’s click on this and a new popup will open up. I have given the project name as “My Firebase Project“. It’ll automatically generate a project id. You can keep the default. However, in my case, I have edited the id.
- Change the country as per your choice and click on “CREATE PROJECT” button.
- A new window will open up, there will be several options. As we are here to develop an android app, let’s select “Add Firebase to your Android app” option.
- A new window will pop-up. We’ll provide exactly the same package name that we used while creating the app in Android Studio. In my case, it isĀ com.iteritory.itcmyfirebaseauth
- Let’s Provide an app nick name as well. The window looks like below –
- Click on register app button. A new window will open up.
- Click on the Download google-services.json button and a .json file will be downloaded in your local system.
- As described in the above screen, switch to project view if you have not already done. Copy the downloaded googl-services.json file and paste inside app folder. If you notice, it will be a sibling of build.gradle file inside app folder.
- Click on the Continue and then Finish button.
- Next, click on the DEVELOP menu on the left and then select Authentication sub-menu. A new window will open up on your right –
- In this tutorial, we will use 2 methods from the provided list. Email/Password and Google.
- Click on Email/Password, a window will pop-up. Click on Enable and then click Save button –
- Repeat the same process for Google option as well.
- Click on Enable button.
- Additionally, in the “Project public-facing name”, provide user facing name. I have provided “Iteritory Firebase Demo”. You can provide a name relevant to you.
- Click on Save button.
- So, now that’s it. We are done with all the setup thingy! Next, we do some coding again š
Add Firebase Dependency
- Open the root level build.grade file and add following classpath
- classpath ‘com.google.gms:google-services:3.1.1’ // google-services plugin
- Post modification the file will look like –
123456789101112131415161718192021222324252627// Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {repositories {google()jcenter()}dependencies {classpath 'com.android.tools.build:gradle:3.0.0'classpath 'com.google.gms:google-services:3.1.1' // google-services plugin// NOTE: Do not place your application dependencies here; they belong// in the individual module build.gradle files}}allprojects {repositories {google()jcenter()}}task clean(type: Delete) {delete rootProject.buildDir}
- Open app level build.gradle file and add following two dependencies
- compile ‘com.google.firebase:firebase-auth:11.4.2’
- compile ‘com.firebaseui:firebase-ui-auth:3.1.0’
- At the end of depdencies, add following –
- apply plugin: ‘com.google.gms.google-services’
- Post modification, the app level build.gradle will look like –
123456789101112131415161718192021222324252627282930313233343536373839404142apply plugin: 'com.android.application'android {compileSdkVersion 26defaultConfig {applicationId "com.iteritory.itcmyfirebaseauth"minSdkVersion 16targetSdkVersion 26versionCode 1versionName "1.0"testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}}dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.support.constraint:constraint-layout:1.0.2'testImplementation 'junit:junit:4.12'androidTestImplementation 'com.android.support.test:runner:1.0.1'androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'implementation("com.mikepenz:materialdrawer:6.0.1@aar") {transitive = true}//required support lib modulesimplementation 'com.android.support:appcompat-v7:26.1.0'implementation 'com.android.support:recyclerview-v7:26.1.0'implementation 'com.android.support:support-annotations:26.1.0'implementation 'com.android.support:design:26.1.0'//Firebase Core Authenticationcompile 'com.google.firebase:firebase-auth:11.4.2'//Firebase Authentication UIcompile 'com.firebaseui:firebase-ui-auth:3.1.0'}apply plugin: 'com.google.gms.google-services'
Instantiate User in MainActivity
Declare an instance of FirebaseAuth and do a getUser() on that instance to check who is the current user. If the getUser returns NULL, we know that there is no user session, i.e. no user is currently logged in. Let’s take a look at the simple function
1 2 3 4 |
private void intstantiateUser(){ mFirebaseAuth = FirebaseAuth.getInstance(); mFirebaseUser = mFirebaseAuth.getCurrentUser(); } |
We’ll also write a utility function to tell us if the user is logged in or not –
1 2 3 4 5 6 7 |
private boolean isUserSignedIn(){ if (mFirebaseUser == null){ return false; }else{ return true; } } |
App UI Workflow
- While launching the app, it will check if there is any user already logged in by using the functions written above.
- If there is no user logged in, it will show “Log in” menu item along with HOME and SETTINGS. It’ll also show a message in the app text view that there is no user currently logged in to the app.
- When a user selects “Login” menu, Firebase AuthUI kicks in and it takes the user through a very intuitive UI sequence, for either signing in or signing up purpose. Notice that, we won’t write a single line of code for all these. We’ll just kick start the AuthUI with require parameters and it will take its own course. This is the beauty of Firebase Authentication with AuthUI. You don’t code the complex logic; you have everything ready for you. Let’s take a look at the code that does the magic for us
12345678910startActivityForResult(AuthUI.getInstance().createSignInIntentBuilder().setAvailableProviders(Arrays.asList(new AuthUI.IdpConfig.Builder(AuthUI.EMAIL_PROVIDER).build(),new AuthUI.IdpConfig.Builder(AuthUI.GOOGLE_PROVIDER).build())).setTheme(R.style.AuthUITheme).setLogo(R.mipmap.ic_account_circle_black_48dp).setTosUrl(TOS_URL).setPrivacyPolicyUrl(PP_URL).setAllowNewEmailAccounts(true).setIsSmartLockEnabled(true).build(), RC_SIGN_IN);
- Notice that in this AuthUI, we have provided 2 different authentication methods. These are the two methods, we have also configured while setting up project in firebase console.
- We have also set a UI theme. Just so you know, it’s possible to customize the authentication UI by setting the theme. To create the theme, you can open styles.xml and make the necessary modification. For the demonstration purpose, I have created a simple theme and after all the modification, the styles.xml file looks like –
123456789101112131415161718192021222324252627282930<resources><style name="FirebaseMaterialDesignTheme" parent="AppTheme"></style><!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item></style>AuthUITheme<!-- Firebase theme --><style name="AuthUITheme" parent="FirebaseUI"><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item><item name="android:textColorHint">@android:color/black</item></style><style name="FirebaseUI.Text"><item name="android:layout_width">match_parent</item><item name="android:layout_height">wrap_content</item><item name="android:fontFamily">sans-serif</item><item name="android:textColor">@android:color/black</item></style><style name="FirebaseUI.Text.Link"><item name="android:textColor">@android:color/holo_blue_dark</item></style></resources>
- We have set Terms of Service URL (TOS_URL)
- We have set Privacy Policy URL too (PP_URL)
- This is as much code you write to have users get authenticated in your app. Cool!! isn’t it?
- But if there is any user already logged in, we will show
- the user’s email id and profile pic (pic will be hard coded in this case. In real time scenario, you can always populate it dynamically) in navigation drawer header.
- In the Navigation drawer bottom portion, we will show the user’s name and an icon to denote whether the user is verified or unverified.
- When a user is already logged in, in the navigation drawer, we won’t see any Login menu item. Instead, we will have Logout menu item.
- We’ll also print a message stating that user is logged in.
After stitching together all the checks and balances, my MainActivity.java looks like –
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 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
package com.iteritory.itcmyfirebaseauth; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.firebase.ui.auth.AuthUI; import com.firebase.ui.auth.ErrorCodes; import com.firebase.ui.auth.IdpResponse; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.mikepenz.materialdrawer.AccountHeader; import com.mikepenz.materialdrawer.AccountHeaderBuilder; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.DividerDrawerItem; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.ProfileDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IProfile; import java.util.Arrays; public class MainActivity extends AppCompatActivity { Toolbar mToolbar; FirebaseAuth mFirebaseAuth; FirebaseUser mFirebaseUser; Drawer mDrawerResult; AccountHeader mHeaderResult; ProfileDrawerItem mProfileDrawerItem; PrimaryDrawerItem mItemLogin, mItemLogout, mItemVerifiedProfile, mItemHome, mItemSettings, mItemUnverifiedProfile, mCurrentProfile; private static final int RC_SIGN_IN = 123; //For demo purpose, I have provided two sample URLs. One for Privacy Policy and another for Terms of Service private static final String PP_URL = "https://iteritory.com/msadrud/install-or-setup-apache-ignite-in-windows-step-by-step-tutorial/"; private static final String TOS_URL = "https://iteritory.com/msadrud/install-or-setup-apache-ignite-in-windows-step-by-step-tutorial/"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setupToolbar(); intstantiateUser(); instantiateMenuItems(); setupProfileDrawer(); setupNavigationDrawerWithHeader(); } private void setupToolbar(){ mToolbar = (Toolbar) findViewById(R.id.toolbarMain); setSupportActionBar(mToolbar); } private void intstantiateUser(){ mFirebaseAuth = FirebaseAuth.getInstance(); mFirebaseUser = mFirebaseAuth.getCurrentUser(); } private boolean isUserSignedIn(){ if (mFirebaseUser == null){ return false; }else{ return true; } } private PrimaryDrawerItem checkCurrentProfileStatus(){ if (mFirebaseUser.isEmailVerified()){ mCurrentProfile = new PrimaryDrawerItem().withIdentifier(2).withName(R.string.verified_profile).withIcon(getResources().getDrawable(R.mipmap.ic_verified_user_black_24dp));; }else{ mCurrentProfile = new PrimaryDrawerItem().withIdentifier(2).withName(R.string.unverified_profile).withIcon(getResources().getDrawable(R.mipmap.ic_report_problem_black_24dp)); } return mCurrentProfile; } private void instantiateMenuItems(){ mItemVerifiedProfile = new PrimaryDrawerItem().withIdentifier(1).withName(R.string.verified_profile).withIcon(getResources().getDrawable(R.mipmap.ic_verified_user_black_24dp)); mItemUnverifiedProfile = new PrimaryDrawerItem().withIdentifier(2).withName(R.string.unverified_profile).withIcon(getResources().getDrawable(R.mipmap.ic_report_problem_black_24dp)); mItemLogin = new PrimaryDrawerItem().withIdentifier(3).withName(R.string.login_menu_item).withIcon(getResources().getDrawable(R.mipmap.ic_login_black_48dp)); mItemLogout = new PrimaryDrawerItem().withIdentifier(4).withName(R.string.logout_menu_item).withIcon(getResources().getDrawable(R.mipmap.ic_logout_black_48dp));; mItemHome = new PrimaryDrawerItem().withIdentifier(5).withName(R.string.home).withIcon(getResources().getDrawable(R.mipmap.ic_home_black_48dp)); mItemSettings = new PrimaryDrawerItem().withIdentifier(6).withName(R.string.settings).withIcon(getResources().getDrawable(R.mipmap.ic_settings_black_48dp)); } private void setupProfileDrawer() { //check if the user is logged in. If logged in, get details (name, email, pic etc) dynamically //For demonstration purpose, I have set a personal photo hard coded. In real-time, we can easily // pass the actual photo dynamically. if (mFirebaseUser != null) { mProfileDrawerItem = new ProfileDrawerItem() .withName(mFirebaseUser.getDisplayName()) .withEmail(mFirebaseUser.getEmail()) .withIcon(getResources().getDrawable(R.drawable.profile)); } else {//else if the user is not logged in, show a default icon mProfileDrawerItem = new ProfileDrawerItem() .withIcon(getResources().getDrawable(R.mipmap.ic_account_circle_black_48dp)); } } private AccountHeader setupAccountHeader(){ mHeaderResult = new AccountHeaderBuilder() .withActivity(this) .withHeaderBackground(R.drawable.header) .addProfiles(mProfileDrawerItem) .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() { @Override public boolean onProfileChanged(View view, IProfile profile, boolean currentProfile) { return false; } }).withSelectionListEnabledForSingleProfile(false) .build(); return mHeaderResult; } private void setupNavigationDrawerWithHeader(){ //Depending on user is logged in or not, decide whether to show Log In menu or Log Out menu if (!isUserSignedIn()){ mDrawerResult = new DrawerBuilder() .withActivity(this) .withAccountHeader(setupAccountHeader()) .withToolbar(mToolbar) .addDrawerItems(mItemLogin, new DividerDrawerItem(), mItemHome,mItemSettings) .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { onNavDrawerItemSelected((int)drawerItem.getIdentifier()); return true; } }) .build(); mDrawerResult.deselect(mItemLogin.getIdentifier()); }else{ mCurrentProfile = checkCurrentProfileStatus(); mDrawerResult = new DrawerBuilder() .withActivity(this) .withAccountHeader(setupAccountHeader()) .withToolbar(mToolbar) .addDrawerItems(mCurrentProfile, mItemLogout, new DividerDrawerItem(), mItemHome,mItemSettings) .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { onNavDrawerItemSelected((int)drawerItem.getIdentifier()); return true; } }) .build(); } mDrawerResult.closeDrawer(); } private void onNavDrawerItemSelected(int drawerItemIdentifier){ switch (drawerItemIdentifier){ //Sign In case 3: Toast.makeText(this, "Login menu selected", Toast.LENGTH_LONG).show(); startActivityForResult(AuthUI.getInstance().createSignInIntentBuilder() .setAvailableProviders(Arrays.asList(new AuthUI.IdpConfig.Builder(AuthUI.EMAIL_PROVIDER).build(), new AuthUI.IdpConfig.Builder(AuthUI.GOOGLE_PROVIDER).build())) .setTheme(R.style.AuthUITheme) .setLogo(R.mipmap.ic_account_circle_black_48dp) .setTosUrl(TOS_URL) .setPrivacyPolicyUrl(PP_URL) .setAllowNewEmailAccounts(true) .setIsSmartLockEnabled(true) .build(), RC_SIGN_IN); break; //Sign Out case 4: signOutUser(); Toast.makeText(this, "Logout menu selected", Toast.LENGTH_LONG).show(); break; //Home case 5: Toast.makeText(this, "Home menu selected", Toast.LENGTH_LONG).show(); break; //Settings case 6: Toast.makeText(this, "Settings menu selected", Toast.LENGTH_LONG).show(); break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == RC_SIGN_IN) { IdpResponse response = IdpResponse.fromResultIntent(data); // Successfully signed in if (resultCode == RESULT_OK) { Toast.makeText(this, R.string.login_success, Toast.LENGTH_LONG).show(); signInUser(); return; }else{ //User pressed back button if (response == null) { Toast.makeText(this, R.string.login_failed, Toast.LENGTH_LONG).show(); mDrawerResult.deselect(mItemLogin.getIdentifier()); return; } //No internet connection. if (response.getErrorCode() == ErrorCodes.NO_NETWORK) { Toast.makeText(this, R.string.no_connectivity, Toast.LENGTH_LONG).show(); return; } //Unknown error if (response.getErrorCode() == ErrorCodes.UNKNOWN_ERROR) { Toast.makeText(this, R.string.login_unknown_Error, Toast.LENGTH_LONG).show(); return; } } } } private void refreshMenuHeader(){ mDrawerResult.closeDrawer(); mHeaderResult.clear(); setupProfileDrawer(); setupAccountHeader(); mDrawerResult.setHeader(mHeaderResult.getView()); mDrawerResult.resetDrawerContent(); } private void signInUser(){ intstantiateUser(); if (!mFirebaseUser.isEmailVerified()){ //mFirebaseUser.sendEmailVerification(); } mCurrentProfile = checkCurrentProfileStatus(); mDrawerResult.updateItemAtPosition(mCurrentProfile,1); mDrawerResult.addItemAtPosition(mItemLogout,2); mDrawerResult.deselect(mItemLogout.getIdentifier()); refreshMenuHeader(); ((TextView)findViewById(R.id.content)).setText(R.string.welcome_on_signin); } private void signOutUser(){ //Sign out mFirebaseAuth.signOut(); mFirebaseUser = mFirebaseAuth.getCurrentUser(); if (!isUserSignedIn()) { mDrawerResult.updateItemAtPosition(mItemLogin,1); mDrawerResult.removeItemByPosition(2); mDrawerResult.deselect(mItemLogin.getIdentifier()); refreshMenuHeader(); ((TextView)findViewById(R.id.content)).setText(R.string.default_nouser_signin); }else{ //check if internet connectivity is there } } } |
Now for the demo, go on top of the page and see GIF.
GitHub
I have pushed my entire project in git hub and you can get it here.
Conclusion
This post has been pretty long and I have covered two tutorials essentially. One for easy integration of navigration drawer using Mike Penz’s library and on top of that I built a complete user authentication solution based on FirebaseUI and FirebaseAuth libraries. Hope it helped you. If you have question, feel free to reach out in the comment box below. š
Suman Shekhar
January 6, 2018Hello,
Can you please write a post on implementation of firebase database UI using RecyclerView. That would be helpful.
Sadruddin Md
January 8, 2018Hi Suman, Thanks for your comment and suggestion. Will surely write next on this.
Jaemin
August 13, 2018The profile picture is not updated after Sign In. Can you please let me know how I can update it?
Jaemin
August 14, 2018The problem is solved. Good tutorial!
Sadruddin Md
August 15, 2018Hi @Jaemin, apologies, I saw your comment much later. Great to know, you sorted it out. š
Luccas Freitas
August 31, 2018Hello. I did follow your entire tutorial. But at the end I’m facing this problem: “Default FirebaseApp is not initialized in this process. Make sure to call FirebaseApp.initializeApp(Context) first. Any suggestions?
Sadruddin Md
September 4, 2018HI Luccas, apologies for the late reply. My hunch is that your gradle dependencies are not in sync! Can you update all your dependencies (including that of firebase) to the latest; clean, rebuild.
Do let me know should it not work even after this
Adi
October 14, 2018I’m getting this error, what should I do? How can I fix it?
error: incompatible types: android.support.v7.widget.Toolbar cannot be converted to androidx.appcompat.widget.Toolbar
(I got it after android studio forced me to change the sdk version to 28)
Adi
October 14, 2018Ok, so after a lot of google version update, migrations, code fixes and rebuilds, it works. Thanks!
I have also added facebook login button (Also after hard work because facebook not friendly at all!), but why the profile image isn’t changing the default profile image? Is this app supporting that from facebook or only with Google connecting?
Thanks a lot.
Sadruddin Md
October 15, 2018Hello Adi.. the first error is related to the version issue. Glad, you figured it out.
As for FB profile image, ideally it should. However, I’ll update here once I get a chance to take a look. Thank you.
Adi
October 15, 2018Hi,
Regarding to Google sign-in, I have two issues:
1) I saw that Jaemin had a problem as mine that after connecting with google account the profile image remains with the default and not changing to the google account image. How can I fix it?
2) I have 2 accounts of google in my device, at the first time it asked me which one I want. But after I logged out, and want to sign-in again but with the other one, it keeps sign-in with the previous one as default each time. What can I do here?
* Regarding the Facebook login, I did all the procedures, when I press the facebook login button, it recognizes my facebook profile in my device, but after confirm the permissions I’m getting “provider error”. Is it familiar to you?
And thanks again.
Adi
October 15, 2018In addition to my previous comment, in the “setupProfileDrawer()” procedure, I have tried to change this line:
.withIcon(getResources().getDrawable(R.drawable.profile)
with this:
.withIcon(mFirebaseUser.getPhotoUrl().toString()
(And I have verified, it does return the jpg url of the profile image in 96×96 resolution)
But the image remains like the default ‘ic_account_circle_black_48dp’ but in a different color)
Adi
October 17, 2018UPDATE:
The Facebook login is ok. The error was because I generated the hash keys wrong.
But the profile image still not shown when I’m trying this:
.withIcon(getResources().getDrawable(R.drawable.profile)
Adi
October 20, 2018UPDATE:
The problem of the profile picture has been solve.
You can implement it using Picasso or Glide (For loading image with url)
For more details, you can read it here:
https://github.com/mikepenz/MaterialDrawer/issues/2380#issuecomment-431571200
Fabrice
January 16, 2019Hello, maybe stupid question (sorry, I’m a beginner), I would like to force my users to be logged in, ie start the sign in process with FirebaseUI at the launch of the app. Where should I put the call to FirebaseUI ?
Sadruddin Md
January 19, 2019@Adi, thanks for resolving the issues and posting your findings and solutions here. You are awesome!!
Sadruddin Md
January 19, 2019@Fabrice, you can put it in onCreate function of MainActivity class. Instatiate and check if the user is signed in. If not, launch the UI. Hope this helps.