Research collaborate build

May 14, 2020

Creating a Chat Application using Vue-Native and Firebase

Integrate Firebase with Vue Native and create a chat application.
Anmol Jain
Anmol JainPrinciple Software Engineer - I
lines

Vue Native is a framework created to bring the best of VueJS to build hybrid mobile apps.

In this tutorial, we are going to build a chat-application using Vue-Native and Firebase as a backend service. This project will include some basic features of a chat application. First of all, users will have to get through the authentication layer of the app to access their account and then they will be able to do real-time chat with their contacts. Before starting the steps to integrate Firebase, lets see some advantages of Vue-Native.

Internally, Vue-Native uses the React Native API which means getting benefits of both Vue and React Native properties under a single hood. Since Vue Native is based on VueJs, it gives developers the freedom to code in a template based syntax, like web, which makes transitioning to mobile based frameworks trouble-free. Firebase, on the other hand, is a powerful backend tool for building great mobile apps with services like crashlytics, authentication, storage etc.

Integrating Firebase with Vue Native is not as tough as it may sound. Following the below steps, you will be able to integrate Firebase with Vue Native in no time. If you are a newbie in Vue-Native, this link will help you with the installation and initial project setup.

Installing Firebase Dependency:

Open your Vue-Native project in the terminal and type the below commands to install firebase package.

npm install react-native-firebase 

or 

yarn add react-native-firebase

react-native link react-native-firebase 

To achieve chat application features, we will be needing:

  • A user authentication service.
  • A service to store users messages and personal information.

Firebase will provide us with all the above services.

Project Directory Setup:

  • Create src folder inside project directory and navigate to src.
  • Create two more folders inside src, one for Vue components and other for firebase functions as shown below.

Project Directory Setup

Firebase Project Setup:

Firstly, sign up for the Firebase console and create a new project using the ‘+’ button in it. Enter the project's name and click on the 'create project' button. After creating a successful project, open the project's dashboard.

Firebase Project Setup

For creating a basic chat-app, we will create two collections in Firebase database. One for the Users information and one for the messages.

  • Click to Database button on the left sidebar in firebase console.
  • Select cloud firebase from database options.
  • Click on start collection to create one.

create collection

Android Setup:

After successful creation of project you will see 'add app +' icon on the project dashboard.

Add App

Click on it and add the android app. Post that, a list of steps will appear. Follow all the steps carefully shown in the dashboard to integrate it successfully in Android. Then:

  1. Add the applicationId of your project which is to be integrated with Firebase. (ApplicationId can be found in the app>build.gradle file of your android folder in your Vue Native project.) Add a nickname and SHA - debug key (optional).
  2. Then download the google-services.json file (This file is mandatory for accessing Firebase operations) and place it inside the app folder of android.
  3. Open your project in the editor and navigate to android folder.

    android project directory
  4. Add the following dependencies to android/app/build.gradle file :
Hire our Development experts.
 implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
 implementation "com.facebook.react:react-native:+"  // From node_modules
