# In-App Messaging in Flutter with Freshchat

Freshchat provides a live chat feature on Web, Mobile and social media platforms like Whatsapp, Facebook Messenger, Slack, Spotify etc. It helps in connecting users on different platforms, engage them by helping them interact with each other and hence develop business. 

Freshchat has some outstanding features. With Freshchat, one can: 

- Send in-app messages.
- Set up email campaigns
- Set user segments and target messages based on specific business logic
- Push Notification services
- Multi-channel messaging
    and much more..


In this article, we are going to explore **in-app messaging + push notification** features of Freshchat, which is an important feature in almost every mobile apps nowadays.😀

### Prerequisite Knowledge

 This article assumes that the reader has basic working knowledge of Android + iOS development in **Flutter** along with basic knowledge of the **Dart** language.

## Installation

In order to integrate Freshchat plugin in our project:

1. Add `flutter_freshchat` dependency to the project's `pubspec.yaml` file:

```dart
dependencies:
  flutter_freshchat: ^1.4.0
```

2. Install it through the command line using the following command:

```dart
$ flutter pub get
```

3. Import the Freshchat package and use in your project through:

```dart
import 'package:flutter_freshchat/flutter_freshchat.dart';
```

### Android Integration

To set up Firebase Cloud Messaging (FCM) in your app, please follow this [link](https://pub.dev/packages/firebase_messaging)

- To handle background messages, add the `com.github.freshdesk:freshchat-android` dependency in your app-level `build.gradle` file that is located at `<app-name>/android/app/build.gradle`:

```dart
dependencies {
		// your other dependency plugins
    implementation 'com.github.freshdesk:freshchat-android:3.3.0'
  }
```

To handle remote messages sent by Freshchat via FCM when app is in background mode, add:

```
dart
<service android:name=".FcmMessageService"
         android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

```

Create a class `FcmMessageService` which handles the remote message inside `FreshchatMessagingService.kt` file that is located at `<app-name>/android/app/src/main/kotlin`.

```
dart
package <your package's identifier>

import com.freshchat.consumer.sdk.Freshchat;
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class FcmMessageService : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
       if (Freshchat.isFreshchatNotification(remoteMessage)) {
            Freshchat.handleFcmMessage(this, remoteMessage);
        }  
    }
}
```

For java, create a`FreshchatMessagingService.java` file located at `<app-name>/android/app/src/main/java`:

```
package <your package's identifier>;

import com.freshchat.consumer.sdk.Freshchat;
import com.google.firebase.messaging.RemoteMessage;
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;

public class FcmMessageService extends FirebaseMessagingService {

    @Overridepublic void onNewToken(String token) {
        super.onNewToken(token);
    }

    @Overridepublic void onMessageReceived(final RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        if (Freshchat.isFreshchatNotification(remoteMessage)) {
            Freshchat.handleFcmMessage(this, remoteMessage);
        }
    }
}
```

>Since Freshchat does not provide a default FileProvider, add the following to your `AndroidManifest.xml` file that is located at `<app-name>/android/app/src/main/AndroidManifest.xml`   for secure sharing of files and to grant temporary access to the files that Freshchat requires:

```dart
<manifest>
    ...
    <application>
        ...
          <provider
             android:name="android.support.v4.content.FileProvider"
             android:authorities="com.example.demoapp.provider"
             android:exported="false"
             android:grantUriPermissions="true">
               <meta-data
                  android:name="android.support.FILE_PROVIDER_PATHS"
                  android:resource="@xml/freshchat_file_provider_paths" />
           </provider>
        ...
    </application>
</manifest>

```

For those who have migrated projects to **androidX**,  replace line 
`android:name="android.support.v4.content.FileProvider"` with `android:name="androidx.core.content.FileProvider"`

- To define the resource used by the `FileProvider`, add this to the `strings.xml` file that is located at 
`<app-name>/android/app/src/main/res/values/strings.xml`:

```dart
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="freshchat_file_provider_authority">com.example.demoapp.provider</string>
</resources>
```

## iOS Integration

To allow your app to access Photos and Camera of a phone running iOS, it is mandatory to provide  these additional access permissions. Add the following to the`info.plist` file located at `<app-name>/ios/Runner/info.plist`:

```dart
    <key>NSPhotoLibraryUsageDescription</key>
    <string>To Enable access to Photo Library</string>
    <key>NSCameraUsageDescription</key>
    <string>To take Images from Camera</string>
```
After adding this, the user will be prompted with a dialog box asking for an "Allow" and "Don't Allow" input.

This completes the installation and set up process for the Freshchat plugin.

We shall now see how to use the Freshchat API's and a few use cases. 

### Using Freshchat

First, initialise the Freshchat plugin for the app in `main.dart` with the code below:

```dart
import 'package:flutter_freshchat/flutter_freshchat.dart';

await FlutterFreshchat.init(
            appID: "your App ID here",
            appKey: "your App Key here",
            domain: "your domain here"
)
```

You can find the **AppId**, **AppKey** and domain here in the Freshchat dashboard.


![Screenshot_2020-12-29_at_1.01.03_PM.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1610546967791/hhiwT1_ym.jpeg)

Also, send the fcmToken to Freshchat and add this method to the place where you are fetching your Firebase's token.

```dart
 await FlutterFreshchat.setupPushNotifications(token: fcmToken)
```

**iOS push Notification** 

To set up the push Notifications for iOS, upload `p.12` file of your project, its `password` and `bundleId` of your project


![Screenshot_2020-12-29_at_1.01.39_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610547006238/GMym4aBT1.png)

**Android Push Notification**

To set up the push Notifications for Android, add the **FCM Server key** of your project which firebase provides, here:


![Screenshot_2020-12-29_at_1.01.49_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610547030996/iOrwgxkxg.png)



### Users and Conversations

- **Create/Register** a user in Freshchat

```dart
//creating a new user
FreshchatUser user = FreshchatUser.initial();
user.email = "test.com";
user.firstName = "test";
user.lastName = "user";
user.phoneCountryCode = "+91";
user.phone = "0123456789";

await FlutterFreshchat.updateUserInfo(user: user);

// Custom properties can also be included
Map<String, String> customProperties = Map<String, String>();
customProperties["loggedIn"] = "true";
customProperties["companyName"] = "company";
customProperties["userCategory"] = "admin";

await FlutterFreshchat.updateUserInfo(user: user, customProperties: customProperties);
```

- **Show conversation** opens the conversation screen. One can set the title for the chat screen and can reply to the conversation like shown in the attachment.

```dart
await FlutterFreshchat.showConversations(tags: const [], title: 'CHAT_SCREEN_TITLE');
```

![Screenshot_2020-12-31_at_5.18.08_PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1610547074753/Qk-WJhqEG.png)

- To **restore the chats**, `restoreID` is required. Do note that `restoreID` returns a value only once a conversation is initiated. Which means that for the first time, `restoreID` will be null.

```dart
int restoreId = await FlutterFreshchat.identifyUser(externalID: 'UNIQUE_ID', restoreID: 'RESTORE_ID');
```
where, `externalID` is the one which (email/userId) you want to uniquely identify the user with. The above call returns the `restoreID`.

- **To get the unread message count**

```dart
int unReadMessageCount = await FlutterFreshchat.getUnreadMsgCount();
```

![Screenshot_2020-12-29_at_1.00.35_PM.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1610547097079/z4WBCRoZR.jpeg)


### Common Issues

These are the issues which you might face repeatedly while running Freshchat on an iOS app and you can waste a lot of time while trying resolving them.

- If you face any issues while running the iOS app, run the following:

```
cd /ios
rm Podfile.lock
pod install --repo-update
flutter clean
```

- Swift compiler errors which says:
**`include of non-modular header inside framework module 'flutter_freshchat.FlutterFreshchatPlugin' 
 Objective-c module errors`**

    To fix them,

    - Open your iOS folder in xcode.
    - Open the `pods` folder present on the left side, just below the Runner.
    - Click on the `freshchatSDK` folder inside the pods folder and click on the `freshchatSDK.h` file.
    - Press **cmd+options+0** for the right side pane to find the target membership frameworks.
    - Select the **flutter_freshchat** framwork and also **make it public** (present on the right side).

 Now, again run the project and everything will work as expected!

By making the header file (.h) to be public, swift compiler can easily compile the code written in Objective C language.

>**Please Note:** Manually set up the target of the `freshchatSDK.h` when you switch or rebuild the xcode project. It seems like there is still an [open issue](https://github.com/fayeed/flutter_freshchat/issues/52) on automating this.

### **Few takeaways (Tips)** 😀

When you encounter any errors/issues in the middle of using the package:

- From my experience, it is better to first look into the **open and closed issues** of the package by visiting View/report issues link . This saves a lot of time in figuring out the solution and also helps one in taking the community's help for a particular package.
- Don’t get overwhelmed by the installation procedures put up by multiple articles at once, simply follow one at a time

**Happy chatting !!😄**
