Introduction

In this tutorial, you will learn how to implement the read receipt feature on your Android app with the help of MirrorFly SDKs. This entire tutorial is coded in Java, and the steps are illustrated to develop apps in Android Studio.

Please note that this guide assumes that you have a basic familiarity with Javascript . With no further ado, Let’s begin!

Steps To Implement Read Receipts

Read receipts is a chat app feature that lets senders know when the message they’ve sent is opened or read by the recipient. To implement this feature, you’ll need a ready-to-integrate SDK, which is available to download instantly from MirrorFly.

Let’s take a closer look into the steps to build read receipts into Android apps:

I. Downloading The Chat SDKs

Step 1 : Go to the Signup Page

#


Step 2 : Sign up using your Google or LinkedIn account or,

Step 3 : Fill in the sign up details. An account confirmation link will be sent to your email.

Step 4 : Click the link and verify your account.

Step 5 : On confirmation, you will be taken to the Account Dashboard

Step 6 : Extract the dependencies from the ZIP folder. We’ll use these files in Part 2

Step 7 : Next, scroll down to find the License Key

Step 8 : You’ll need this License key in Part 3

II . Setting Up The New App Project in Android Studio

Note: This Tutorial uses Android Studio for explanation purposes. However, MirrorFly’s SDKs can be used on any IDEs of your choice to build Android apps.

In this step, we’ll create a New Android App project.

Step 1 : Open the Android Studio IDE

#


Step 2 : Fill in the details of your project on the Welcome Page

Step 3 : Select the programming language as Java

Step 4 : The project dashboard will open. On this page, go to the project menu on the left side

Step 5 : Select the App folder

Step 6 : Import all the dependencies downloaded in Part 1

III. Integrating The Chat SDK With The App

Once the dependencies are added to the project,

Step 1 : Add the below code to the build gradle of your app folder


                  plugins { 
                       ... 
                       id 'kotlin-android' 
                       id 'kotlin-kapt' 
                   } 
                    
                   android { 
                       compileOptions { 
                           sourceCompatibility JavaVersion.VERSION_1_8 
                           targetCompatibility JavaVersion.VERSION_1_8 
                       } 
                    
                       kotlinOptions { 
                           jvmTarget = '1.8' 
                       } 
                    
                       packagingOptions { 
                           exclude 'META-INF/AL2.0' 
                           exclude 'META-INF/DEPENDENCIES' 
                           exclude 'META-INF/LICENSE' 
                           exclude 'META-INF/LICENSE.txt' 
                           exclude 'META-INF/license.txt' 
                           exclude 'META-INF/NOTICE' 
                           exclude 'META-INF/NOTICE.txt' 
                           exclude 'META-INF/notice.txt' 
                           exclude 'META-INF/ASL2.0' 
                           exclude 'META-INF/LGPL2.1' 
                           exclude("META-INF/*.kotlin_module") 
                       } 
                    
                   } 

                 

Step 2 : Next, add the dependencies to the app/build.gradle file


                   dependencies { 
                  
                     ... // your app dependencies 
                  
                     implementation files('libs/appbase.aar') 
                     implementation files('libs/flycommons.aar') 
                     implementation files('libs/flynetwork.aar') 
                     implementation files('libs/flydatabase.aar') 
                     implementation files('libs/videocompression.aar') 
                     implementation files('libs/xmpp.aar') 
                  
                 } 
              

