Source: https://fyno.docs.pageloop.ai/sd-ks/in-app/flutter

# Flutter In-App SDK

Fyno's Flutter InApp SDK offers a comprehensive set of notification features within your app. It's designed to efficiently deliver messages, ensuring optimal performance and user experience.

> ## Important Note:
>
> - Web support has been added to the Flutter In-App SDK starting from version 1.2.0. From this version onwards, the SDK can be easily integrated and used in Flutter Web applications in addition to mobile platforms.
> - If you are developing for the web, please ensure that your project is using Flutter In-App SDK v1.2.0 or later to access and benefit from web compatibility. Web-based implementations are only supported in newer SDK versions; projects using earlier versions do not have this capability.

## Installation

Install the package by using one of the following commands.

#### Dart

```bash title="Dart" wordWrap
dart pub add fyno_flutter_inapp
```

#### Flutter

```bash title="Flutter" wordWrap
flutter pub add fyno_flutter_inapp
```

This will add a line like this to your package's `pubspec.yaml` (and run an implicit `dart/flutter pub get`):

```yaml title="pubspec.yaml" wordWrap
dependencies:
  fyno_flutter_inapp: <latest_version>
```

Alternatively, your editor might support `dart/flutter pub get`. Check the docs for your editor to learn more.

## Usage

Before you dive into using the In-App Notification Center, there are some prerequisites you need to fulfill. You must ensure you have the necessary information and generate an HMAC signature.

### Prerequisites

Before you start, make sure you have the following information ready

