NativeScript is now considered as one of the hottest platforms attracting developers. By using XML, JavaScript (also Angular), minor CSS for the visual aspects, and the magical touch of incorporating native SDKs, the platform has adopted the best of both worlds. Plus, this allows applications to be cross-platform, which means your application can run on both Android and iOS!
In this tutorial, we're going to see how we can use Firebase to create some awesome native applications.
This article is an excerpt taken from the book,' Firebase Cookbook', written by Houssem Yahiaoui.
Getting started with NativeScript project
In order to start a NativeScript project, we will need to make our development environment Node.js ready. So, in order to do so, let's download Node.js. Head directly to https://nodejs.org/en/download/ and download the most suitable version for your OS.
After you have successfully installed Node.js, you will have two utilities. One is the Node.js executable and the other will be npm or the node package manager. This will help us download our dependencies and install NativeScript locally.
How to do it...
In your terminal/cmd of choice, type the following command:
~> npm install -g nativescript
After installing NativeScript, you will need to add some dependencies. To know what your system is missing, simply type the following command:
~> tns doctor
This command will test your system and make sure that everything is in place. If not, you'll get the missing parts.
In order to create a new project, you will have many options to choose from. Those options could be creating a new project with vanilla JavaScript, with Typescript, from a template, or even better, using Angular. Head directly to your working directory and type the following command:
~> tns create <application-name>
This command will initialize your project and install the basic needed dependencies. With that done, we're good to start working on our NativeScript project.
Adding the Firebase plugin to our application
One of NativeScript's most powerful features is the possibility of incorporating truly native SDKs. So, in this context, we can install the Firebase NativeScript on Android using the normal Gradle installation command. You can also do it on iOS via a Podfile if you are running macOS and want to create an iOS application along the way. However, the NativeScript ecosystem is pluggable, which means the ecosystem has plugins that extend certain functionalities. Those plugins usually incorporate native SDKs and expose the functionalities using JavaScript so we can exploit them directly within our application.
In this recipe, we're going to use the wonderfully easy-to-use Eddy Verbruggen Firebase plugin, so let's see how we can add it to our project.
How to do it...
Head to your terminal/cmd of choice, type the following command, and hit Return/Enter respectively:
tns plugin add nativescript-plugin-firebase
This command will install the necessary plugin and do the required configuration.
To find out the id, open your package.json file where you will find the NativeScript value:
"nativescript": {
"id": "org.nativescript.<your-app-name>"
}
Copy the id that you found in the preceding step and head over to your Firebase project console. Create a new Android/iOS application and paste that ID over your bundle name. Download the google-service.json/GoogleServices-Info.plist files and paste google-server.json in your app/Application_Resources/Android folder if you created an Android project. If you've created an iOS project, then paste the GoogleServices-Info.plist in the app/Application_Resources/iOS folder.
Pushing/retrieving data from the Firebase Real-time Database
Firebase stores data in a link-based manner that allows you to add and query the information really simple. The NativeScript Firebase plugin makes the operation much simpler with an easy-to-use API. So, let's discover how we can perform such operations.
In this recipe, we're going to see how we can add and retrieve data in NativeScript and Firebase.
Before we begin, we need to make sure that our application is fully configured with Firebase. You will also need to initialize the Firebase plugin with the application. To do that, open your project, head to your app.js file, and add the following import code:
var firebase = require("nativescript-plugin-
firebase");
This will import the Firebase NativeScript plugin. Next, add the following lines of code:
firebase.init({}).then((instance) => {
console.log("[*] Firebase was successfully
initialised");
}, (error) => {
console.log("[*] Huston we've an initialization
error: " + error);
});
The preceding code will simply go and initialize Firebase within our application.
How to do it...
After initializing our application, let's see how we can push some data to our Firebase Realtime Database. Let's start first by adding our interface, which will look similar to the one (Figure 1):
Figure 1: Ideas adding page.
The code behind it is as follows, and you can use this to implement the addition of new data to your bucket:
<Page
xmlns="http://schemas.nativescript.org/tns.xsd"
navigatingTo="onNavigatingTo" class="page">
<Page.actionBar>
<ActionBar title="Firebase CookBook"
class="action-bar">
</ActionBar>
</Page.actionBar>
<StackLayout class="p-20">
<TextField text="{{ newIdea }}" hint="Add here your
shiny idea"/>
<Button text="Add new idea to my bucket" tap="{{
addToMyBucket
}}" </span>class</span>="btn btn-primary btn-
active"/>
</StackLayout>
</Page>
Now let's see the JavaScript related to this UI for our behavior. Head to your view-model and add the following snippets inside the createViewModel function:
viewModel.addToMyBucket = () => {
firebase.push('/ideas', {
idea: viewModel.newIdea
}).then((result) => {
console.log("[*] Info : Your data was pushed !");
}, (error) => {
console.log("[*] Error : While pushing your data to
Firebase, with error: " + error);
});
}
If you check your Firebase database, you will find your new entry present there.
Once your data is live, you will need to think of a way to showcase all your shiny, new ideas. Firebase gave us a lovely event that we shall listen to whenever a new child element is created. The following code teaches you how to create the event for showcasing the addition of new child elements:
var onChildEvent = function(result) {
console.log("Idea: " +
JSON.stringify(result.value));
};
firebase.addChildEventListener(onChildEvent,
"/ideas").then((snapshot) => {
console.log("[*] Info : We've some data !");
});
After getting the newly-added child, it's up to you to find the proper way to bind your ideas. They are mainly going to be either lists or cards, but they could be any of the previously mentioned ones.
To run and experience your new feature, use the following command:
~> tns run android # for android
~> tns run ios # for ios
How it works...
So what just happened?
We defined a basic user interface that will serve us by adding those new ideas to our Firebase console application.
Next, the aim was to save all that information inside our Firebase Realtime Database using the same schema that Firebase uses. This is done via specifying a URL where all your information will be stored and then specifying the data schema. This will finally hold and define the way our data will be stored.
We then hooked a listener to our data URL using firebase.addChildEventListener. This will take a function where the next item will be held and the data URL that we want our listener hook to listen on.
In case you're wondering how this module or service works in NativeScript, the answer is simple. It's due to the way NativeScript works; because one of NativeScript's powerful features is the ability to use native SDKs. So in this case, we're using and implementing the Firebase Database Android/iOS SDKs for our needs, and the plugin APIs we're using are the JavaScript abstraction of how we want to exploit our native calls.
Authenticating using anonymous or password authentication
As we all know, Firebase supports both anonymous and password-based authentication, each with its own, suitable use case. So in this recipe, we're going to see how we can perform both anonymous and password authentication.
You will need to initialize the Firebase plugin with the application. To do that, open your project, head to your app.js file, and add the following import:
var firebase = require("nativescript-plugin-
firebase");
This will import the Firebase NativeScript plugin. Next, add the following lines of code:
firebase.init({}).then((instance) => {
console.log("[*] Firebase was successfully
initialised");
}, (error) => {
console.log("[*] Huston we've an initialization
error: " + error);
});
The preceding code will go and initialize Firebase within our application.
How to do it...
Before we start, we need to create some UI elements. Your page will look similar to this one after you finish (Figure 2):
Figure 2: Application login page.
Now open your login page and add the following code snippets there:
<Page
xmlns="http://schemas.nativescript.org/tns.xsd"
navigatingTo="onNavigatingTo" class="page">
<Page.actionBar>
<ActionBar title="Firebase CookBook" icon=""
class="action-bar">
</ActionBar>
</Page.actionBar>
<StackLayout>
<Label text="Login Page" textWrap="true"
style="font-weight:
bold; font-size: 18px; text-align: center;
padding:20"/>
<TextField hint="Email" text="{{ user_email }}" />
<TextField hint="Password" text="{{
user_password }}"
secure="true"/><Button text="LOGIN" tap="{{
passLogin }}"
class="btn btn-primary btn-active" />
<Button text="Anonymous login" tap="{{ anonLogin
}}"
class="btn btn-success"/>
</StackLayout>
</Page>
Save that. Let's now look at the variables and functions in our view-model file. For that, let's implement the passLogin and anonLogin functions. The first one will be our normal email and password authentication, and the second will be our anonymous login function. To make this implementation come alive, type the following code lines on your page:
viewModel.anonLogin = () => {
firebase.login({
type: firebase.LoginType.ANONYMOUS
}).then((result) => {
console.log("[*] Anonymous Auth Response:" +
JSON.stringify(result));
},(errorMessage) => {
console.log("[*] Anonymous Auth Error:
"+errorMessage);
});
}
viewModel.passLogin = () => {
let email = viewModel.user_email;
let pass = viewModel.user_password;
firebase.login({
type: firebase.LoginType.PASSWORD,
passwordOptions: {
email: email,
password: pass
}
}).then((result) => {
console.log("[*] Email/Pass Response : " +
JSON.stringify(result));
}, (error) => {
console.log("[*] Email/Pass Error : " +
error);
});
}
Now, simply save your file and run it using the following command:
~> tns run android # for android
~> tns run ios # for ios
How it works...
Let's quickly understand what we've just done in the recipe:
We've built the UI we needed as per the authentication type. If we want the email and password one, we will need the respective fields, whereas, for anonymous authentication, all we need is a button.
Then, for both functions, we call the Firebase login button specifying the connection type for both cases. After finishing that part, it's up to you to define what is next and to retrieve that metadata from the API for your own needs later on.
Authenticating using Google Sign-In
Google Sign-In is one of the most popular integrated services in Firebase. It does not require any extra hustle, has the most functionality, and is popular among many apps. In this recipe, we're going to see how we can integrate Firebase Google Sign-In with our NativeScript project.
You will need to initialize the Firebase plugin within the application. To do that, open your project, head to your app.js file, and add the following line:
var firebase = require("nativescript-plugin-
firebase");
This will import the Firebase NativeScript plugin. Next, add the following lines of code:
firebase.init({}).then((instance) => {
console.log("[*] Firebase was successfully
initialised");
}, (error) => {
console.log("[*] Huston we've an initialization
error: " + error);
});
The preceding code will go and initialize Firebase within our application.
We will also need to install some dependencies. For that, underneath the NativeScript-plugin-firebase folder | platform | Android | include.gradle file, uncomment the following entry for Android:
compile "com.google.android.gms:play-services-
auth:$googlePlayServicesVersion"
Now save and build your application using the following command:
~> tns build android
Or uncomment this entry if you're building an iOS application:
pod 'GoogleSignIn'
Then, build your project using the following command:
~> tns build ios
How to do it...
First, you will need to create your button. So for this to happen, please go to your login-page.xml file and add the following button declaration:
<Button text="Google Sign-in" tap="{{ googleLogin
}}"
class="btn" style="color:red"/>
Now let's implement the googleLogin() function by using the following code snippet:
viewModel.googleLogin = () => {
firebase.login({
type: firebase.LoginType.GOOGLE,
}).then((result) => {
console.log("[*] Google Auth Response: " +
JSON.</span>stringify(result));
},(errorMessage) => {
console.log("[*] Google Auth Error: " +
errorMessage);
});
}
To build and experience your new feature, use the following command:
~> tns run android # for android
~> tns run ios # for ios
Now, once you click on the Google authentication button, you should have the following (Figure 3):
Figure 3: Account picking after clicking on Google Login button.
Don't forget to add your SHA-1 fingerprint code or the authentication process won't finish.
How it works...
Let's explain what just happened in the preceding code:
We added the new button for the Google authentication. Within the tap event of this button, we gave it the googleLogin() function.
Within googleLogin(), we used the Firebase login button giving it firebase.LoginType.GOOGLE as type. Notice that, similar to normal Google authentication on a web platform, we can also give the hd or the hostedDomain option. We could also use the option of filtering the connection hosting we want by adding the following option under the login type:
googleOptions: { hostedDomain: "<your-host-name>" } The hd option or the hostedDomain is simply what's after the @ sign in an email address. So, for example, in the email ID cookbook@packtpub.com the hosted domain is packtpub.com. For some apps, you might want to limit the email ID used by users when they connect to your application to just that host. This can be done by providing only the hostedDomain parameter in the code line pertaining to the storage of the email address.
When you look at the actual way we're making these calls, you will see that it's due to the powerful NativeScript feature that lets us exploit native SDK. If you remember the Getting ready section of this recipe, we uncommented a section where we installed the native SDK for both Android and iOS. Besides the NativeScript firebase plugin, you can also exploit the Firebase Auth SDK, which will let you exploit all supported Firebase authentication methods.
Adding dynamic behavior using Firebase Remote Config
Remote Config is one of the hottest features of Firebase and lets us play with all the different application configurations without too much of a headache. By a headache, we mean the process of building, testing, and publishing, which usually takes a lot of our time, even if it's just to fix a small float number that might be wrong.
So in this recipe, we're going to see how we can use Firebase Remote Config within our application.
In case you didn't choose the functionality by default when you created your application, please head to your build.gradle and Podfile and uncomment the Firebase Remote Config line in both files or in the environment you're using with your application.
How to do it...
Actually, the integration part of your application is quite easy. The tricky part is when you want to toggle states or alter some configuration. So think upon that heavily, because it will affect how your application works and will also affect the way you change properties.
Let's suppose that within this NativeScript application we want to have a mode called Ramadan mode. We want to create this mode for a special month where we wish to offer discounts, help our users with new promos, or even change our user interface to suit the spirit of it. So, let's see how we can do that:
firebase.getRemoteConfig({
developerMode: true,
cacheExpirationSeconds: 1,
properties: [{
key: "ramadan_promo_enabled",
default: false
}
}).then(function (result) {
console.log("Remote Config: " +
JSON.stringify(
result.properties.ramadan_promo_enabled));
//TODO : Use the value to make changes.
});
In the preceding code, and because we are still in development mode, we set that we want the developerMode to be activated. We also set the cacheExpirationSeconds to be one second. This is important because we don't want our settings to take a long time until they affect our application during the development phase. This will set the throttled mode to true, which will make the application fetch or look for new data every second to our Firebase remote configurations.
We can set the default values of each and every item within our Firebase remote configuration. This value will be the starting point for fetching any new values that might be present over the Firebase project console.
Now, let's see how we can wire that value from the project console. To do this, head to your Firebase project Console | Remote Config Section | ADD YOUR FIRST PARAMETER Button (Figure 4):
Figure 4: Firebase Remote Config Parameter adding section.
Next, you will get a modal where you will add your properties and their values. Make sure to add the exact same one that's in your code otherwise it won't work. The following screenshot shows the PARAMETERS tab of the console where you will add the properties (Figure 5):
Figure 5: While adding the new parameter
After adding them, click on the PUBLISH CHANGES button (Figure 6):
Figure 6: Publishing the new created Parameter.
With that, you're done.
Exit your application and open it back up again. Watch how your console and your application fetches the new values. Then, it's up to you and your application to make the needed changes once the values are changed.
How it works...
Let's explain what just happened:
We added back our dependencies from the build.gradle and Podfile so we can support the functionality we want to use.
We've selected and added the code that will be responsible for giving the default values and for fetching the new changes. We have also activated the developer mode, which will help out in our development and staging phases. This mode will be disabled once we're in production. We've set the cache expiration time, which is essential while being in development so we can retrieve those values in a fast way. This too will be changed in production, by giving the cache more expiration time, because we don't want to jeopardize our application with high-throttled operations every second.
We've added our support config in our Firebase Remote Config parameters, gave it the necessary value, and published it. This final step will control the way our application feels and looks like each new change.
We learned how to integrate Firebase with NativeScript using various recipes. If you've enjoyed this article, do check out 'Firebase Cookbook' to change the way you develop and make your app a first class citizen of the cloud.
Read more