Step 3 : Add the below modules to the app/build.gradle file


               dependencies { 
                
                   ... // your app dependencies 
                
                   configurations { 
                       all { 
                           exclude group: 'org.json', module: 'json' 
                           exclude group: 'xpp3', module: 'xpp3' 
                       } 
                   } 
                
                   //For lifecycle listener 
                   implementation 'android.arch.lifecycle:extensions:1.1.1' 
                   annotationProcessor 'android.arch.lifecycle:compiler:1.1.1' 
                
                   //For GreenDao 
                   implementation 'de.greenrobot:greendao:2.1.0' 
                
                   //For gson parsing 
                   implementation 'com.google.code.gson:gson:2.8.1' 
                
                   //for smack implementation 
                   implementation 'org.igniterealtime.smack:smack-android:4.4.4' 
                   implementation 'org.igniterealtime.smack:smack-tcp:4.4.4' 
                   implementation 'org.igniterealtime.smack:smack-im:4.4.4' 
                   implementation 'org.igniterealtime.smack:smack-extensions:4.4.4' 
                   implementation 'org.igniterealtime.smack:smack-sasl-provided:4.4.4' 
                
                   implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' 
                   implementation 'androidx.multidex:multidex:2.0.1' 
                   implementation 'com.google.android.gms:play-services-location:17.0.0' 
                
                   //Dagger Dependencies 
                   api 'com.google.dagger:dagger:2.40.5' 
                   kapt 'com.google.dagger:dagger-compiler:2.40.5' 
                   api 'com.google.dagger:dagger-android:2.40.5' 
                   api 'com.google.dagger:dagger-android-support:2.40.5' 
                   kapt 'com.google.dagger:dagger-android-processor:2.40.5' 
                
                   //coroutines 
                   implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8' 
                   implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.8' 
                
                   //apicalls 
                   implementation 'com.squareup.retrofit2:retrofit:2.6.1' 
                   implementation 'com.squareup.retrofit2:converter-gson:2.6.1' 
                   implementation 'com.squareup.okhttp3:okhttp:4.2.0' 
                   implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2' 
                
                   //stetho interceptor 
                   implementation 'com.facebook.stetho:stetho-okhttp3:1.3.1' 
                
                   //okhttp interceptor 
                   implementation 'com.squareup.okhttp3:logging-interceptor:3.14.3' 
                
                   //shared preference encryption 
                   implementation 'androidx.security:security-crypto:1.1.0-alpha03' 
                
                   //for mobile number formatting 
                   implementation 'io.michaelrocks:libphonenumber-android:8.10.1' 
                
               } 

                

Step 4 : In order to refrain from conflict among the imported library files, we’ll need to add the below code to the gradle.properties file


                   android.enableJetifier=true 
                  

Step 5 : Next, add the permissions to AndroidManifest.xml


               <uses-permission android:name="android.permission.INTERNET" /> 
               <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
              

Step 6 : Now, we need to add the License key to the app/build.gradle file


                   buildTypes { 
                       debug { 
                         buildConfigField 'String', 'SDK_BASE_URL', '"https://api-preprod-sandbox.mirrorfly.com/api/v1/"' 
                         buildConfigField 'String', 'LICENSE', '"xxxxxxxxxxxxxxxxxxxxxxxxx"' 
                         buildConfigField 'String', 'WEB_CHAT_LOGIN', '"https://webchat-preprod-sandbox.mirrorfly.com/"' 
                         buildConfigField "String", "SUPPORT_MAIL", '"contussupport@gmail.com"' 
                       } 
                   } 
                      
                  

IV. Initializing The Chat SDK

This step will collect all the essential data like client and server details to start the data exchange between user devices.

Step 1 : To kickstart, add the below code to the onCreate() method of the Application class


                       //For chat logging 
                     LogMessage.enableDebugLogging(BuildConfig.DEBUG); 
                      
                     new ChatSDK.Builder() 
                         .setDomainBaseUrl(BuildConfig.SDK_BASE_URL) 
                         .setLicenseKey(BuildConfig.LICENSE) 
                         .setIsTrialLicenceKey(true) 
                         .build();  

                  

V. Registering The App User

This step is used to register the user in the sandbox or live mode. The below code will check if the license key is on trial and register the user


                     FlyCore.registerUser(USER_IDENTIFIER, (isSuccess, throwable, data ) -> { 
                       if(isSuccess) { 
                           Boolean isNewUser = (Boolean) data.get("is_new_user"); 
                           JSONObject responseObject = (JSONObject) data.get("data"); 
                         // Get Username and password from the object 
                       } else { 
                         // Register user failed print throwable to find the exception details. 
                       } 
                       }); 
                  

VI. Connecting To Chat Server