+implementation "com.google.android.gms:play-services-base:16.1.0" 
+implementation "com.google.firebase:firebase-core:16.0.9"
+implementation "com.google.firebase:firebase-auth:17.0.0"
+implementation "com.google.firebase:firebase-firestore:19.0.0"
  • On the top of this file, add apply plugin:'com.google.gms.google-services'. Also add multiDexEnabled true in the defaultConfig object.

  • Now open the android/build.gradle file. Change  classpath 'com.android.tools.build:gradle:3.4.0' to classpath 'com.android.tools.build:gradle:3.4.1'.
  • Hire our Development experts.
    dependencies {
    - classpath("com.android.tools.build:gradle:3.4.0")
    + classpath("com.android.tools.build:gradle:3.4.1")
    + classpath 'com.google.gms:google-services:4.2.0'
  • Also, add method google() in allprojects/repositories module in build.gradle file.
  • Hire our Development experts.
    allprojects {
        repositories {
            mavenLocal()
    +       google()
            jcenter()
  • Now open MainApplication.java file and add new RNFirebaseAuthPackage(), new RNFirebaseFirestorePackage() inside the getPackages() function.
  • Hire our Development experts.
     protected List<ReactPackage> getPackages() {
          return Arrays.<ReactPackage>asList(
                new MainReactPackage(), 
                new RNFirebasePackage(),
           +    new RNFirebaseAuthPackage(),
           +    new RNFirebaseFirestorePackage()
          );
        }​
  • Also add subsequent imports to them,as following:
  • Hire our Development experts.
     import com.facebook.react.ReactApplication;
     import io.invertase.firebase.RNFirebasePackage;
    +import io.invertase.firebase.auth.RNFirebaseAuthPackage;
    +import io.invertase.firebase.firestore.RNFirebaseFirestorePackage;​

     

  • These dependencies are only for implementing Authentication and Basic read/write operations.You can add more as well according to the application needs.
  • Now run command react-native run-android in the terminal to check if everything is working correctly.
  • Log in to firebase console and you will see the android app icon with your project's information.

    Android App Firebase

    The Android integration journey is now complete. Pretty easy, right? I assure you, the iOS integration is even easier.

    iOS Setup:

    Open your project in the Firebase console, click on 'add app +' button and select iOS. A new screen will open.

    iOS integration steps

    Then:

    1. First add the Bundle Id (can be found in Xcode>project.xcworkspace>general>bundle identifier) of your project, project nickname and Apple id (Optional).
    2. Then download Google-Service-Info.plist file and add it using Xcode.
    3. Open Xcode> Click on your project name after opening project.xcworkspace file. Click on folder on the left sidebar with same name as project, expand it and select the folder with same name as your project. Select add files to project_name>Add Google-Service-Info.plist file.
    4. Again open the project directory in the editor.
    5. Now open ios folder > podfile. If pod file is not created, create a new one using command pod init.
      ios folder structure
    6. Add pod Firebase/Core, pod 'Firebase/Firestore'and pod 'Firebase/Auth' to podfile. (Remove #use_frameworks from podfile if build doesn't work)
    7. Add lines @import Firebase/#import <Firebase.h> and [FIRApp configure] to AppDelegate.m file of your project.
    Hire our Development experts.
    #import "AppDelegate.h"
    
    #import <React/RCTBridge.h>
    #import <React/RCTBundleURLProvider.h>
    #import <React/RCTRootView.h>
    @import Firebase     //!! add this line !!
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
      [FIRApp configure];        // !! add this line !!
      RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
      RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                       moduleName:@"chat_app"
                                                initialProperties:nil];
    
      rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
    
      self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
      UIViewController *rootViewController = [UIViewController new];
      rootViewController.view = rootView;
      self.window.rootViewController = rootViewController;
      [self.window makeKeyAndVisible];
      return YES;
    }
  • Run pod install.Open project.xcworkspace file of your project and click on play button. Check in the Firebase console for iOS app to see whether integration was successful.
  • Wow!! Integration completed.

    Vue Native is now completely integrated with Firebase. Now, we can make a small chat application.

    Creating Registration and Sign In functionality:

    Let's start by creating the authentication flow for the chat application. We will create a component named Register and Login in Register.vue and login.vue file respectively inside the components folder. You can check the basic Vue-Native components to create a basic template.

    authentication screen

     

    For using Firebase authentication service, we will be using email/password type authentication.

    • Go to authentication section > sign-in method and enable it as shown.

    select auth type

    • Create signUp/Register and signIn functions using below firebase methods in firebaseModules folder.
    firebase.auth().createUserWithEmailAndPassword(email, password)
    firebase.auth().signInWithEmailAndPassword(email, password)
    Checkout the above functions implemented in this link.
    • If the user is the registered successfully using createUserWithEmailAndPassword() function, add a document to users collection about user info as:
    Hire our Development experts.
    async function register (email, password, name) {
      try {
        const registered = await firebase.auth().createUserWithEmailAndPassword(email, password)
        if (registered) {
          await addUser(registered, name)
          return registered.user
        } else {
          return null
        }
      } catch (e) {
        return null
      }
    }
    
    async function addUser (userObject, name) {
      firebase.firestore().collection('users').doc().set({
        // user data
      }).then(res => console.log(res))
    }
    • Similarly create sign-in functionality.
    • Create subsequent Vue Native components for register and signIn in the components folder.
    • Open App.vue file in Vue-Native and in the mounted function add below function to check if any user is already signed-in.
    Hire our Development experts.
     async mounted () {
        await firebase.auth().onAuthStateChanged(function (user) {
          if (user) {
            // go to contacts screen
          } else {
            // go to sign-in
          }
        })
      },
    
    • Similarly, create a  sign-out functionality using firebase function.

    firebase.auth().signOut()

    Creating contacts screen and its functionality:

    After the authentication screen, let's start creating the 'contacts' screen functionality. Let's create a file named Users.vue for Users component inside the components folder.

    contact list

    • Create a getUsers() function to fetch all other users from the database. Send current userId to filter other users.
    Hire our Development experts.
    async function getUsers (userId) {
      let users = []
      firebase.firestore().collection('users').get().then(function (querySnapshot) {
        querySnapshot.forEach(function (doc) {
          if (doc.data().uid != userId) { users.push(doc.data()) }
        })
      }).then(res => console.log(res)).catch(err => console.log(err))
      return users
    }
    • Add a template for showing contact list.
    Hire our Development experts.
    <template>
        <view>
            <text class="text-white">Contacts</text>
            <flat-list :data = 'users'
            :render-item= "(user) => renderUsers(user)"/>
        </view>
    </template>
    • Send userId as props in this component. Checkout this link for more information about props.
    Hire our Development experts.
     props:{
            ...other props
            userUid:{
                Type:String
            },
           }​
  • Call getUsers() function in mounted()This function will be called after the component renders for the first time.
  • Hire our Development experts.
     mounted: async function () {
        this.users = await getUsers(this.userUid)
      },

    Creating Chat Screen and its functionality:

    Now we are only left with chat functionality. For that, we will create the final component in file called Chat.vue inside components folder.

    chat screen

    • Import Firebase from the package as shown below:
    Hire our Development experts.
    import firebase from 'react-native-firebase'
    • Now for sending messages, create a function as below:
    Hire our Development experts.
    async function sendMessage (userId, friendId, text) {
      try {
        await firebase.firestore().collection('messages').doc().set({
          message: text,
          time: newDate(),
          timestamp: Date.now(),
          sender: userId,
          sentTo: friendId,
        })
      } catch (e) {
        return e.message
      }
      return {
        message: text,
        time: newDate(),
        timestamp: Date.now(),
        sender: userId,
        sentTo: friendId,
      }
    }

    For receiving messages, Consider the below function `addListener()`.

    1. Add userId, friendId and message array as parameters for this function.
    2. Write Firebase query for adding listeners to collection for fetching real time messages. Filter query using where condition as shown below.
    3. Note that for the first time, the value doc._type will always be 'added' for all the messages.
    4. In the end, we can sort the messages according to the timestamp or we can also use the orderBy function from Firebase.
    Hire our Development experts.
    async function addListener (userId, friendId, messages) {
      await firebase.firestore().collection('messages').where('sender', '==',
        friendId).where('sentTo', '==', userId).onSnapshot(async function (querySnapshot) {
        console.log(querySnapshot._changes)
        await querySnapshot._changes.forEach(function (doc) {
          if (doc._type == 'added') {
            messages.push(doc.doc.data())
            messages.sort((message1, message2) => message1.timestamp -
                   message2.timestamp)
          }
        })
      })
      await firebase.firestore().collection('messages').where('sender', '==',
        userId).where('sentTo', '==', friendId).onSnapshot(async function (querySnapshot) {
        await querySnapshot._changes.forEach(function (doc) {
          if (doc._type == 'added') {
            messages.push(doc.doc.data())
            messages.sort((message1, message2) => message1.timestamp -
                    message2.timestamp)
          }
        })
      })
      return messages
    }
    • Now, create a Vue Native component for the chat-screen containing a text input and a flatlist or list of view to show messages. Checkout the render-prop-fn in Vue-Native to render the list in Vue-Native only.
    Hire our Development experts.
    <template>
        <view> 
          <view class="user">
            <image :source="require('../assets/user-male.png')" class="profile-pic"/>
            <text class="text-bold">
            {{ friendName }}
            <text>
          </view> 
          <view class="message-view">
            <text-input v-model="text" class="message-box" placeholder="Type Message" />
            <touchable-opacity :on-press="()=>sendMessage()" :disabled="(text == '')">
              <view  class="button-view">
                <text class="color-white">Send</text>
              </view>
            </touchable-opacity>  
            </view>
            <scroll-view :content-container-style="{contentContainer: {
              flex:1
            }}">
            <flat-list :data='messages'
              :render-item= "(message) => renderMessage(message)"
              >
            </flat-list>
            </scroll-view>
        </view>
    </template>
    • Now in the data section, add variable messages that are going to be passed as parameter for the addListener function.
    Hire our Development experts.
     data: function () {
        return {
          text: '',
          messages: [],
          friendName: '',
          date: '',
        }
      },
    • Import addListener() and sendMessage() function from send-message.js. Add sendMessage() method to send messages and clear the input afterwards.
    Hire our Development experts.
     methods: {
        sendMessage: async function () {
          var newMessage = await sendMessage(this.userId, this.friendId, this.text)
          this.text = ''
        },
      },
    Hire our Development experts.
     mounted: async function () {
        this.messages = await addListener(this.userId, this.friendId, this.messages)
      },

    Since we have added the messages variable to data, it becomes reactive. Now for every change in messages array, there will be change in the UI or the view. At the end, import all components in App.vue to conditionally render according to user existing or not. Also you can simply use vue-native-router for navigation b/w screens.

    If you followed the above steps correctly, a simple demo for the chat application using Vue Native & Firebase is ready for you.

    chat-application

    Check out the full project on https://github.com/anmoljain10/chat-app-vue-native

    It contains all Vue Native components and also the authentication layer for the app. If there are any queries or suggestions that you have, please leave them in the comments section on GitHub and I will respond to as many as I can.

    For more information about Vue Native, you can go to this link.

    Thank you for reading!

    Hire our Development experts.