# MPush Documentation

{% content-ref url="/pages/-MHRWd2BA6aqIm7Gyehl" %}
[ API](/api)
{% endcontent-ref %}

{% content-ref url="/pages/-MHRZAh2YkSQZ4ywL2fK" %}
[  iOS SDK](/ios-sdk)
{% endcontent-ref %}

{% content-ref url="/pages/-MHRZB3GKJ7Kyxt1I4df" %}
[ Android SDK](/android-sdk)
{% endcontent-ref %}

{% content-ref url="/pages/-ML7YSGO29st6dcEAT7C" %}
[Flutter SDK](/flutter-sdk)
{% endcontent-ref %}


# &#x20;API


# Introduction

{% hint style="success" %}
This document will help you through MPush API integration.
{% endhint %}

### Getting Started

MPush follows a **Publish/Subscribe** model based on topics to determine which devices receive a notification.

Devices can subscribe to one or more topics. Your backend can then send push notifications to specific topics, and only devices subscribed to at least one of the targeted topics will receive the message.

The MPush API is built on REST principles and uses JSON for both requests and responses. Errors are communicated using standard HTTP status codes and include detailed information in the JSON response body.

To simplify mobile integration, open-source SDKs are available for both [iOS](https://github.com/Mumble-SRL/MPush-iOS) and [Android](https://github.com/Mumble-SRL/MPush-Android). Refer to the iOS and Android documentation for implementation details.

Before getting started, make sure you have an API authentication token. It is required for every API call, as described in [Authentication](/api/authentication). To request a token, please send an email [here](mailto:developers@shoppy.is?subject=MPush%20Auth%20Token).


# Authentication

{% hint style="info" %}
MPush uses some HTTP headers to handle requests. In particular, are used to authenticate and to know which kind of data should expect from the client and vice versa.
{% endhint %}

All used headers are shown in the below table, but they can change based on which API you are calling.

| Header          | Description                                                          |
| --------------- | -------------------------------------------------------------------- |
| Accept          | Should always be `application/json`.                                 |
| Content-Type    | Should always be `application/json`.                                 |
| X-MPush-Token   | Contains the token to authenticate every API call.                   |
| X-MPush-Version | Define the API version you want to use. The minimum and actual is 2. |

### Errors <a href="#errors" id="errors"></a>

MBurger APIs uses the following HTTP error codes:

| Code | Meaning               | Description                                                        |
| ---- | --------------------- | ------------------------------------------------------------------ |
| 400  | Bad Request           | Your request is invalid.                                           |
| 401  | Unauthorized          | Your API key is wrong or not present.                              |
| 403  | Forbidden             | You don't have permission to access this resource.                 |
| 404  | Not Found             | The requested resource can not be found.                           |
| 405  | Method Not Allowed    | You tried to use an invalid method.                                |
| 406  | Not Acceptable        | You requested a format that isn't json.                            |
| 422  | Unprocessable Entity  | You requested did not pass the input validation.                   |
| 429  | Too Many Requests     | You're requesting too many! Slow down!                             |
| 500  | Internal Server Error | We had a problem with our server. Try again later.                 |
| 503  | Service Unavailable   | We're temporarily offline for maintenance. Please try again later. |

Below are reported some examples of them:

On authentication error is returned an HTTP 401 and a JSON like this:

```php
{
  "message": "The project token is not present."
}
```

On permission error is returned an HTTP 403 and a JSON like this:

```php
{
  "message": "This action is unauthorized."
}
```

On validation error is returned an HTTP 422 and a JSON like this:

```php
{
  "message": "The given data was invalid.",
  "errors": {
    "email": [
      "The token field is required."
    ]
  }
}
```


# Send Notifications

{% hint style="success" %}
This section describes API to send push notifications.
{% endhint %}

### Send Push <a href="#send-push" id="send-push"></a>

To send push notifications.

On success, the endpoint confirms that the notification has been queued and delivery has started. To check the delivery status, use the `notificationId` from the response with [Send Notifications](/api/send-notifications#send-push-1) endpoint.

#### Endpoint <a href="#http-request" id="http-request"></a>

`POST https://app.mpush.cloud/api/send`

#### Parameters (JSON) <a href="#parameters-json" id="parameters-json"></a>

| Key                        | Type   | Required | Description                                                                                                                 |
| -------------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| topics                     | array  | Yes      | Contains a list of all topics to send the push to.                                                                          |
| payload.title              | string | No       | Notification title.                                                                                                         |
| payload.body               | string | Yes      | Notification body.                                                                                                          |
| payload.badge              | int    | No       | Badge number.                                                                                                               |
| payload.sound              | string | No       | Specify the sound path to play when the push arrives.                                                                       |
| payload.title\_loc\_key    | string | No       | Specify the key to a *body* string in a localization file for the current locale.                                           |
| payload.title\_loc\_args   | array  | No       | Specify the values to appear in place of the format specifiers in `title_loc_key`.                                          |
| payload.loc\_key           | string | No       | Specify the key to a *title* string in a localization file for the current locale.                                          |
| payload.loc\_args          | array  | No       | Specify the values to appear in place of the format specifiers in `loc_key`.                                                |
| payload.action\_loc\_key   | string | No       | Custom sound to play.                                                                                                       |
| payload.launch\_image      | string | No       | Specify the image path to launch at the app launch.                                                                         |
| payload.mutable\_content   | bool   | No       | Mutable content (**only iOS**).                                                                                             |
| payload.content\_available | bool   | No       | Content available (**only iOS**).                                                                                           |
| payload.category           | string | No       | Specify a category (**only iOS**).                                                                                          |
| payload.thread\_id         | int    | No       | Specify a thread (**only iOS**).                                                                                            |
| payload.collapse\_id       | int    | No       | Multiple notifications with the same collapse identifier are displayed to the user as a single notification (**only iOS**). |
| payload.expiration\_at     | int    | No       | A UNIX timestamp (UTC) that identifies the date when the notification is no longer valid and can be discarded.              |
| payload.custom             | object | No       | An object containing custom data.                                                                                           |

This table is used the "dot" notation to show the payload JSON structure.

For a complete reference to all available values to include in the payload we remand to the official documentation: [iOS](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1) and [Android](https://firebase.google.com/docs/cloud-messaging/server).

#### Example <a href="#http-request" id="http-request"></a>

This API requires a **JSON payload**.

```php
curl https://app.mpush.cloud/api/send
-X POST 
-H "Accept: application/json" 
-H "Content-Type: application/json" 
-H "X-MPush-Token: <token>" 
-H "X-MPush-Token: 2" 
-d '<JSON payload>' 
```

On success is returned an HTTP 200 and JSON like this:

```php
{
  "notificationId": "18f7c750-5cde-4900-84db-2a863afebb91",
  "status": "accepted",
  "message": "Notification queued for processing"
}
```

#### Payload examples <a href="#examples" id="examples"></a>

Payload example to send a basic notification:

```php
{
  "topics": ["all"],
  "payload": {
    "body": "Hello"
  }
}
```

Payload example to send a basic notification to multiple topics with custom badge and sound:

```php
{
  "topics": ["news", "user.12", "user.15"],
  "payload": {
    "title": "News!",
    "body": "Hello",
    "badge": 2,
    "sound": "sound.aiff"
  }
}
```

Payload example to send a notification with an image:

```php
{
  "topics": ["project.all"],
  "payload": {
    "body": "Message with Image",
    "mutable_content": 1,
    "custom": {
      "media_url": "https://link-to-image.com"
    }
  }
}
```

Payload example to send a notification with localization:

```php
{
  "topics": ["user.23"],
  "payload": {
    "loc_key": "LOCALIZED_PUSH",
    "loc_args": [
      "Name",
      "Surname"
    ]
  }
}
```

### Notification Status <a href="#send-push" id="send-push"></a>

To retrieve the sending status.

When the `status` value becomes `completed`, it means the system has finished sending the notification.

#### Endpoint <a href="#http-request" id="http-request"></a>

`GET https://app.mpush.cloud/api/notifications/<notificationId>`

#### Example:

```php
curl https://app.mpush.cloud/api/notifications/<notificationId>
-H "Accept: application/json" 
-H "X-MPush-Token: <token>" 
-H "X-MPush-Token: 2"
```

On success is returned an HTTP 200 and JSON like this:

```php
{
  "projectId": 1,
  "failedCount": 10,
  "status": "completed",
  "createdAt": 1764100807728,
  "priority": "normal",
  "totalDevices": 1064,
  "topics": [
    "project.all"
  ],
  "notification": {
    "badge": 1,
    "title": "Title",
    "body": "Message"
  },
  "completedAt": 1764100816175,
  "sentCount": 1054,
  "iosCount": 736,
  "updatedAt": 1764100816141,
  "androidCount": 328,
  "id": "18f7c750-5cde-4900-84db-2a863afebb91"
}
```


# Topics

{% hint style="info" %}
This section describes APIs to add devices to MPush and associate them with topics. Only clients (e.g. apps) should implement these APIs or use mobile SDKs.
{% endhint %}

### Add Device <a href="#add-device" id="add-device"></a>

```php
curl https://app.mpush.cloud/api/tokens
-X POST
-H "Accept: application/json" 
-H "Content-Type: application/json"
-H "X-MPush-Token: <token>" 
-H "X-MPush-Version: 2"
-d <data>
```

To register a new device token.

This API requires a **JSON payload**.

#### HTTP Request <a href="#http-request" id="http-request"></a>

`POST https://app.mpush.cloud/api/tokens`

Payload example to register a device to 3 topics:

```php
{
  "token": "<token>",
  "platform": "ios",
  "device_id": "<device ID>"
}
```

#### Parameters <a href="#parameters" id="parameters"></a>

| Name       | Type   | Required | Description                                                                      |
| ---------- | ------ | -------- | -------------------------------------------------------------------------------- |
| token      | string | Yes      | Specify token device obtained from APNS and FCM.                                 |
| platform   | string | Yes      | Specify the device platform. Values are *ios* and *android*.                     |
| device\_id | string | Yes      | Specify the unique device ID. It's used to update the *token* in case of change. |

On success is returned an HTTP 200 and JSON like this:

```php
{
  "status_code": 0
}
```

### Register <a href="#register" id="register"></a>

```php
curl https://app.mpush.cloud/api/register
-X POST
-H "Accept: application/json" 
-H "Content-Type: application/json"
-H "X-MPush-Token: <token>" 
-H "X-MPush-Version: 2"
-d '<JSON payload>' 
```

To register a device to one or more topics.

A topic can represent either a device or a list of devices, you can specify it through the`single`parameter. If the specified topic doesn't exist it will be created.

This API requires a **JSON payload**.

#### HTTP Request <a href="#http-request_1" id="http-request_1"></a>

`POST https://app.mpush.cloud/api/register`

Payload example to register a device to 3 topics:

```php
{
  "topics": [
    {
      "code": "all",
      "title": "All Users",
      "single": false,
    },
    {
      "code": "ios",
      "title": "iOS Users",
      "single": false,
    },
    {
      "code": "user.1",
      "title": "User 1",
      "single": true,
    },
  ],
  "device_id": "<device ID>"
}
```

#### Parameters (JSON) <a href="#parameters-json" id="parameters-json"></a>

| Key        | Type   | Required | Description                                              |
| ---------- | ------ | -------- | -------------------------------------------------------- |
| topics     | array  | Yes      | Contains a list of all topics to register the device to. |
| device\_id | string | Yes      | Specify the unique device ID.                            |

On success is returned an HTTP 200 and JSON like this:

```php
{
  "status_code": 0
}
```

### Unregister <a href="#unregister" id="unregister"></a>

```php
curl https://app.mpush.cloud/api/unregister
-X POST
-H "Accept: application/json" 
-H "Content-Type: application/json"
-H "X-MPush-Token: <token>" 
-H "X-MPush-Version: 2"
-d '<JSON payload>' 
```

To unregister a device from one or more topics.

If the specified topic doesn't exist it will be ignored.

This API requires a **JSON payload**.

#### HTTP Request <a href="#http-request_2" id="http-request_2"></a>

`POST https://app.mpush.cloud/api/unregister`

Payload example to unregister a device from 2 topics (old version):

```php
{
  "topics": ["all", "ios"],
  "device_id": "<device ID>"
}
```

Payload example to unregister a device from 2 topics (new version):

```php
{
  "topics": [
    {
      "code": "all",
    },
    {
      "code": "ios",
    }
  ],
  "device_id": "<device ID>"
}
```

#### Parameters (JSON) <a href="#parameters-json_1" id="parameters-json_1"></a>

| Key        | Type   | Required | Description                                              |
| ---------- | ------ | -------- | -------------------------------------------------------- |
| topics     | array  | Yes      | Contains a list of all topics to register the device to. |
| device\_id | string | Yes      | Specify the unique device ID.                            |

On success is returned an HTTP 200 and JSON like this:

```php
{
  "status_code": 0
}
```

### Unregister All <a href="#unregister-all" id="unregister-all"></a>

```php
curl https://app.mpush.cloud/api/unregister-all
-X POST
-H "Accept: application/json" 
-H "Content-Type: application/json"
-H "X-MPush-Token: <token>" 
-H "X-MPush-Version: 2"
-d '<JSON payload>' 
```

To unregister a device from all topics.

This API requires a **JSON payload**.

#### HTTP Request <a href="#http-request_3" id="http-request_3"></a>

`POST https://app.mpush.cloud/api/unregister-all`

Payload example to unregister a device from all topics:

```php
{
  "device_id": "<device ID>"
}
```

#### Parameters (JSON) <a href="#parameters-json_2" id="parameters-json_2"></a>

| Key        | Type   | Required | Description                   |
| ---------- | ------ | -------- | ----------------------------- |
| device\_id | string | Yes      | Specify the unique device ID. |

On success is returned an HTTP 200 and JSON like this:

```php
{
  "status_code": 0
}
```


# &#x20; iOS SDK


# Introduction

{% hint style="info" %}
MPush is a client library, written in Swift, that can be used to interact with the MPush API. The minimum deployment target for the library is iOS 11.0.
{% endhint %}

MPush uses a classic Pub/Sub pattern, you will register your device to topics, then from the MPush APIs you will be able to send notifications to those topics and all device registered will receive a notification.

A topic can represent whatever you want in your system (e.g. the entire app, a user a subset of user with a common characteristic) so you will be able to choose the granularity of the notifications.

### Minimum Requirements

* [Swift 4.0+](https://github.com/pusher/push-notifications-swift/commit/d6dfa2186195135d8d7d1e3d3efdd7f8661ea404)
* [Xcode](https://itunes.apple.com/us/app/xcode/id497799835) - The easiest way to get Xcode is from the [App Store](https://itunes.apple.com/us/app/xcode/id497799835?mt=12), but you can also download it from [developer.apple.com](https://developer.apple.com/) if you have an AppleID registered with an Apple Developer account.


# Installation

{% tabs %}
{% tab title="CocoaPods" %}
CocoaPods is a dependency manager for iOS, which automates and simplifies the process of using 3rd-party libraries in your projects. You can install CocoaPods with the following command:

```bash
$ gem install cocoapods
```

To integrate the MPush into your Xcode project using CocoaPods, specify it in your Podfile:

```bash
platform :ios, '10.0'

target 'TargetName' do
    use_frameworks!

    pod 'MPushSwift'
end
```

Then, run the following command:

```bash
$ pod install
```

CocoaPods is the preferred method to install the library.
{% endtab %}

{% tab title="Manual" %}
To install the library manually drag and drop the folder `MPush` to your project structure in XCode.

Note that `MPush` has `MBNetworking (1.0)` as a dependency, so you have to install also this library.
{% endtab %}
{% endtabs %}


# Add Push Notification to your app

The first thing you have to do is implement Push Notifications using the [UserNotifications](https://developer.apple.com/documentation/usernotifications) framework.

{% hint style="info" %}
You will be guided through all the steps needed to have a functional project with the push notifications, if you have already done it you can skip to the [Integrate MPush](/ios-sdk/integrate-mpush) section of this README.
{% endhint %}

## Create a key <a href="#create-a-key" id="create-a-key"></a>

Go to [developer.apple.com](https://www.developer.apple.com/) with an admin account and under Keys -> All click the plus button in the top right corner.&#x20;

Specify a name for your key and enable Apple Push Notifications service (APNs).

&#x20;

![Key creation 2](https://docs.mumbleideas.it/mpush/ios/images/Key-creation-2.png)

![Key creation 1](https://docs.mumbleideas.it/mpush/ios/images/Key-creation-1.png)

Then download the .p8 key file created and upload it in our dashboard.

{% hint style="info" %}
Note that the key created is valid for all the apps of your profile and can't be re-downloaded, keep it in a safe place because you will likely have to resue it.
{% endhint %}

## Add notifications to your app <a href="#add-notifications-to-your-app" id="add-notifications-to-your-app"></a>

Now go to your app settings under Identifier -> AppId and enable the notifications services following the steps. After that, you need to update the Provisioning Profile for your app or create a new one because push notifications don't work for applications signed with a wildcard Provisioning Profile.

Now it's finally time to move to XCode. Open your project and enable push notifications in the capabilities tab.

<div align="center"><img src="https://docs.mumbleideas.it/mpush/ios/images/XCode-capabilities.png" alt="XCode-capabilities"></div>

In `AppDelegate.swift` add

```bash
import UserNotifications

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    ...

    let userNotificationCenter = UNUserNotificationCenter.current()
    userNotificationCenter.delegate = self

    self.registerForPushNotifications()
    ...
}

// MARK: - Notifications

func registerForPushNotifications() {
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, _) in
        guard granted else { return }
        self.getNotificationSettings()
    }
}

func getNotificationSettings() {
    UNUserNotificationCenter.current().getNotificationSettings { (settings) in
        guard settings.authorizationStatus == .authorized else { return }
        DispatchQueue.main.async {
            UIApplication.shared.registerForRemoteNotifications()
        }
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler
                                completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler(UNNotificationPresentationOptions.alert)
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler
                                completionHandler: @escaping () -> Void) {
        completionHandler()
    }
}
```


# Integrate MPush

To integrate MPush to your implementation you need to add this in your AppDelegate

```bash
import MPushSwift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    ...
    MPush.token = "YOUR_PUSH_TOKEN"
    ...
}

...

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    MPush.registerDevice(deviceToken: deviceToken, success: {
        MPush.register(toTopic: "YOUR_TOPIC")
        // OR if you have more than one topic
        // MPush.register(toTopics: ["TOPIC1", "TOPIC2"])
    })
}
```

{% hint style="success" %}
You're set 🎉, the device will receive notifications for the topic is registered to.
{% endhint %}


# Rich Notifications

To implement rich notifications you will have to create a new Notification Service Target that will be responsible for downloading the media of the notification and attach it to the notification object.

In Xcode go to File -> New -> Target and choose Notification Service Extension

{% hint style="info" %}
Keep in mind that notifications don't have much time to download the media attached, if the download doesn't finish in a short period of time the notification will be delivered without the media.
{% endhint %}

To handle MPush attachments add this your `NotificationService` should look like this:

```bash
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    self.contentHandler = contentHandler
    bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

    if let bestAttemptContent = bestAttemptContent {
        if let mediaUrl = request.content.userInfo["media_url"] as? String, let fileUrl = URL(string: mediaUrl) {
            downloadMedia(fileUrl: fileUrl, request: request, bestAttemptContent: bestAttemptContent) {
                contentHandler(bestAttemptContent)
            }
        } else {
            contentHandler(bestAttemptContent)
        }
    }
}

func downloadMedia(fileUrl: URL, request: UNNotificationRequest, bestAttemptContent: UNMutableNotificationContent, completion: @escaping () -> Void) {
    let task = URLSession.shared.downloadTask(with: fileUrl) { (location, _, _) in
        if let location = location {
            let tmpDirectory = NSTemporaryDirectory()
            let tmpFile = "file://".appending(tmpDirectory).appending(fileUrl.lastPathComponent)
            let tmpUrl = URL(string: tmpFile)!
            do {
                try FileManager.default.moveItem(at: location, to: tmpUrl)

                var options: [String: String]? = nil
                if let type = request.content.userInfo["media_type"] as? String {
                    options = [String: String]()
                    options?[UNNotificationAttachmentOptionsTypeHintKey] = type
                }
                if let attachment = try? UNNotificationAttachment(identifier: "media." + fileUrl.pathExtension, url: tmpUrl, options: options) {
                    bestAttemptContent.attachments = [attachment]
                }
                completion()
            } catch {
                completion()
            }
        }
    }
    task.resume()
}

override func serviceExtensionTimeWillExpire() {
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
        contentHandler(bestAttemptContent)
    }
}
```

With this code, we download the attachment, if exists, and move it to a temporary directory. Then we add it to our notification with

```bash
if let attachment = try? UNNotificationAttachment(identifier: "media." + fileUrl.pathExtension, url: tmpUrl, options: options) {
    bestAttemptContent.attachments = [attachment]
}
```


# &#x20;Android SDK


# Introduction

### MPush <a href="#mpush" id="mpush"></a>

If your project is configured to send push notifications you must use this set of API to properly register your users' devices tor receive push notifications. Also, you'll need to have basic knowledge of Google Firebase and Firebase Cloud Messaging.

#### Before you start <a href="#before-you-start" id="before-you-start"></a>

You must **create a Firebase project** for your application, this way you'll have the push server key to insert in your `MBurger project`. This will generate a push API KEY.

To create a new Firebase project, please reference [this](https://firebase.google.com/docs/android/setup) documentation.&#x20;

{% hint style="info" %}
Remember that you'll need at least these Firebase dependencies:
{% endhint %}

```bash
com.google.firebase:firebase-core
com.google.firebase:firebase-messaging
```

For the **FCM client setup** refer to [this](https://firebase.google.com/docs/cloud-messaging/android/client) documentation. Long story short you'll need to extend a new`FirebaseMessagingService`which will trigger`onNewToken`to obtain the Firebase token which you'll need to send to the MBurger API and`onMessageReceived,` an event triggered when a push message is received. Be aware that **MBurger uses the "data" message** types in order to permit the developers to completely customize notifications and behavior on receiving notifications (you'll find all about data messages [here](https://firebase.google.com/docs/cloud-messaging/concept-options))

After you have set up your project for Firebase you can start using Nooko SDK to register users receive FCM messages.


# Setup

If you have the **MBurger Android SDK** already installed on your project, you also have MPush, if you wish to add it without MBurger you can get the library via **Maven** adding to your top `build.gradle` file this repository:

```bash
maven { 
    url "https://dl.bintray.com/mumbleideas/MBurger-Android/" 
}
```

Then add to your dependencies:

```bash
implementation 'mumble.mburger:mpush-android:1.1.7'
```


# Register a device

To register a new device you'll need to have a Firebase token, which you can obtain one from your `FirebaseMessagingService` method `onNewToken`:

```java
@Override
public void onNewToken(String token) {
}
```

Then is the best practice to register your device calling the registration API:

```java
@Override
public void onNewToken(String token) {
    MBurgerPushTasks.sendToken(getApplicationContext(), 
            listener, //OPTIONAL LISTENER FOR TOKEN SENDING AND ERROR MANAGING
            getDeviceID(), token);
}
```

Where `getDeviceID()` is your method to obtain the **Android ID** which will be your unique identifier. Pay attention to the changes Oreo makes to this data, refer to [this documentation](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID). Now your device is ready to receive push messages with your `FirebaseMessagingService` method `onMessageReceived`, but if you need to differentiate push groups you may need to use **topics**.


# Subscribe to topics

A topic is like a group you can subscribe in order to send push notifications specifically to that topic, you can subscribe to multiple topics creating a `MBTopic` Arraylist with the topic names, then call the API:

```java
ArrayList<MBTopic> topics = new ArrayList<MBTopic>()
topics.add(new MBTopic(
    TOPIC_CODE, //The main topic String to which subscribe (eg. sport)
    TOPIC_NAME, //A familiar name to give your topic (eg. Sport Club)
    false       //If it's a topic where only one user should subscribe
))

MBurgerPushTasks.registerTopics(context, 
        getDeviceId(context), topics)
```

From the `MBurger Push dashboard` then you can send push notification only to some topics of making an app send push notifications to a specific topic. While it's not necessary to subscribe to topics at every startup, it can be useful to resubscribe anytime your `InstanceID` changes in order to maintain data coherence.

When you receive a push notification then your `FirebaseMessagingService` will be triggered and you will find all the data you inserted on the "**data**" field of the **RemoteMessage** object.

```bash
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
     Map<String, String> map = remoteMessage.getData();

     //The standard message is inside the "body" field
     String msg = map.get("body");
     if(map.containsKey("custom")) {
         String custom = map.get("custom");
         if(custom != null){
             try {
                JSONObject jCustom = new JSONObject(custom);
               //Take out the data you inserted inside the notification and create your notification with Android SDK.
             } catch (JSONException e) {
                    e.printStackTrace();
             }
         }
     }
}
```

To create a notification with the Android SDK refer to [this documentation](https://developer.android.com/training/notify-user/build-notification).

#### Push topics management <a href="#push-topics-management" id="push-topics-management"></a>

To unsubscribe from a push topic you'll need to call the **unregisterTopics**() API with the same fields you used with **registerTopics**(). You can also unsubscribe to all topics you subscribed by calling:

```java
MBurgerPushTasks.unregisterAllTopics(context, getDeviceId())
```

This way you'll no more receive push messages from any topic you registered the device before.


# Flutter SDK


# Introduction

MPush is a client library, written in dart, that can be used to interact with the MPush API, you can find it also on [https://pub.dev/packages/mpush](< https://pub.dev/packages/mpush>)

MPush uses a classic Pub/Sub pattern, you will register your device to topics, then from the MPush APIs you will be able to send notifications to those topics and all device registered will receive a notification.

A topic can represent whatever you want in your system (e.g. the entire app, a user a subset of user with a common characteristic) so you will be able to choose the granularity of the notifications.

#### Packages dependencies

* `http: ^0.12.2`
* `device_info: ^0.4.2+8`


# Installation

You can install the MPush SDK using pub, add this to your `pubspec.yaml` file:

```yaml
dependencies:
  mpush: ^0.0.1
```

And then install packages from the command line with:

```bash
$ flutter pub get
```


# Android Setup

To integrate your plugin into the Android part of your app, follow these steps (from the firebase messaging plugin):

1. Using the [Firebase Console](https://console.firebase.google.com/) add an Android app to your project: Follow the assistant, download the generated `google-services.json` file and place it inside `android/app`.
2. Add the classpath to the `[project]/android/build.gradle` file.

```
dependencies {
  // Example existing classpath
  classpath 'com.android.tools.build:gradle:3.5.3'
  // Add the google services classpath
  classpath 'com.google.gms:google-services:4.3.2'
}
```

3\. Add the apply plugin to the `[project]/android/app/build.gradle` file.

```
// ADD THIS AT THE BOTTOM
apply plugin: 'com.google.gms.google-services'
```

{% hint style="info" %}
If this section is not completed you will get an error like this:
{% endhint %}

```java
java.lang.IllegalStateException:
Default FirebaseApp is not initialized in this process [package name].
Make sure to call FirebaseApp.initializeApp(Context) first.
```

{% hint style="info" %}
When you are debugging on Android, use a device or AVD with Google Play services. Otherwise you will not be able to authenticate.When you are debugging on Android, use a device or AVD with Google Play services. Otherwise you will not be able to authenticate.
{% endhint %}


# iOS Setup

The first thing you have to do is to setup the iOS project is to enable the push notification capability to your project. Open the project in Xcode going in ios -> Runner.xcworkspace, then in the Signing & Capabilities tab click on the + Capability button and select "Push Notifications"

![Enable push notifications capability](/files/-ML7_tOsJ6Ny2BDq4Kxu)

{% hint style="info" %}
You will have to use a provisoning profile created for this app, you will not be able to test and receive push notification using a wildcard provisioning profile.
{% endhint %}

Then yu have to modify the AppDelegate class of your application, open `AppDelegate.swift` file and add this line in the `didFinishLaunchingWithOptions` function.

```swift
UNUserNotificationCenter.current().delegate = self
```

The app delegate should look like this.

```swift
import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    UNUserNotificationCenter.current().delegate = self
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}
```


# Rich Notifications

If you want to include images and videos in your push notifications you will need to create a new target. The link of the media will be sent in the payload of the notifications in the `media_url` field. To view the media sent in the notifications follow tihs steps.\
\
1\. Create a Notification Service target

In Xcode go to File -> New Target and choose [Notification Service Extension](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension).\
\
This will create a class that will intercept all push notification sent to the app, you will be able to change its content from this class.

![Create Notification Servide Extension](/files/-ML7aY_m6s2sn1ZX0d8A)

2\. Download the media

In the notification service class use this code to download the media and attach to the push notification.

```swift
class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            if let mediaUrl = request.content.userInfo["media_url"] as? String, let fileUrl = URL(string: mediaUrl) {
                let type = request.content.userInfo["media_type"] as? String
                downloadMedia(fileUrl: fileUrl, type: type, request: request, bestAttemptContent: bestAttemptContent) {
                    contentHandler(bestAttemptContent)
                }
            } else {
                contentHandler(bestAttemptContent)
            }
        }
    }
    
    func downloadMedia(fileUrl: URL, type: String?, request: UNNotificationRequest, bestAttemptContent: UNMutableNotificationContent, completion: @escaping () -> Void) {
        let task = URLSession.shared.downloadTask(with: fileUrl) { (location, _, _) in
            if let location = location {
                let tmpDirectory = NSTemporaryDirectory()
                let tmpFile = "file://".appending(tmpDirectory).appending(fileUrl.lastPathComponent)
                let tmpUrl = URL(string: tmpFile)!
                do {
                    try FileManager.default.moveItem(at: location, to: tmpUrl)
                    
                    var options: [String: String]? = nil
                    if let type = type {
                        options = [String: String]()
                        options?[UNNotificationAttachmentOptionsTypeHintKey] = type
                    }
                    if let attachment = try? UNNotificationAttachment(identifier: "media." + fileUrl.pathExtension, url: tmpUrl, options: options) {
                        bestAttemptContent.attachments = [attachment]
                    }
                    completion()
                } catch {
                    completion()
                }
            }
        }
        task.resume()
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}
```


# Custom replacements

To use the custom replacements function yoou will need to update the notification extension cerated in the previous step, here are the steps to follow.

## 1. Create an app group identifier

Go to developer.apple.com -> Certificates, Identifiers & Profiles -> Identifiers. Select App Groups and create a new one.

![](/files/vXeqJzm53DGwbrtDSrKJ)

## 2. Enable App Groups&#x20;

You will need then to enable app groups, with the app group created previously, both on developer.apple.com and on the project in XCode, under the Signing & Capabilities section.

You need to do this for the main app and for the notification extension.

## 3. Set the app group identifier

In your `AppDelegate` class set the app group identifier

```swift
SwiftMpushPlugin.appGroupIdentifier = "YOUR_APP_GROUP_ID"
```

## 4. Update the notification extension code

Update your notification extension code to manage the replacements

```swift
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            manageCustomReplacements(request: request, bestAttemptContent: bestAttemptContent)
            ...
        }
    }

    private func manageCustomReplacements(request: UNNotificationRequest, bestAttemptContent: UNMutableNotificationContent) {
        let appGroupIdentifier = "YOUR_APP_GROUP_ID"
        let customDatakey = "com.mumble.mpush.customData"
        guard let customData = UserDefaults(suiteName: appGroupIdentifier)?.object(forKey: customDatakey) as? [String: String] else {
            return
        }
        
        for (key, value) in customData {
            bestAttemptContent.title = request.content.title.replacingOccurrences(of: key, with: value)
            bestAttemptContent.body = request.content.body.replacingOccurrences(of: key, with: value)
        }
    }
```


# Flutter Setup

The first thing you need to do is to set your `apiToken`:

```dart
MPush.apiToken = 'YOuR_API_TOKEN';
```

Then you need to configure MPush with the callbacks that will be called when a notifcation arrives or is tapped and the android notification settings.

```dart
MPush.configure(
  onNotificationArrival: (notification) {
    print("Notification arrived: $notification");
  },
  onNotificationTap: (notification) {
    print("Notification tapped: $notification");
  },
  androidNotificationsSettings: MPAndroidNotificationsSettings(
    channelId: 'mpush_example',
    channelName: 'MPush Notifications',
    channelDescription: 'Push notification channel', 
    icon: '@mipmap/icon_notif',
  ),
);
```

To configure the Android part you need to pass a `MPAndroidNotificationsSettings` to the configure sections, it has 2 parameters:

* `channelId`: the id of the channel
* `channelName`: the name for the channel
* `channelDescription`: the description for the channel
* `icon`: the default icon for the notification, in the example application the icon is in the res folder as a mipmap, so it's adressed as `@mipmap/icon_notif`, iff the icon is a drawable use `@drawable/icon_notif`.


# Request a token

To request a notification token you need to do the following things:

1. Set a callback that will be called once the token is received correctly from APNS/FCM

```dart
MPush.onToken = (token) {
    print("Token retrieved: $token");
}
```

2\. Request the token using MPush:

```dart
MPush.requestToken();
```


# Register to topics

Once you have a notification token you can register this device to push notifications and register to topics:

```dart
MPush.onToken = (token) async {
  print("Token received $token");
  await MPush.registerDevice(token).catchError(
    (error) => print(error),
  );
  await MPush.registerToTopic(MPTopic(code: 'Topic')).catchError(
    (error) => print(error),
  );
  print('Registered');
};
```

The topic are instances of the `MPTopic` class which has 3 properties:

* `code`: the id of the topic
* *\[Optional]* `title`: the readable title of the topic that will be displayed in the dashboard, if this is not set it will be equal to `code`.
* *\[Optional]* `single`: if this topic represents a single device or a group of devices, by default `false`.


# Launch notification

If the application was launched from a notification you can retrieve the data of the notification like this, this will be `null` if the application was launched normally:

```dart
Map<String, dynamic> launchNotification = await MPush.launchNotification();
print(launchNotification);
```