To connect the client-side apps, we’ll need a central server that can execute data exchange between the devices. The below SDK method will set up the server connection and start receiving and sending the data on client requests from user devices.


                   ChatManager.connect(new ChatConnectionListener() { 
                       @Override 
                       public void onConnected() { 
                           // Write your success logic here to navigate Profile Page or 
                           // To Start your one-one chat with your friends 
                       } 
                    
                       @Override 
                       public void onDisconnected() { 
                         // Connection disconnected 
                         //No need implementations 
                       } 
                    
                     @Override 
                       public void onConnectionNotAuthorized() { 
                         // Connection Not authorized 
                         //No need implementations 
                     } 
                   }); 

                  

VII. Sending Messages

Once, the server connection is established, you can start sending messages from a device through the SDK by implementing the following method


                   FlyMessenger.sendTextMessage(TO_JID, TEXT, new SendMessageListener() { 
                     @Override 
                     public void onResponse(boolean isSuccess, @Nullable ChatMessage chatMessage) { 
                         // you will get the message sent success response 
                     } 
                 }); 

                  

VIII. Receiving Messages

This method will be used to notify the user device when new incoming messages are received on the user device.


                    @Override 
                        public void onMessageReceived(@NonNull ChatMessage message) { 
                            super.onMessageReceived(message); 
                            // received message object 
                        } 

                   }); 

                  

IX. Adding The Read Receipt Feature

Once the app can send and receive messages, the user needs the status of the message delivery on the UI. The below method will notify the user when the recipient has opened the sent message.

Before setting this up, we’ll need to make a few configurations with the user jid. Here are the steps:

Step 1 : We’ll need to set the user jid as ongoing chat user in the activity/fragment onResume


                       @Override 
                     public void onResume() { 
                             super.onResume(); 
                             ChatManager.setOnGoingChatUser(JID); 
                         } 


                  

Step 2 : Next, we’ll need to clear the ongoing chat user in the activity/fragment onPause


                   @Override 
                         public void onPause() { 
                               super.onPause(); 
                               ChatManager.setOnGoingChatUser(""); 
                           } 
                  

Step 3 : Now, when the chat window is opened, the recipient jid will be passed to the below method

Step 4 : The SDK will start using the user jid set by the ChatManager.setOnGoingChatUser(jid: String)


                      ChatManager.markAsRead(JID)
                  

X. Observing The Message Events

Using the below method, we can register a listener to update the user UI immediately on any message related events. When a message is sent via the SDK, the message status events will give the respective callbacks.


                   ChatEventsManager.setupMessageEventListener(new MessageEventsListener() { 
                         @Override 
                         public void onMessageReceived(@NotNull ChatMessage message) { 
                           //called when the new message is received 
                         } 
                      
                         @Override 
                         public void onMessageStatusUpdated(@NotNull String messageId) { 
                           //called when the message status is updated 
                           //find the index of message object in list using messageId 
                           //then fetch message object from db using `FlyMessenger.getMessageOfId(messageId)` and notify the item in list 
                         } 
                      
                         @Override 
                         public void onMediaStatusUpdated(@NotNull ChatMessage message) { 
                           //called when the message status is updated 
                           //find the index of message object in list using messageId 
                           //then fetch message object from db using `FlyMessenger.getMessageOfId(messageId)` and notify the item in list 
                         } 
                      
                         @Override 
                         public void onUploadDownloadProgressChanged(@NotNull String messageId, int progressPercentage) { 
                         //called when the media message progress is updated 
                         } 
                      
                         @Override 
                         public void onMessagesClearedOrDeleted(@NotNull ArrayList messageIds) { 
                         //called when the message is deleted 
                         } 
                     }); 


                  

Conclusion

Through this tutorial, we have seen the steps to implement read receipts in an Android chat app , including the respective code samples. To explore more features for your app, we encourage you to check out our Features page.

Also, you can also gain further details and support with the implementation from our team of experts. Contact us now!

Looking To Build Realtime Chat App?

Start today with MirrorFly APIs and services to scale 1 Billion+ Conversations.

  • Average API response 3s
  • 100ms worldwide latency
  • 1 Billion+ Conversations
Try for free
#
Explore Our Free SDKs For 21 Days!

Integrate Our Video, Voice & Chat SDKs into any app in < 30 mins

Try it free
#
Get Started With Our Self-hosted Chat Solution Today!

Get Full Access To Our Customizable Video, Voice & Chat SDKs!

Contact Sales