- **Workspace ID (WSID)**: You can find your workspace ID on your Fyno App > [API Keys](https://app.fyno.io/settings#api-keys) page.
- **Integration Token**: Obtain the integration token from the Fyno App > [Integrations](https://app.fyno.io/integrations) page.
- **User ID**: This should be a unique identifier for the currently logged-in user. This user ID is crucial for Fyno to send specific notifications to the right users.

### HMAC Signature Generation

The HMAC signature is essential for ensuring the security and integrity of your notifications. Here is an example of how to generate the HMAC signature in various programming languages.

#### Dart

```dart title="Dart" wordWrap
import 'dart:convert';
import 'package:crypto/crypto.dart';

void main() {
  String signature = Hmac(sha256, utf8.encode(workspaceId + integrationToken))
      .convert(utf8.encode(userId))
      .toString();
}

```

#### Node

```js title="Node" wordWrap
import crypto from 'crypto'; //module
//or
// const crypto = require('crypto') //commonjs
const signature = crypto
  .createHmac('sha256', 'WSID' + 'INTEGRATION_TOKEN')
  .update('USER_ID')
  .digest('hex');
```

#### JavaScript

```js title="JavaScript" wordWrap
const CryptoJS = require('crypto-js'); //commonjs
//or
//import CryptoJS from "crypto-js";//module
const secretKey = 'WSID' + 'INTEGRATION_TOKEN';
const userId = 'USER_ID';

const signature = CryptoJS.HmacSHA256(userId, secretKey).toString(CryptoJS.enc.Hex);
```

#### Python

```python title="Python" wordWrap
import hashlib
import hmac

secret_key = b'WSID'+b'INTEGRATION_TOKEN'
user_id = 'USER_ID'

signature = hmac.new(secret_key, user_id.encode('utf-8'), hashlib.sha256).hexdigest()
```

#### Java

```java title="Java" wordWrap
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class SignatureExample {

    public static void main(String[] args) throws Exception {
        String secretKey = "WSID" + "INTEGRATION_TOKEN"; // Concatenate the secret key
        String userId = "USER_ID";

        // Create a new instance of the HmacSHA256 algorithm
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(secretKeySpec);

        // Compute the hash
        byte[] hash = mac.doFinal(userId.getBytes(StandardCharsets.UTF_8));

        // Convert the hash to a hexadecimal string
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            String hex = String.format("%02x", b);
            hexString.append(hex);
        }

        String signature = hexString.toString();
    }

}

```

#### Go

```go title="Go" wordWrap
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
)

func main() {
	secretKey := "WSID"+"INTEGRATION_TOKEN"
	userId := "USER_ID"

	key := []byte(secretKey)
	data := []byte(userId)

	// Create an HMAC-SHA256 hasher
	hasher := hmac.New(sha256.New, key)

	// Write the data to the hasher
	_, err := hasher.Write(data)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// Get the resulting hash as bytes
	hash := hasher.Sum(nil)

	// Convert the hash to a hexadecimal string
	signature := hex.EncodeToString(hash)
}
```

#### PHP

```php title="PHP" wordWrap
$secretKey = 'WSID'.'INTEGRATION_TOKEN';
$userId = 'USER_ID';

$signature = hash_hmac('sha256', $userId, $secretKey);
```

#### Ruby

```ruby title="Ruby" wordWrap
require 'openssl'

secret_key = 'WSID'+'INTEGRATION_TOKEN'
user_id = 'USER_ID'

signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, user_id)
```

#### C\#

```csharp title="C#" wordWrap
using System;
using System.Security.Cryptography;
using System.Text;

class Program
{
    static void Main()
    {
        string secretKey = "WSIDINTEGRATION_TOKEN";
        string userId = "USER_ID";

        using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey))
        {
            byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(userId));
            string signature = BitConverter.ToString(hash).Replace("-", "").ToLower();
        }
    }
}
```

> [!WARNING]
>
> **Watch out when generating HMAC Signatures!**
>
> Avoid generating the signature in the frontend, as it can expose your Integration token. Always generate the token securely in the backend or middleware.

### SDK Initialisation

Import the package in your Dart file:

```dart title="dart" wordWrap
import 'package:fyno_flutter_inapp/fyno_flutter_inapp.dart';
```

To use the SDK in your Flutter application, initialise the SDK as follows:

```dart title="dart" wordWrap
final FynoInApp fynoInApp = FynoInApp();

//Web Socket connection
fynoInApp.fynoInAppSocketConnect(
  workspaceId,
  integrationId,
  userId,
  origin,
  signature,
);
```

### Reset SDK

To reset the Inapp SDK, typically during logout, call the `fynoInapp.reset()` function.

```dart title="dart" wordWrap
fynoInApp.reset();
```

### In-App UI

There are 3 ways you can configure the InApp UI.

1. Fyno UI
2. Fyno Customisable UI
3. Your own UI

#### Fyno UI

```dart title="dart" wordWrap
fynoInApp.getFynoNotificationIconButton(
  context,
  <icon_color>,
),
```

#### Fyno Customisable UI

To customise the Fyno UI, you can pass the notification icon and colours you would like to use for the inapp notification inbox.

As of now, you can only change notification icon to any of the built in icons.

You can do the customisation as follows:

```dart title="dart" wordWrap
fynoInApp.getFynoNotificationIconButton(
    context,
    <icon_color>,
    notificationIcon: <notification_icon>,
    themeConfig: ThemeConfig(
        lightBackground: <light_background>,
        darkBackground: <dark_background>,
        lightText: <light_text>,
        darkText: <dark_text>,
        primary: <primary>,
    ),
)
```

- **lightBackground** (optional) - The background color in light mode
- **darkBackground** (optional) - The background color in dark mode
- **lightText** (optional) - The text color in light mode
- **darkText** (optional) - The text color in dark mode
- **primary** (optional) - The background color of primary buttons (if any) in the notification

#### Your own UI

You have the flexibility to build your own UI. Additionally, you can personalise the icons for actions like 'Read all' and 'Delete all' with your own custom designs. If you are going to use this approach, it is necessary to invoke the following functions.

#### Count of all InApp notifications (Both read and unread)

```js title="dart" wordWrap
fynoInApp.fynoInAppState.count;
```

#### Count of unread InApp notifications

```js title="dart" wordWrap
fynoInApp.fynoInAppState.unreadCount
```

#### List of all InApp notifications (Both read and unread)

```js title="dart" wordWrap
fynoInApp.fynoInAppState.list
```

#### List of unread InApp notifications

```js title="dart" wordWrap
fynoInApp.fynoInAppState.unreadList
```

#### Current page number

```js title="dart" wordWrap
fynoInApp.fynoInAppState.page
```

#### To mark all InApp notifications as Read

```js title="dart" wordWrap
fynoInApp.markAllAsRead()
```

#### To delete all InApp notifications

```js title="dart" wordWrap
fynoInApp.deleteAllMessages()
```

#### To mark a single InApp notifications as Read

```js title="dart" wordWrap
fynoInApp.markAsRead(notification)
// pass one of the items from the list: fynoInApp.fynoInAppState.list
```

#### To delete a single InApp notification

```js title="dart" wordWrap
fynoInApp.deleteMessage(notification)
// pass one of the items from the list: fynoInApp.fynoInAppState.list
```

#### To load more notifications (based on pagination)

```js title="dart" wordWrap
fynoInApp.loadMoreNotifications(page, type)
// type -> 'all' or 'unread', page should be greater than zero
```
