Creating a Chat Application using Vue-Native and Firebase
Creating a Chat Application using Vue-Native and Firebase
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.
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.
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.
Android Setup:
After successful creation of project you will see 'add app +' icon on the project dashboard.
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:
- 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).
- Then download the google-services.json file (This file is mandatory for accessing Firebase operations) and place it inside the
app
folder of android. - Open your project in the editor and navigate to android folder.
- Add the following dependencies to android/app/build.gradle file :
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 addmultiDexEnabled true
in thedefaultConfig
object. - Now open the android/build.gradle file. Change
classpath 'com.android.tools.build:gradle:3.4.0'
toclasspath 'com.android.tools.build:gradle:3.4.1'.
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()
inallprojects/repositories
module in build.gradle file.allprojects { repositories { mavenLocal() + google() jcenter()
- Now open MainApplication.java file and add
new RNFirebaseAuthPackage()
,new RNFirebaseFirestorePackage()
inside thegetPackages()
function.protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new RNFirebasePackage(), + new RNFirebaseAuthPackage(), + new RNFirebaseFirestorePackage() ); }
- Also add subsequent imports to them,as following:
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.
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.
Then:
- First add the Bundle Id (can be found in Xcode>project.xcworkspace>general>bundle identifier) of your project, project nickname and Apple id (Optional).
- Then download Google-Service-Info.plist file and add it using Xcode.
- 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.
- Again open the project directory in the editor.
- Now open ios folder > podfile. If pod file is not created, create a new one using command
pod init
. - Add
pod Firebase/Core
,pod 'Firebase/Firestore'
andpod 'Firebase/Auth'
to podfile. (Remove#use_frameworks
from podfile if build doesn't work) - Add lines
@import Firebase/#import <Firebase.h>
and[FIRApp configure]
to AppDelegate.m file of your project.#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.
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.
- Create signUp/Register and signIn functions using below firebase methods in firebaseModules folder.
firebase.auth().createUserWithEmailAndPassword(email, password)
firebase.auth().signInWithEmailAndPassword(email,
password)
- If the user is the registered successfully using
createUserWithEmailAndPassword()
function, add a document to users collection about user info as:
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
andsignIn
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.
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.
- Create a
getUsers()
function to fetch all other users from the database. Send currentuserId
to filter other users.
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.
<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.
props:{ ...other props userUid:{ Type:String }, }
- Call
getUsers()
function inmounted()
. This function will be called after the component renders for the first time.
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.
- Import Firebase from the package as shown below:
import firebase from 'react-native-firebase'
- Now for sending messages, create a function as below:
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()
`.
- Add
userId
,friendId
andmessage
array as parameters for this function. - Write Firebase query for adding listeners to collection for fetching real time messages. Filter query using where condition as shown below.
- Note that for the first time, the value
doc._type
will always be 'added' for all the messages. - In the end, we can sort the messages according to the timestamp or we can also use the
orderBy
function from Firebase.
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.
<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 theaddListener
function.
data: function () {
return {
text: '',
messages: [],
friendName: '',
date: '',
}
},
- Import
addListener()
andsendMessage()
function fromsend-message.js
. AddsendMessage()
method to send messages and clear the input afterwards.
methods: {
sendMessage: async function () {
var newMessage = await sendMessage(this.userId, this.friendId, this.text)
this.text = ''
},
},
- Now in the mounted function, call:
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.
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!