Let’s make a personal, secure android app like WhatsApp 😎. Do you use ? Do you have interest in ? Are you interested in making a personal chat application like WhatsApp? WhatsApp/Facebook Messenger Java or Android If yes, then you’re at the . perfect place It will be your own app with . You would be in almost . no ads, no privacy issues and nothing full control So, here we will learn making a simple chat application that has l that you can send to talk with your friends. ogin/signup feature, and chat messages implementation For this we will be using , as the backend to store the chats and send them to other device. Firebase-Realtime-Database You can find the entire code for the app here. First off, let’s understand our app , that’d help us in our way, if we are stuck at some point. using a simple flow chart Our android app → User signs up or logs in → User can choose the friend he wants to send message to → User can type and send the message → The friend would receive the message on his device. Internally we would store the message on our database and then send it to the desired user. This is a and so we would only be doing this much in it. But you can add much more cooler aspects in the app, once you’re done with this. demo purpose app Firebase provides tons of amazing facilities you can use in your app like . ML Kit, Realtime notifications and lot more Setting Up Firebase First of all, create a firebase account. Follow following steps: Here the name is for demo purposes, you can use whatever name or titles you want, and go with them. Go to Firebase website from , and create a firebase account to start with. Go to Firebase console and Create a New Project by clicking on the “ ” Button as shown below. this link Create New Project Firebase 2. Give the Project name and country you are currently in, Once you are done click on “ ” button. Create Project Project 3. In the next screen choose “Add Firebase to your Android app” and then add the package details and Debug signing certificate SHA-1 key( This is required if you want to enable certain features like Dynamic Links, Invites, and Google Sign-In etc. otherwise it is an optional field). Android chatting app This will download the google-services.json file. Download it to your computer. We will add it to our android app later. This is required because the default security rules for the Android Firebase allows only authenticated users to read and write. Then click on the Database tab in the Firebase Menu. It shows the root of the , we would be adding a child node called listItems and then will add each item under it. JSON tree When we add data to the JSON tree, it becomes a new node in the existing JSON structure with an associated key. Also . And don’t forget to change them in the codes below. copy the URL of database You can check the Rules tab to see or change the security rules for reading and writing on Android Firebase Database. Below figure shows the default settings. Firebase rules You can change these to true, if you want free unauthenticated access to your Firebase. Once you are done with this, Let’s create our that will connect to we have just created. Android chat Application Firebase Database Now that we’re almost done setting up Firebase, let’s dive into some android code. First make a like android studio, and name your first activity as Register. new Android Project in your IDE Needless to say, we’re naming this activity like that, because we have in the app that have different functions. more activities Add the following code in your activity. Register public class Register extends AppCompatActivity {EditText username, password;Button registerButton;String user, pass;TextView login; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity\_register); username = (EditText)findViewById(R.id.username); password = (EditText)findViewById(R.id.password); registerButton = (Button)findViewById(R.id.registerButton); login = (TextView)findViewById(R.id.login); Firebase._setAndroidContext_(this); login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(Register.this, Login.class)); } }); registerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { user = username.getText().toString(); pass = password.getText().toString(); if(user.equals("")){ username.setError("can't be blank"); } else if(pass.equals("")){ password.setError("can't be blank"); } else if(!user.matches("\[A-Za-z0-9\]+")){ username.setError("only alphabet or number allowed"); } else if(user.length()<5){ username.setError("at least 5 characters long"); } else if(pass.length()<5){ password.setError("at least 5 characters long"); } else { final ProgressDialog pd = new ProgressDialog(Register.this); pd.setMessage("Loading..."); pd.show(); String url = "https://chatapp-60323.firebaseio.com/users.json"; StringRequest request = new StringRequest(Request.Method._GET_, url, new Response.Listener<String>(){ @Override public void onResponse(String s) { Firebase reference = new Firebase("https://chatapp-60323.firebaseio.com/users"); if(s.equals("null")) { reference.child(user).child("password").setValue(pass); Toast._makeText_(Register.this, "registration successful", Toast._LENGTH\_LONG_).show(); } else { try { JSONObject obj = new JSONObject(s); if (!obj.has(user)) { reference.child(user).child("password").setValue(pass); Toast._makeText_(Register.this, "registration successful", Toast._LENGTH\_LONG_).show(); } else { Toast._makeText_(Register.this, "username already exists", Toast._LENGTH\_LONG_).show(); } } catch (JSONException e) { e.printStackTrace(); } } pd.dismiss(); } },new Response.ErrorListener(){ @Override public void onErrorResponse(VolleyError volleyError) { System._out_.println("" + volleyError ); pd.dismiss(); } }); RequestQueue rQueue = Volley._newRequestQueue_(Register.this); rQueue.add(request); } } }); } } This code sets up your registering in your firebase database. As you might wonder, the which essentially means, you don’t need to query stuff using SQL. Firebase database is a NoSQL Firebase uses reference method to retrieve and put the values. So we have to decide on what and how to make our database structure. Here we also are going to make user sign up and sign in using a custom username and password, so we’ve to keep this in mind too. The that I’ve come up for this app is based on . We keep authentication details in a parent node named “users” and messages in another parent node named “messages”. database structure simplicity Inside messages we also keep track of who messaged whom by the order of the usernames. So in image, in action. this structure would look something like this Used for authentication: Users database structure Used for messaging: Messages database structure Please keep in mind, , so here I have . But this can be made very secure using Firebase and you may do so after building this, on your own. that this a demo app for tutorial purposes not used any method to keep this secure Let’s go back to our android code again. So yes, errors. Do you and tons of red lines, after adding that code in the register activity? see errors in your project Don’t worry, I am not buffing about anything. The errors will go away. First let’s add our . You might also want to connect your app to the firebase account you’ve made. dependencies To connect it to your firebase project, go to Tools → Firebase → Realtime database → Save and retrieve data → Connect your app to Firebase. Just sign in again and select your project, and it should get connected. You might also want to follow other steps in the same tab, like adding database to your app. Or, you can just copy paste in your module app of the project. these set of dependencies dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.support:appcompat-v7:28.0.0'implementation 'com.firebase:firebase-client-android:2.5.2'implementation 'com.android.volley:volley:1.0.0'implementation 'com.android.support.constraint:constraint-layout:1.1.3'implementation 'com.google.firebase:firebase-database:16.0.5'implementation 'com.google.firebase:firebase-auth:16.1.0'testImplementation 'junit:junit:4.12'androidTestImplementation 'com.android.support.test🏃1.0.2'androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'} Now, . Others will also, as we proceed. just hit alt+Enter, on the errors, and most of them should go away Let’s add the activity code, which looks something like this: Login public class Login extends AppCompatActivity {TextView registerUser;EditText username, password;Button loginButton;String user, pass; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity\_login); registerUser = findViewById(R.id.register); username = findViewById(R.id.username); password = findViewById(R.id.password); loginButton = findViewById(R.id.loginButton); registerUser.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(Login.this, Register.class)); } }); loginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { user = username.getText().toString(); pass = password.getText().toString(); if(user.equals("")){ username.setError("can't be blank"); } else if(pass.equals("")){ password.setError("can't be blank"); } else{ String url = "https://chatapp-60323.firebaseio.com/users.json"; final ProgressDialog pd = new ProgressDialog(Login.this); pd.setMessage("Loading..."); pd.show(); StringRequest request = new StringRequest(Request.Method._GET_, url, new Response.Listener<String>(){ @Override public void onResponse(String s) { if(s.equals("null")){ Toast._makeText_(Login.this, "user not found", Toast._LENGTH\_LONG_).show(); } else{ try { JSONObject obj = new JSONObject(s); if(!obj.has(user)){ Toast._makeText_(Login.this, "user not found", Toast._LENGTH\_LONG_).show(); } else if(obj.getJSONObject(user).getString("password").equals(pass)){ UserDetails._username_ \= user; UserDetails._password_ \= pass; startActivity(new Intent(Login.this, Users.class)); } else { Toast._makeText_(Login.this, "incorrect password", Toast._LENGTH\_LONG_).show(); } } catch (JSONException e) { e.printStackTrace(); } } pd.dismiss(); } },new Response.ErrorListener(){ @Override public void onErrorResponse(VolleyError volleyError) { System._out_.println("" + volleyError); pd.dismiss(); } }); RequestQueue rQueue = Volley._newRequestQueue_(Login.this); rQueue.add(request); } } }); } } We may also now add our activity code, which will be the place where the chats are seen. chat public class Chat extends AppCompatActivity {LinearLayout layout;RelativeLayout layout_2;ImageView sendButton;EditText messageArea;ScrollView scrollView;Firebase reference1, reference2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity\_chat); layout = findViewById(R.id.layout1); layout\_2 = findViewById(R.id.layout2); sendButton = findViewById(R.id.sendButton); messageArea = findViewById(R.id.messageArea); scrollView = findViewById(R.id.scrollView); Firebase._setAndroidContext_(this); reference1 = new Firebase("https://chatapp-60323.firebaseio.com/messages/" + UserDetails._username_ \+ "\_" + UserDetails._chatWith_); reference2 = new Firebase("https://chatapp-60323.firebaseio.com/messages/" + UserDetails._chatWith_ \+ "\_" + UserDetails._username_); sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String messageText = messageArea.getText().toString(); if(!messageText.equals("")){ Map<String, String> map = new HashMap<String, String>(); map.put("message", messageText); map.put("user", UserDetails._username_); reference1.push().setValue(map); reference2.push().setValue(map); messageArea.setText(""); } } }); reference1.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) { Map map = dataSnapshot.getValue(Map.class); String message = map.get("message").toString(); String userName = map.get("user").toString(); if(userName.equals(UserDetails._username_)){ addMessageBox(message, 1); } else{ addMessageBox(message, 2); } } @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(FirebaseError firebaseError) { } }); } public void addMessageBox(String message, int type){ TextView textView = new TextView(Chat.this); textView.setText(message); LinearLayout.LayoutParams lp2 = new LinearLayout.LayoutParams(ViewGroup.LayoutParams._WRAP\_CONTENT_, ViewGroup.LayoutParams._WRAP\_CONTENT_); lp2.weight = 7.0f; if(type == 1) { lp2.gravity = Gravity._LEFT_; textView.setBackgroundResource(R.drawable.bubble\_in); } else{ lp2.gravity = Gravity._RIGHT_; textView.setBackgroundResource(R.drawable.bubble\_out); } textView.setLayoutParams(lp2); layout.addView(textView); scrollView.fullScroll(View._FOCUS\_DOWN_); } } Also, the activity where we would see the list of for the app. users public class Users extends AppCompatActivity {ListView usersList;TextView noUsersText;ArrayList<String> al = new ArrayList<>();int totalUsers = 0;ProgressDialog pd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity\_users); usersList = (ListView)findViewById(R.id.usersList); noUsersText = (TextView)findViewById(R.id.noUsersText); pd = new ProgressDialog(Users.this); pd.setMessage("Loading..."); pd.show(); String url = "https://chatapp-60323.firebaseio.com/users.json"; StringRequest request = new StringRequest(Request.Method._GET_, url, new Response.Listener<String>(){ @Override public void onResponse(String s) { doOnSuccess(s); } },new Response.ErrorListener(){ @Override public void onErrorResponse(VolleyError volleyError) { System._out_.println("" + volleyError); } }); RequestQueue rQueue = Volley._newRequestQueue_(Users.this); rQueue.add(request); usersList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { UserDetails._chatWith_ \= al.get(position); startActivity(new Intent(Users.this, Chat.class)); } }); } public void doOnSuccess(String s){ try { JSONObject obj = new JSONObject(s); Iterator i = obj.keys(); String key = ""; while(i.hasNext()){ key = i.next().toString(); if(!key.equals(UserDetails._username_)) { al.add(key); } totalUsers++; } } catch (JSONException e) { e.printStackTrace(); } if(totalUsers <=1){ noUsersText.setVisibility(View._VISIBLE_); usersList.setVisibility(View._GONE_); } else{ noUsersText.setVisibility(View._GONE_); usersList.setVisibility(View._VISIBLE_); usersList.setAdapter(new ArrayAdapter<String>(this, android.R.layout._simple\_list\_item\_1_, al)); } pd.dismiss(); } } Now let’s make a class to help get details in a better way, that is: simple Java public class UserDetails {static String = "";static String = "";static String = "";} username password chatWith And yes, we’re all done with our app… Oh wait, you’re still getting errors? That should not be happening, I don’t know what went wrong… Nah, just kidding 😆 We’re yet to add the UI code, and that’s what the errors might also be stating. So let’s first add activity. UI code for register <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/back"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.pd.chatapp.Register"android:orientation="vertical"android:gravity="center"> <TextView android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:text="@string/register" android:textSize="30sp" android:gravity="center" android:layout\_marginBottom="20dp"/> <EditText android:id="@+id/username" android:layout\_width="365dp" android:layout\_height="49dp" android:layout\_marginBottom="10dp" android:background="#000000" android:hint="@string/enter\_username" android:inputType="text" android:maxLines="1" android:textColor="#ffffff" /> <EditText android:id="@+id/password" android:layout\_width="363dp" android:layout\_height="50dp" android:layout\_marginBottom="10dp" android:background="#000000" android:hint="@string/enter\_password" android:inputType="textPassword" android:maxLines="1" android:textColor="#ffffff" /> <Button android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:text="@string/register" android:id="@+id/registerButton" android:layout\_marginBottom="20dp"/> <TextView android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:text="@string/click\_here\_to\_login" android:textSize="20sp" android:gravity="center" android:id="@+id/login"/> </LinearLayout> For activity. chat <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/back"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:orientation="vertical"tools:context="com.pd.chatapp.Chat"> <ScrollView android:layout\_width="match\_parent" android:layout\_weight="20" android:layout\_height="0dp" android:id="@+id/scrollView"> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout2" android:layout\_width="match\_parent" android:layout\_height="wrap\_content"> <LinearLayout android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:orientation="vertical" android:id="@+id/layout1"> </LinearLayout> </RelativeLayout> </ScrollView> <include layout="@layout/message\_place" android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:gravity="bottom" android:layout\_marginTop="5dp"/> </LinearLayout> Also for our activity. login <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:background="@drawable/back"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.pd.chatapp.Login"android:orientation="vertical"android:gravity="center"> <TextView android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:layout\_marginBottom="20dp" android:gravity="center" android:text="@string/login" android:textSize="30sp" /> <EditText android:id="@+id/username" android:layout\_width="362dp" android:layout\_height="49dp" android:layout\_marginBottom="10dp" android:background="#000000" android:hint="@string/enter\_username" android:inputType="text" android:maxLines="1" android:textColor="#ffffff" /> <EditText android:id="@+id/password" android:layout\_width="358dp" android:layout\_height="49dp" android:layout\_marginBottom="10dp" android:background="#000000" android:hint="@string/enter\_password" android:inputType="textPassword" android:maxLines="1" android:textColor="#ffffff" /> <Button android:id="@+id/loginButton" android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:layout\_marginBottom="20dp" android:text="@string/login" /> <TextView android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:text="@string/click\_here\_to\_register" android:textSize="20sp" android:gravity="center" android:id="@+id/register"/> </LinearLayout> And let’s not forget the activity. user’s place <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.pd.chatapp.Users"android:orientation="vertical"> <TextView android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:text="@string/no\_users\_found" android:id="@+id/noUsersText" android:visibility="gone"/> <ListView android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:id="@+id/usersList"/> </LinearLayout> Also for a better view, we’ve made message area in a different layout file. So make a new xml file, with name . message_place.xml And add the following code to it. <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="bottom"android:orientation="horizontal"> <EditText android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:layout\_weight="1" android:textColorHint="#CFD8DC" android:textColor="#CFD8DC" android:hint="@string/write\_a\_message" android:id="@+id/messageArea" android:maxHeight="80dp" /> <ImageView android:layout\_width="match\_parent" android:layout\_height="wrap\_content" android:layout\_weight="4" android:padding="4dp" android:src="@android:drawable/ic\_menu\_send" android:id="@+id/sendButton"/> </LinearLayout> What? You’re still getting some errors? Don’t worry that’s because you’re missing the background and other images or resources we’ve used. You may find all of them on my GitHub account repository. . The source code of the app Hell, yes! Now . Fully done app should greet you with a screen like this: we’re really fully done Android app Made everything , right? worth the effort Now what are you waiting for? . Chat with your friends, using your own app Go and show off!! Read my previous post about making a machine learning android game from scratch.