How to add Flutter In-app Chat to your app? (10 mins)
Tags: flutter, programming, tutorial
Published: 2023-11-16 12:54:20

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fow40jhebj4cd8rgneni.jpg)
In this tutorial, you’ll learn how to add Fluttter in-app communication to your app in just 10 minutes. Let it be any size of app and deployed on any platform. You can easily add MirrorFly in-app chat, voice, and video SDKs by following the simple protocols in this tutorial.

Flutter is the most popular cross-platform framework currently being used by more than `[46% of developers across the world](https://www.statista.com/statistics/869224/worldwide-software-developer-working-hours/). Make your Flutter app more engaging with in-app communication SDKs.

## Let’s be clear about all the things covered in this blog

1. Prerequisites
2. Getting started with MirrorFly account
3. Initializing and Installing the SDKs
4. Integrating chat and call SDKs with your Flutter app
5. Integrating additional features

## Prerequisites

- Android Lolipop 5.0 (API level 21) or above
- Java 7  or higher
- Gradle 4.1.0 or higher
- iOS 12.1 or later
- Xcode 14.1 or later
- Swift 5.0 or later

## Getting started

**Integrate Chat SDKs**

Initially, you need a MirrorFly account to start with the integration steps. Follow the below method
**Step 1:** Go to [MirrorFly console page](https://console.mirrorfly.com/register) and create your account
**Step 2:** Complete the setup of your account
**Step 3:** Acquire MirrorFly license key from the overview page

**Step 1: Create Android Dependency**
In your Android folder, add the following to your root **build.gradle**
`allprojects {
 repositories {
     google()
     mavenCentral()
     jcenter()
     maven {
         url "https://repo.mirrorfly.com/snapshot/"
     }
 }
}
`
Now add the following dependencies in the **app/build.gradle** file
`android {
    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: Create iOS Dependency**
Add the following code in the end of your **ios/podfile**
`post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.1'
      config.build_settings['ENABLE_BITCODE'] = 'NO'
      config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No'
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
      config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
     end
  end
end
`
Now, enable all the below mentioned capabilities in your project.
`Goto Project -> Target -> Signing & Capabilities -> Click + at the top left corner -> Search for the capabilities below
`
**Step 3: Create Flutter Dependency**
In your pubspec.yaml, add the below dependencies
`dependencies:
  mirrorfly_plugin: ^0.0.12
`
Now, run **flutter pub get** command in your project library. You can also use all classes and methods with the following statement.
`import 'package:mirrorfly_plugin/mirrorfly.dart';
`
**Step 4: Initialize MirrorFly Plugin**
In order to initalize the plugin, place the below code in your **main.dart** file - inside the main function - before **runApp()**.
`void main() {
  WidgetsFlutterBinding.ensureInitialized();
  Mirrorfly.init(
      baseUrl: 'https://api-preprod-sandbox.mirrorfly.com/api/v1/',
      licenseKey: 'Your_Mirrorfly_Licence_Key',
      iOSContainerID: 'Your_iOS_app_Group_id');
  runApp(const MyApp());
 }
`
**Step 5: Register a User**

To register a user, follow the below method.
`Mirrorfly.registerUser(userIdentifier).then((value) {
  // you will get the user registration response
  var userData = registerModelFromJson(value);
}).catchError((error) {
    // Register user failed print throwable to find the exception details.
    debugPrint(error.message);
});
`

> **Note:** During registration, the above registerUser method will accept the FCM_TOKEN as an optional parameter and pass it across. The connection will be established automatically upon completion of registration and is not required for separate logins.

**Step 6: Send a One-to-one Message**

Call the below method to to start sending message to another user

> Note: To generate unique user JID by **username** call the below method
`var userJid = await Mirrorfly.getJid(username);`
`Mirrorfly.sendTextMessage(message, jid).then((value) {
  // you will get the message sent success response
  var chatMessage = sendMessageModelFromJson(value);
});
`
 
**Step 7: Receive a One-to-one Message**

Use the callbackListeners method to receive a message from another user. This function will be triggered every time a user receives a message.
`Mirrorfly.onMessageReceived.listen(result){
  // you will get the new messages
  var chatMessage = sendMessageModelFromJson(result)
}
`
**Integrate Call SDKs**

To integrate call SDKs with your Flutter app, **repeat the similar steps from Step 1 - Step 5** with a minor change in **Step 2: Creating iOS Dependencies**.

**Creating iOS Dependency**

Add the following code at the end of your ios/podfile
`post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.1'
      config.build_settings['ENABLE_BITCODE'] = 'NO'
      config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No'
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
      config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"      
     end
  end
end
`
Now disable the bitcode for your project
`Goto Project -> Build Settings -> Filter the term `Bitcode` -> and select No from the dropdow
`
Now, you can enable all the below mentioned capabilities in your project.
`Goto Project -> Target -> Signing & Capabilities -> Click + at the top left corner -> Search for the capabilities below`

**Conditions and Notes**

Note: From Android 12, ensure that android.permission.BLUETOOTH_CONNECT and android.permission  READ_PHONE_STATE runtime permissions are granted for your app for seamless audio routing and GSM call handling. 

**Caution 1:** If the android.permission.BLUETOOTH_CONNECTpermission is not granted, call audio will not be routed to BT Headset even though it is connected.

**Caution 2:** If the android.permission.  READ_PHONE_STATE permission is not granted; gsm call related functionalities will not work in SDK.

Note: From Android 13, CallSDK needs the below permission to show ongoing call notifications.
`Manifest.permission.POST_NOTIFICATIONS`

**Caution:** To make and receive a voice/video call, microphone and camera usage permissions were required. Make Sure those permissions are granted

After initiating the previous steps as mentioned in Step 1 - Step 5 follow the below mentioned steps to make use of call SDKs.

### Step 1: Make a Voice Call

Run the below method to make a one-to-one voice call
`Mirrorfly.makeVoiceCall(USER_JID).then((response) {
    if (response) {
      
    }
    }).catchError((e) {
      debugPrint("#Mirrorfly Call Exception $e");
});
`
### Step 2: Receive a Call
The Call SDK will take care of receiving and processing the received call payload and triggering the CallKit for iOS and Incoming Call Intent for Android if you are connected to the server in foreground state. 

Once the call is presented with the Accept/Reject Call buttons, we can either choose to attend or reject the call. If we attend the call, the below event listener onCallStatusUpdated will be triggered, and the status will be of the case Attended.
`Mirrorfly.onCallStatusUpdated.listen((event) {
  var statusUpdateReceived = jsonDecode(event);
  var callMode = statusUpdateReceived["callMode"].toString();
  var userJid = statusUpdateReceived["userJid"].toString();
  var callType = statusUpdateReceived["callType"].toString();
  var callStatus = statusUpdateReceived["callStatus"].toString();
});
`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/khnrdoonp623rqtehej2.png)

