In this tutorial, you'll see Firebase integration within a native context, basically over an iOS and Android application. You will also implement some of the basic, as well as advanced features, that are found in any modern mobile application in both, Android and iOS ecosystems. So let's get busy!
This article is an excerpt taken from the book,' Firebase Cookbook', written by Houssem Yahiaoui.
Implement the pushing and retrieving of data from Firebase Real-time Database
We're going to start first with Android and see how we can manage this feature:
First, head to your Android Studio project. Now that you have opened your project, let's move on to integrating the Real-time Database.
In your project, head to the Menu bar, navigate to Tools | Firebase, and then select Realtime Database. Now click Save and retrieve data. Since we've already connected our Android application to Firebase, let's now add the Firebase Real-time Database dependencies locally by clicking on the Add the Realtime Database to your app button. This will give you a screen that looks like the following screenshot:
Figure 1: Android Studio Firebase integration section
Click on the Accept Changes button and the gradle will add these new dependencies to your gradle file and download and build the project.
Now we've created this simple wish list application. It might not be the most visually pleasing but will serve us well in this experiment with TextEdit, a Button, and a ListView.
So, in our experiment we want to do the following:
Add a new wish to our wish list Firebase Database
See the wishes underneath our ListView
Let's start with adding that list of data to our Firebase. Now head to your MainActivity.java file of any other activity related to your project and add the following code:
//[*] UI reference.
EditText wishListText;
Button addToWishList;
ListView wishListview;
// [*] Getting a reference to the Database Root.
DatabaseReference fRootRef =
FirebaseDatabase.getInstance().getReference();
//[*] Getting a reference to the wishes list.
DatabaseReference wishesRef =
fRootRef.child("wishes");
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[*] UI elements
wishListText = (EditText)
findViewById(R.id.wishListText);
addToWishList = (Button)
findViewById(R.id.addWishBtn);
wishListview = (ListView)
findViewById(R.id.wishsList);
}
@Override
protected void onStart() {
super.onStart();
//[*] Listening on Button click event
addToWishList.setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
//[*] Getting the text from our EditText UI Element.
String wish =
wishListText.getText().toString();
//[*] Pushing the Data to our Database.
wishesRef.push().setValue(wish);
AlertDialog alertDialog = new
AlertDialog.Builder(MainActivity.this).create();
alertDialog.setTitle("Success");
alertDialog.setMessage("wish was added to Firebase");
alertDialog.show();
}
});
}
In the preceding code, we're doing the following:
Getting a reference to our UI elements
Since everything in Firebase starts with a reference, we're grabbing ourselves a reference to the root element in our database
We are getting another reference to the wishes child method from the root reference
Over the OnCreate() method, we are binding all the UI-based references to the actual UI widgets
Over the OnStart() method, we're doing the following:
Listening to the button click event and grabbing the EditText content
Using the wishesRef.push().setValue() method to push the content of the EditText automatically to Firebase, then we are displaying a simple AlertDialog as the UI preferences
However, the preceding code is not going to work. This is strange since everything is well configured, but the problem here is that the Firebase Database is secured out of the box with authorization rules.
So, head to Database | RULES and change the rules there, and then publish. After that is done, the result will look similar to the following screenshot:
Figure 2: Firebase Real-time Database authorization section
After saving and launching the application, the pushed data result will look like this:
Figure 3: Firebase Real-time Database after adding a new wish to the wishes collection
Firebase creates the child element in case you didn't create it yourself. This is great because we can create and implement any data structure we want, however, we want.
Next, let's see how we can retrieve the data we sent. Move back to your onStart() method and add the following code lines:
wishesRef.addChildEventListener(new
ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot
dataSnapshot, String s) {
//[*] Grabbing the data Snapshot
String newWish =
dataSnapshot.getValue(String.class);
wishes.add(newWish);
adapter.notifyDataSetChanged();
}
@Override
public void onChildChanged(DataSnapshot
dataSnapshot, String s) {}
@Override
public void onChildRemoved(DataSnapshot
dataSnapshot) {}
@Override
public void onChildMoved(DataSnapshot
dataSnapshot, String s) {}
@Override
public void onCancelled(DatabaseError
databaseError) {}
});
Before you implement the preceding code, go to the onCreate() method and add the following line underneath the UI widget reference:
//[*] Adding an adapter.
adapter = new ArrayAdapter<String>(this,
R.layout.support_simple_spinner_dropdown_item,
wishes);
//[*] Wiring the Adapter
wishListview.setAdapter(adapter);
Preceding that, in the variable declaration, simply add the following declaration:
ArrayList<String> wishes = new ArrayList<String>();
ArrayAdapter<String> adapter;
So, in the preceding code, we're doing the following:
Adding a new ArrayList and an adapter for ListView changes. We're wiring everything in the onCreate() method.
Wiring an addChildEventListener() in the wishes Firebase reference.
Grabbing the data snapshot from the Firebase Real-time Database that is going to be fired whenever we add a new wish, and then wiring the list adapter to notify the wishListview which is going to update our Listview content automatically.
Congratulations! You've just wired and exploited the Real-time Database functionality and created your very own wishes tracker.
Now, let's see how we can create our very own iOS wishes tracker application using nothing but Swift and Firebase:
Head directly to and fire up Xcode, and let's open up the project, where we integrated Firebase. Let's work on the feature.
Edit your Podfile and add the following line:
pod 'Firebase/Database'
This will download and install the Firebase Database dependencies locally, in your very own awesome wishes tracker application. There are two view controllers, one for the wishes table and the other one for adding a new wish to the wishes list, the following represents the main wishes list view.
Figure 4: iOS application wishes list view
Once we click on the + sign button in the Header, we'll be navigated with a segueway to a new ViewModal, where we have a text field where we can add our new wish and a button to push it to our list.
Figure 5: Wishes iOS application, in new wish ViewModel
Over addNewWishesViewController.swift, which is the view controller for adding the new wish view, after adding the necessary UITextField, @IBOutlet and the button @IBAction, replace the autogenerated content with the following code lines:
import UIKit
import FirebaseDatabase
class newWishViewController: UIViewController {
@IBOutlet weak var wishText: UITextField
//[*] Adding the Firebase Database Reference
var ref: FIRDatabaseReference?
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
}
@IBAction func addNewWish(_ sender: Any) {
let newWish = wishText.text // [*] Getting the
UITextField content.
self.ref?.child("wishes").childByAutoId().setValue(
newWish!)
presentedViewController?.dismiss(animated: true,
completion:nil)
}
}
In the preceding code, besides the self-explanatory UI element code, we're doing the following:
We're using the FIRDatabaseReference and creating a new Firebase reference, and we're initializing it with viewDidLoad().
Within the addNewWish IBAction (function), we're getting the text from the UITextField, calling for the "wishes" child, then we're calling childByAutoId(), which will create an automatic id for our data (consider it a push function, if you're coming from JavaScript). We're simply setting the value to whatever we're going to get from the TextField.
Finally, we're dismissing the current ViewController and going back to the TableViewController which holds all our wishes.
Implementing anonymous authentication
Authentication is one of the most tricky, time-consuming and tedious tasks in any web application. and of course, maintaining the best practices while doing so is truly a hard job to maintain. For mobiles, it's even more complex, because if you're using any traditional application it will mean that you're going to create a REST endpoint, an endpoint that will take an email and password and return either a session or a token, or directly a user's profile information. In Firebase, things are a bit different and in this recipe, we're going to see how we can use anonymous authentication—we will explain that in a second.
You might wonder, but why? The why is quite simple: to give users an anonymous temporal, to protect data and to give users an extra taste of your application's inner soul. So let's see how we can make that happen.
How to do it...
We will first see how we can implement anonymous authentication in Android:
Fire up your Android Studio. Before doing anything, we need to get some dependencies first, speaking, of course, of the Firebase Auth library that can be downloaded by adding this line to the build.gradle file under the dependencies section:
compile 'com.google.firebase:firebase-auth:11.0.2'
Now simply Sync and you will be good to start adding Firebase Authentication logic. Let us see what we're going to get as a final result:
Figure 6: Android application: anonymous login application
A simple UI with a button and a TextView, where we put our user data after a successful authentication process.
Here's the code for that simple UI:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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.hcodex.anonlogin.MainActivity">
<Button
android:id="@+id/anonLoginBtn"
android:layout_width="289dp"
android:layout_height="50dp"
android:text="Anounymous Login"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginTop="47dp"
android:onClick="anonLoginBtn"
app:layout_constraintTop_toBottomOf=
"@+id/textView2"
app:layout_constraintHorizontal_bias="0.506"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Firebase Anonymous Login"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="80dp" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Profile Data"
android:layout_marginTop="64dp"
app:layout_constraintTop_toBottomOf=
"@+id/anonLoginBtn"
android:layout_marginLeft="156dp"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:id="@+id/profileData"
android:layout_width="349dp"
android:layout_height="175dp"
android:layout_marginBottom="28dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text=""
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.526"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf=
"@+id/textView3" />
</android.support.constraint.ConstraintLayout>
Now, let's see how we can wire up our Java code:
//[*] Step 1 : Defining Logic variables.
FirebaseAuth anonAuth;
FirebaseAuth.AuthStateListener authStateListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
anonAuth = FirebaseAuth.getInstance();
setContentView(R.layout.activity_main);
};
//[*] Step 2: Listening on the
Login button click event.
public void anonLoginBtn(View view) {
anonAuth.signInAnonymously()
.addOnCompleteListener(
this, new OnCompleteListener<AuthResult>() {
@Override public void onComplete(@NonNull
Task<AuthResult> task) {
if(!task.isSuccessful()) {
updateUI(null);
} else {
FirebaseUser fUser =
anonAuth.getCurrentUser();
Log.d("FIRE", fUser.getUid());
updateUI(fUser);
}
});
}
}
//[*] Step 3 : Getting UI Reference
private void updateUI(FirebaseUser user) {
profileData = (TextView) findViewById(
R.id.profileData);
profileData.append("Anonymous Profile Id : n" +
user.getUid());
}
Now, let's see how we can implement anonymous authentication on iOS:
What we'll achieve in this test is the following :
Figure 7: iOS application, anonymous login application
Before doing anything, we need to download and install the Firebase authentication dependency first. Head directly over to your Podfile and the following line:
pod 'Firebase/Auth'
Then simply save the file, and on your terminal, type the following command:
~> pod install
This will download the needed dependency and configure our application accordingly.
Now create a simple UI with a button and after configuring your UI button IBAction reference, let's add the following code:
@IBAction func connectAnon(_ sender: Any) {
Auth.auth().signInAnonymously() { (user, error) in
if let anon = user?.isAnonymous {
print("i'm connected anonymously here's my id
(user?.uid)")
}
}
}
How it works...
Let's digest the preceding code:
We're defining some basic logic variables; we're taking basically a TextView, where we'll append our results and define the Firebase anonAuth variable. It's of FirebaseAuth type, which is the starting point for any authentication strategy that we might use.
Over onCreate, we're initializing our Firebase reference and fixing our content view.
We're going to authenticate our user by clicking a button bound with the anonLoginBtn() method. Within it, we're simply calling for the signInAnonymously() method, then if incomplete, we're testing if the authentication task is successful or not, else we're updating our TextEdit with the user information.
We're using the updateUI method to simply update our TextField.
Pretty simple steps. Now simply build and run your project and test your shiny new features.
Implementing password authentication on iOS
Email and password authentication is the most common way to authenticate anyone and it can be a major risk point if done wrong. Using Firebase will remove that risk and make you think of nothing but the UX that you will eventually provide to your users. In this recipe, we're going to see how you can do this on iOS.
How to do it...
Let's suppose you've created your awesome UI with all text fields and buttons and wired up the email and password IBOutlets and the IBAction login button. Let's see the code behind the awesome, quite simple password authentication process:
import UIKit
import Firebase
import FirebaseAuth
class EmailLoginViewController: UIViewController {
@IBOutlet weak var emailField: UITextField!
@IBOutlet weak var passwordField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func loginEmail(_ sender: Any) {
if self.emailField.text</span> == "" ||
self.passwordField.text == "" {
//[*] Prompt an Error
let alertController = UIAlertController(title:
"Error", message: "Please enter an email
and password.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK",
style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true,
completion: nil)
} else {
FIRAuth.auth()?.signIn(withEmail:
self.emailField.text!, password:
self.passwordField.text!) { (user, error) in
if error == nil {
//[*] TODO: Navigate to Application Home Page.
} else {
//[*] Alert in case we've an error.
let alertController = UIAlertController(title:
"Error", message: error?.localizedDescription,
preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK",
style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true,
completion: nil)
}
}
}
}
}
How it works ...
Let's digest the preceding code:
We're simply adding some IBOutlets and adding the IBAction login button.
Over the loginEmail function, we're doing two things:
If the user didn't provide any email/password, we're going to prompt them with an error alert indicating the necessity of having both fields.
We're simply calling for the FIRAuth.auth().singIn() function, which in this case takes an Email and a Password. Then we're testing if we have any errors. Then, and only then, we might navigate to the app home screen or do anything else we want. We prompt them again with the Authentication Error message.
And as simple as that, we're done. The User object will be transported, as well, so you may do any additional processing to the name, email, and much more.
Implementing password authentication on Android
To make things easier in terms of Android, we're going to use the awesome Firebase Auth UI. Using the Firebase Auth UI will save a lot of hassle when it comes to building the actual user interface and handling the different intent calls between the application activities. Let's see how we can integrate and use it for our needs.
Let's start first by configuring our project and downloading all the necessary dependencies. Head to your build.gradle file and copy/paste the following entry:
compile 'com.firebaseui:firebase-ui-auth:3.0.0'
Now, simply sync and you will be good to start.
How to do it...
Now, let's see how we can make the functionality work:
Declare the FirebaseAuth reference, plus add another variable that we will need later on:
FirebaseAuth auth;
private static final int RC_SIGN_IN = 17;
Now, inside your onCreate method, add the following code:
auth = FirebaseAuth.getInstance();
if(auth.getCurrentUser() != null) {
Log.d("Auth", "Logged in successfully");
} else {
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(
Arrays.asList(new
AuthUI.IdpConfig.Builder(
AuthUI.EMAIL_PROVIDER).build())).build(),
RC_SIGN_IN);findViewById(R.id.logoutBtn)
.setOnClickListener(this);
Now, in your activity, implement the View.OnClick listener. So your class will look like the following:
public class MainActivity extends AppCompatActivity
implements View.OnClickListener {}
After that, implement the onClick function as shown here:
@Override
public void onClick(View v) {
if(v.getId() == R.id.logoutBtn) {
AuthUI.getInstance().signOut(this)
.addOnCompleteListener(
new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task)
{
Log.d("Auth", "Logged out successfully");
// TODO: make custom operation.
}
});
}
}
In the end, implement the onActivityResult method as shown in the following code block:
@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {
super.onActivityResult(requestCode,
resultCode, data);
if(requestCode == RC_SIGN_IN) {
if(resultCode == RESULT_OK) {
//User is in !
Log.d("Auth",auth.getCurrentUser().getEmail());
} else {
//User is not authenticated
Log.d("Auth", "Not Authenticated");
}
}
}
Now build and run your project. You will have a similar interface to that shown in the following screenshot:
Figure 8: Android authentication using email/password: email picker
This interface will be shown in case you're not authenticated and your application will list all the saved accounts on your device. If you click on the NONE OF THE ABOVE button, you will be prompted with the following interface:
Figure 9: Android authentication email/password: adding new email
When you add your email and click on the NEXT button, the API will go and look for that user with that email in your application's users. If such an email is present, you will be authenticated, but if it's not the case, you will be redirected to the Sign-up activity as shown in the following screenshot:
Figure 10: Android authentication: creating a new account, with email/password/name
Next, you will add your name and password. And with that, you will create a new account and you will be authenticated.
How it works...
From the preceding code, it's clear that we didn't create any user interface. The Firebase UI is so powerful, so let's explore what happens:
The setAvailableProviders method will take a list of providers—those providers will be different based on your needs, so it can be any email provider, Google, Facebook, and each and every provider that Firebase supports. The main difference is that each and every provider will have each separate configuration and necessary dependencies that you will need to support the functionality.
Also, if you've noticed, we're setting up a logout button. We created this button mainly to log out our users and added a click listener to it. The idea here is that when you click on it, the application performs the Sign-out operation. Then you add your custom intent that will vary from a redirect to closing the application.
If you noticed, we're implementing the onActivityResult special function and this one will be our main listening point whenever we connect or disconnect from the application. Within it, we can perform different operations from resurrection to displaying toasts, to anything that you can think of.
Implementing Google Sign-in authentication
Google authentication is the process of logging in/creating an account using nothing but your existing Google account. It's easy, fast, and intuitive and removes a lot of hustle we face, usually when we register any web/mobile application. I'm talking basically about form filling. Using Firebase Google Sign-in authentication, we can manage such functionality; plus we have had the user basic metadata such as the display name, picture URL, and more. In this recipe, we're going to see how we can implement Google Sign-in functionality for both Android and iOS.
Before doing any coding, it's important to do some basic configuration in our Firebase Project console.
Head directly to your Firebase project Console | Authentication | SIGN-IN METHOD | Google and simply activate the switch and follow the instructions there in order to get the client. Please notice that Google Sign-in is automatically configured for iOS, but for Android, we will need to do some custom configuration.
Let us first look at getting ready for Android to implement Google Sign-in authentication:
Before we start implementing the authentication functionality, we will need to install some dependencies first, so please head to your build.gradle file and paste the following, and then sync your build:
compile 'com.google.firebase:firebase-auth:11.4.2'
compile 'com.google.android.gms:play-services-
auth:11.4.2'
The dependency versions are dependable, and that means that whenever you want to install them, you will have to provide the same version for both dependencies.
Moving on to getting ready in iOS for implementation of Google Sign-in authentication:
In iOS, we will need to install a couple of dependencies, so please go and edit your Podfile and add the following lines underneath your already present dependencies, if you have any:
pod 'Firebase/Auth'
pod 'GoogleSignIn'
Now, in your terminal, type the following command:
~> pod install
This command will install the required dependencies and configure your project accordingly.
How to do it...
First, let us take a look at how we will implement this recipe in Android:
Now, after installing our dependencies, we will need to create the UI for our calls. To do that, simply copy and paste the following special button XML code into your layout:
<com.google.android.gms.common.SignInButton
android:id="@+id/gbtn"
android:layout_width="368dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="30dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent" />
The result will be this:
Figure 11: Google Sign-in button after the declaration
After doing that, let's see the code behind it:
SignInButton gBtn;
FirebaseAuth mAuth;
GoogleApiClient mGoogleApiClient;
private final static int RC_SIGN_IN = 3;
FirebaseAuth.AuthStateListener mAuthListener;
@Override
protected void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAuth = FirebaseAuth.getInstance();
gBtn = (SignInButton) findViewById(R.id.gbtn);
button.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
signIn();
}
});
mAuthListener = new FirebaseAuth.AuthStateListener()
{
@Override
public void onAuthStateChanged(@NonNull
FirebaseAuth firebaseAuth) {
if(firebaseAuth.getCurrentUser() != null) {
AlertDialog alertDialog = new
AlertDialog.Builder(MainActivity.this).create();
alertDialog.setTitle("User");
alertDialog.setMessage("I have a user loged
in");
alertDialog.show();
}
}
};
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, new
GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(@NonNull
ConnectionResult connectionResult) {
Toast.makeText(MainActivity.this, "Something
went wrong", Toast.LENGTH_SHORT).show();
}
})
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
GoogleSignInOptions gso = new
GoogleSignInOptions.Builder(
GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
private void signIn() {
Intent signInIntent =
Auth.GoogleSignInApi.getSignInIntent(
mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
@Override
public void onActivityResult(int requestCode, int
resultCode, Intent data) {
super.onActivityResult(requestCode,
resultCode, data);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi
.getSignInResultFromIntent(data);
if (result.isSuccess()) {
// Google Sign In was successful,
authenticate with Firebase
GoogleSignInAccount account =
result.getSignInAccount();
firebaseAuthWithGoogle(account);
} else {
Toast.makeText(MainActivity.this,
"Connection Error", Toast.LENGTH_SHORT).show();
}
}
}
private void firebaseAuthWithGoogle(
GoogleSignInAccount account) {
AuthCredential credential =
GoogleAuthProvider.getCredential(
account.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new
OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull
Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the
signed-in user's information
Log.d("TAG",
"signInWithCredential:success");
FirebaseUser user =
mAuth.getCurrentUser();
Log.d("TAG", user.getDisplayName());
} else {
Log.w("TAG",
"signInWithCredential:failure",
task.getException());
Toast.makeText(MainActivity.this,
"Authentication failed.", Toast.LENGTH_SHORT)
.show();
}
// ...
}
});
}
Then, simply build and launch your application, click on the authentication button, and you will be greeted with the following screen:
Figure 12: Account picker, after clicking on Google Sign-in button.
Next, simply pick the account you want to connect with, and then you will be greeted with an alert, finishing the authentication process.
Now we will take a look at an implementation of our recipe in iOS:
Before we do anything, let's import the Google Sign-in as follows:
import GoogleSignIn
After that, let's add our Google Sign-in button; to do so, go to your Login Page ViewController and add the following line of code:
//Google sign in
let googleBtn = GIDSignInButton()
googleBtn.frame =CGRect(x: 16, y: 50, width:
view.frame.width - 32, height: 50)
view.addSubview(googleBtn)
GIDSignIn.sharedInstance().uiDelegate = self
The frame positioning is for my own needs—you can use it or modify the dimension to suit your application needs.
Now, after adding the lines above, we will get an error. This is due to our ViewController not working well with the GIDSignInUIDelegate, so in order to make our xCode happier, let's add it to our ViewModal declaration so it looks like the following:
class ViewController: UIViewController,
FBSDKLoginButtonDelegate, GIDSignInUIDelegate {}
Now, if you build and run your project, you will get the following:
Figure 13: iOS application after configuring the Google Sign-in button
Now, if you click on the Sign in button, you will get an exception. The reason for that is that the Sign in button is asking for the clientID, so to fix that, go to your AppDelegate file and complete the following import:
import GoogleSignIn
Next, add the following line of code within the application: didFinishLaunchingWithOptions as shown below:
GIDSignIn.sharedInstance().clientID =
FirebaseApp.app()?.options.clientID
If you build and run the application now, then click on the Sign in button, nothing will happen. Why? Because iOS doesn't know how and where to navigate to next. So now, in order to fix that issue, go to your GoogleService-Info.plist file, copy the value of the REVERSED_CLIENT_ID, then go to your project configuration. Inside the Info section, scroll down to the URL types, add a new URL type, and paste the link inside the URL Schemes field:
Figure 14: Xcode Firebase URL schema adding, to finish the Google Sign-in behavior
Next, within the application: open URL options, add the following line:
GIDSignIn.sharedInstance().handle(url,
sourceApplication:options[
UIApplicationOpenURLOptionsKey.sourceApplication] as?
String, annotation:
options[UIApplicationOpenURLOptionsKey.annotation])
This will simply help the transition to the URL we already specified within the URL schemes.
Next, if you build and run your application, tap on the Sign in button and you will be redirected using the SafariWebViewController to the Google Sign-in page, as shown in the following screenshot:
Figure 15: iOS Google account picker after clicking on Sign-in button
With that, the ongoing authentication process is done, but what will happen when you select your account and authorize the application? Typically, you need to go back to your application with all the needed profile information, don't you? isn't? Well, for now, it's not the case, so let's fix that.
Go back to the AppDelegate file and do the following:
Add the GIDSignInDelegate to the app delegate declaration
Add the following line to the application: didFinishLaunchingWithOptions:
GIDSignIn.sharedInstance().delegate = self
This will simply let us go back to the application with all the tokens we need to finish the authentication process with Firebase.
Next, we need to implement the signIn function that belongs to the GIDSignInDelegate; this function will be called once we're successfully authenticated:
func sign(_ signIn: GIDSignIn!, didSignInFor user:
GIDGoogleUser!, withError error: Error!) {
if let err = error {
print("Can't connect to Google")
return
}
print("we're using google sign in", user)
}
Now, once you're fully authenticated, you will receive the success message over your terminal.
Now we can simply integrate our Firebase authentication logic. Complete the following import:
import FirebaseAuth
Next, inside the same signIn function, add the following:
guard let authentication = user.authentication else
{
return }
let credential =
GoogleAuthProvider.credential(withIDToken:
authentication.idToken, accessToken:
authentication.accessToken)
Auth.auth().signIn(with: credential, completion:
{(user, error) in
if let error = error {
print("[*] Can't connect to firebase, with error
:", error) }
print("we have a user", user?.displayName)
})
This code will use the successfully logged in user token and call the Firebase Authentication logic to create a new Firebase user. Now we can retrieve the basic profile information that Firebase delivers.
How it works...
Let's explain what we did in the Android section:
We activated authentication using our Google account from the Firebase project console.
We also installed the required dependencies, from Firebase Auth to Google services.
After finishing the setup, we gained the ability to create that awesome Google Sign-in special button, and we also gave it an ID for easy access.
We created references from SignInButton and FirebaseAuth.
Let's now explain what we just did in the iOS section:
We used the GIDSignButton in order to create the branded Google Sign-in button, and we added it to our ViewController.
Inside the AppDelegate, we made a couple of configurations so we could retrieve our ClientID that the button needed to connect to our application.
For our button to work, we used the information stored in GoogleService-Info.plist and created an app link within our application so we could navigate to our connection page.
Once everything was set, we were introduced to our application authorization page where we authorized the application and chose the account we wanted to use to connect.
In order to get back all the required tokens and account information, we needed to go back to the AppDelegate file and implement the GIDSignInDelegate. Within it, we could can all the account-related tokens and information, once we were successful authenticated.
Within the implemented SignIn function, we injected our regular Firebase authentication signIn method with all necessary tokens and information. When we built and ran the application again and signed in, we found the account used to authenticate, present in the Firebase authenticated account.
To summarize, we learned how to integrate Firebase within a native context, basically over an iOS and Android application. If you've enjoyed reading this, do check,'Firebase Cookbook' for recipes to help you understand features of Firebase and implement them in your existing web or mobile applications.
Using the Firebase Real-Time Database
How to integrate Firebase with NativeScript for cross-platform app development
Build powerful progressive web apps with Firebase
Read more