**Adding Features**
Now let’s add few more features into our chat and call SDKs

**Push Notifications**
Lets add push notifications to flutter app using firebase integrations

### Step 1: Integrate Firebase to the Application

1. Create project in the **[Firebase console](https://console.firebase.google.com/u/0/?pli=1)** using your app package name. Ex: com.testapp
2. Download the automatically generated files **google-service.json** and **GoogleService-Info.plist**
3. Now add **google-service.json** file to your **android/app** folder
4. Then add **GoogleService-Info.plist** file to your **iOS/Runner** folder
5. Now add the firebase dependencies in the **pubspec.yaml** file
`dependencies:
  firebase_core: ^latest_version
  firebase_messaging: ^latest_version
`
6.Finally, run flutter pub get to install the dependencies

### Step 2: Initialize Firebase in your App
Initialize firebase in the main function of your main.dart file

`void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}
`
Configure FCM in your app
`void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  //Configuring FCM to Handle Incoming Messages
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());
}

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // Handle background messages
  
  // If you're going to use other Firebase services in the background, such as Firestore,
  // make sure you call `initializeApp` before using other Firebase services.
  await Firebase.initializeApp();
  // We are checking the Platform Condition here, because we are handling the push notification in iOS via Notification Extension
  if (Platform.isAndroid) {
    //Handle the push notification as given below
    onMessage(message);
  }
}

`

### Step 3: Handle Notifications

When you get a Firebase push notification in your Firebase Messaging service, you can utilize this method to get the content of the message before creating and displaying it:

`static void onMessage(RemoteMessage message) {
  WidgetsFlutterBinding.ensureInitialized();
  
  await Mirrorfly.handleReceivedMessage(notificationData).then((value) async {
    var data = chatMessageFromJson(value.toString());
    if(data.messageId!=null) {
      //Create and Display the Notification
    }
  });
}

`

> Note: For push notifications in iOS, certain limitations exist when the app is in the terminated or background state. Therefore, we utilize the Notification Service Extension to handle these push notifications.

### Step 4: Additional Configuration for iOS

To enable push notifications on iOS, a certain configuration is needed. To make sure that push notifications are received in the background and in the terminated state, this involves adding specific parameters and a notification extension.

Note: Please upload your APNS and VoIP certificates to our [console](https://console.mirrorfly.com/). To learn more how to generate and upload APNS and VOIP certificates, [Click Here](https://www.mirrorfly.com/docs/chat/ios/v3/create_notification)

### Step 5: Capabilities

To receive push notifications in the background or unused state, enable the below capabilities.

Note: Add the “Push Notifications” capability to your project. This can be done via the "Capability" option on the "Signing & Capabilities" tab:

Click on the “+ Capabilities” button
Search “Push Notifications.”

Note: The “Background modes” capability need to be enabled, along with both the “Background fetch” and “Remote notifications” sub-modes.

Click on the “+Capabilities” button
Search “Background Modes.”
Now ensure that both “Background fetch” and “Remote notifications” sub-modes are enabled:

### Step 6: Add Group ID

It is necessary to activate the app group container ID in order to receive messages in the background or when the app is ended.

To access user settings and the database in the container, you must enable app grouping in order to access data between the app and the notification extension.

### Step 7: Notification Extension

The SDK requires you to include the Notification Extension service in your project in order to receive push notifications in the background and in the Killed state.

1.Open the iOS folder in Xcode to create the NotificationExtension Target.
`In  Xcode -> File -> New -> Target -> ' NotificationServiceExtension' -> Next -> TargetName -> Activate Scheme`

2.Include the **Mirrorfly Plugin** and **Firebase Messaging** in the newly formed NotificationExtension target in the **podfile**.
`target 'NotificationExtension' do
  use_frameworks!
    pod 'Firebase/Messaging'
    pod 'mirrorfly_plugin', :path => '.symlinks/plugins/mirrorfly_plugin/ios'
end
`
3.Do **pod install** from **Terminal** inside the **iOS** folder.
4.Open the **Notification Extension** File and import the Mirrorfly Plugin.
`import mirrorfly_plugin
`
5.Add the following code to the notification extension file's didReceive method: This code will handle the incoming push notifications.
`override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        MirrorFlyNotification().handleNotification(notificationRequest: request, contentHandler: contentHandler, containerID: APPGROUPS, licenseKey: LICENSEKEY)
        
    }
`
### Step 8: Requesting Permission
A straightforward API for seeking authorization through the requestPermission method is offered by the firebase_messaging package.

`FirebaseMessaging messaging = FirebaseMessaging.instance;

NotificationSettings settings = await messaging.requestPermission(
  alert: true,
  announcement: false,
  badge: true,
  carPlay: false,
  criticalAlert: false,
  provisional: true,
  sound: true,
);

print('User granted permission: ${settings.authorizationStatus}');
`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pwtfvakm4cnh2fzukul3.png)

Note: On Android, authorization status will return authorized if the user has not disabled notifications for the app via the operating system settings.

### Step 9: Add Runtime Permissions for Push Notifications

Starting with Android 13 We require the following permissions in order to get notifications:

`<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
`
**Get Last Seen Time of a User**

You can use the technique below to find out the chat user's last seen time.
`Mirrorfly.getUserLastSeenTime(jid).then((String? value) {        
});
`
**Hide Last Seen Time of a User**

Use the following way to see if friends can view your last seen status.
`Mirrorfly.isHideLastSeenEnabled().then((bool? value) {
        
});
`

**Get User/Group profile Details**

You can use the technique below to obtain the chat user's profile information.
`Mirrorfly.getProfileDetails(jid, fetchFromServer).then((value) {
    var data = Profile.fromJson(json.decode(value.toString()));
});
`
**Get Recent Chats**

To retrieve a user's or group's most recent chat.
`var value  = await Mirrorfly.getRecentChatOf(jid);
var data = RecentChatData.fromJson(json.decode(value));
`
**Get Recent chat List**

Use the following procedure to obtain the most recent conversation list:
`Mirrorfly.getRecentChatList().then((value) {
  var data = recentChatFromJson(value);
}).catchError((error) {
  // Error handling
});
`
**Conclusion**

Thank you for investing your time in implementing this tutorial. I hope this tutorial helped you add Flutter in-app communication with [MirrorFly SDKs](https://www.mirrorfly.com/flutter-chat-sdk.php) to your app.

If you still have any queries, you can get in touch with our tech support team for immediate solutions, or in order to add more chat and call features, you can have a look at our [documentation page](https://www.mirrorfly.com/docs/chat/flutter-plugin/feature-common/).

You can also find [Flutter UIKit](https://www.mirrorfly.com/docs/uikit/flutter/quick-start/) to plug and-play chat features in your app on any platform. Good luck with your search. See you soon. Bye.