Android
Push Notifications Multi Device Support

Push Notifications with Multi-Device Support

Sendbird’s push notifications with multi-device support provide the same features as our general push notifications, but with additional support for multi-device users. If implemented, notifications are delivered to all online and offline devices of a multi-device user. However, through our Chat SDK for Android, push notifications are displayed only on offline devices, while ignored by online devices. As a result, client apps are able to display push notifications on all offline devices, regardless of whether one or more are online.

For example, let’s say a multi-device user who has six devices installed with your client app is online on one device and offline on the remaining five. If push notifications are implemented, notifications aren’t delivered to any devices. If push notifications with multi-device support are implemented, notifications are delivered to all six devices, but displayed only on the five devices that are offline.

Note: By default, when a user's device is disconnected from Sendbird server, the server sends push notification requests to FCM for the messages. The Chat SDK for Android automatically detects when a user's client app goes into the background from the foreground, and updates the user's connection status to disconnected. Therefore, under normal circumstances, you don't need to call the disconnect() method.

Understanding the differences

To find out which push notifications best suits your client app use cases, refer to the table below:

General push notificationsPush notifications with multi-device support

Send when

All devices are offline.

As long as one device is offline.

Notification messages

Single-device user: Displayed when disconnected from the server and thus offline.

Multi-device user: Displayed only when all devices are offline.

Single-device user: Displayed when disconnected from the server and thus offline.

Multi-device user: Displayed on all offline devices, regardless of whether one or more are online.

SDK's event callback

Invoked only when the app is connected to Sendbird server.

Invoked only when the app is connected to Sendbird server.

App instance's registration token

Can be manually registered to Sendbird server.

Automatically registered to Sendbird server.

Notification preferences

Can be set by application and group channel.

N/A

Push notification templates

Supported.

Supported.

Push notification translation

Supported by Google Cloud Translation API.

Supported by Google Cloud Translation API.


Push notifications for FCM

This part covers the following step-by-step instructions of our push notifications for FCM:

Note: Move to Push notifications for HMS if you want to see the instructions for HMS push notifications.

Step 1: Generate server key for FCM

Sendbird server requires your server key to send notification requests to FCM on behalf of your server. This is required for FCM to authorize HTTP requests.

Note: If you already have your server key, skip this step and go directly to Step 2: Register server key to Sendbird Dashboard.

  1. Go to the Firebase console. If you don't have a Firebase project for your client app, create a new project.
    Project detail
  2. Select your project card to move to the Project Overview.
  3. Click the gear icon at the upper left corner and select Project settings.
    Project settings
  4. Go to Cloud Messaging > Project credentials and copy your server key.
    Server key
  5. Go to the General tab and select your Android app to add Firebase to. During the registration process, enter your package name, download the google-services.json file, and place it in your Android app module root directory. Add firebase to Android App

Step 2: Register server key to Sendbird Dashboard

Register your server key to Sendbird server through the dashboard as follows:

  1. Sign in to your dashboard and go to Settings > Application > Notifications.
  2. Turn on Notifications and select the Send as long as one device is offline option.
  3. Click the Add credentials button and register the app ID and app secret acquired at Step 1. Set Push Information

Note: Your server key can also be registered using the platform API's add a FCM push configuration action.

Step 3: Set up Firebase and the FCM SDK

Add the following dependency for the Cloud Messaging Android library to your build.gradle file as below:

build.gradle
Light Color Skin
Copy
dependencies {
    ...
    implementation 'com.google.firebase:firebase-messaging:20.1.0'
}

Then the Chat SDK writes and declares our push notifications with multi-device support in the manifest while you build your client app. If you declare another push service that extends FirebaseMessagingService in your client app's manifest, this multi-device support will not work in the app.

Note: To learn more about this step, refer to Firebase's Set Up a Firebase Cloud Messaging client app on Android guide. The Google FCM sample project is another helpful reference.

Step 4: Implement multi-device support in your Android app

The following classes and interface are provided to implement push notifications with multi-device support:

Class or interfaceDescription

SendBirdPushHandler

A class that provides the onNewToken(), onMessageReceived(), and other callbacks to handle a user's registration token and receive notification messages from FCM.

SendBirdPushHelper

A class that provides the methods to register and unregister a SendBirdPushHandler handler, check if the same message has already been received, and more.

OnPushTokenReceiveListener

An interface that contains the onReceived() callback to receive a user's registration token from FCM.

These are used to inherit your MyFirebaseMessagingService class from the SendBirdPushHandler class and implement the following:

Light Color Skin
Copy
public class MyFirebaseMessagingService extends SendBirdPushHandler {

    private static final String TAG = "MyFirebaseMsgService";
    private static final AtomicReference<String> pushToken = new AtomicReference<>();

    public interface ITokenResult {
        void onPushTokenReceived(String pushToken, SendBirdException e);
    }

    @Override
    public void onNewToken(String token) {
        pushToken.set(token);
    }

    // Invoked when a notification message has been delivered to the current user's client app.
    @Override
    public void onMessageReceived(Context context, RemoteMessage remoteMessage) {
        String channelUrl = null;
        try {
            if (remoteMessage.getData().containsKey("sendbird")) {
                JSONObject sendbird = new JSONObject(remoteMessage.getData().get("sendbird"));
                JSONObject channel = (JSONObject) sendbird.get("channel");
                channelUrl = (String) channel.get("channel_url");

                // If you want to customize a notification with the received FCM message,
                // write your method like the sendNotification() below.
                sendNotification(context, remoteMessage.getData().get("message"), channelUrl);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected boolean isUniquePushToken() { 
        return false;
    }

    public static void sendNotification(Context context, String messageBody, String channelUrl) {
        // TODO: Customize your notification containing the received FCM message.
    }

    public static void getPushToken(ITokenResult listener) {
        String token = pushToken.get();
        if (!TextUtils.isEmpty(token)) {
            listener.onPushTokenReceived(token, null);
            return;
        }

        SendBirdPushHelper.getPushToken((newToken, e) -> {
            if (listener != null) {
                listener.onPushTokenReceived(newToken, e);
            }

            if (e == null) {
                pushToken.set(newToken);
            }
        });
    }
}

Note: Upon initial startup of your app, the FCM SDK generates a unique and app-specific registration token for the client app instance on your user's device. FCM uses this registration token to determine which device to send notification messages to.

In order to receive information about push notification events for the current user from Sendbird server, register a MyFireBaseMessagingService instance to the SendBirdPushHelper as an event handler. It is recommended to register the instance in the onCreate() method of the Application instance as follows:

Light Color Skin
Copy
public class MyApplication extends Application {
    private static final String APP_ID = "YOUR_APP_ID";
    ...
    
    @Override
    public void onCreate() {
        super.onCreate();
        SendBird.init(APP_ID, getApplicationContext());
        SendBirdPushHelper.registerPushHandler(new MyFirebaseMessagingService());
    }
}

Also, register a MyFireBaseMessagingService instance when a user logs into Sendbird server as follows:

Light Color Skin
Copy
SendBird.connect(USER_ID, new SendBird.ConnectHandler() {
    @Override
    public void onConnected(User user, SendBirdException e) {
        if (e != null) {    //Error!
            return;
        }
        ...
        
        SendBirdPushHelper.registerPushHandler(new MyFirebaseMessagingService());
    }
});

The instance should be unregistered when a users logs out from Sendbird server as follows:

Light Color Skin
Copy
SendBirdPushHelper.unregisterPushHandler(IS_UNREGISTER_ALL, new SendBirdPushHelper.OnPushRequestCompleteListener() {
    @Override
    public void onComplete(boolean isRegisted, String token) {
        SendBird.disconnect(new SendBird.DisconnectHandler() {
            @Override
            public void onDisconnected() {
                // TODO: Clear user-related data.   
            }
        });
    }

    @Override
    public void onError(SendBirdException e) {
    }
});

Step 5: Handle an FCM message payload

The following code shows how to receive and parse a notification message payload which consists of two properties: message and sendbird. The message property is a string generated according to a chosen notification template. The sendbird property is a JSON object which contains all the information about the message a user has sent. Within the MyFirebaseMessagingService.java, you can show the parsed messages to users as notifications by using your custom sendNotification() method.

Note: To learn more about how to write code to receive and parse FCM notification messages, how notification messages are handled depending on the state of the receiving app, how to edit your client app's manifest, or how to override the onMessageReceived method, refer to Firebase's Receive messages in an Android app guide.

MyFirebaseMessagingService.java
Light Color Skin
Copy
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    String channelUrl = null;
    try {
        if (remoteMessage.getData().containsKey("sendbird")) {
            JSONObject sendbird = new JSONObject(remoteMessage.getData().get("sendbird"));
            JSONObject channel = (JSONObject) sendbird.get("channel");
            channelUrl = (String) channel.get("channel_url");

            // If you want to customize a notification with the received FCM message,
            // write your method like the sendNotification() below.
            sendNotification(context, remoteMessage.getData().get("message"), channelUrl);
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

...

public static void sendNotification(Context context, String messageBody, String channelUrl) {
    // TODO: Implement your own way to create and show a notification containing the received FCM message.
}

The following is a complete payload format of the sendbird property, which contains a set of provided key-value items.

Light Color Skin
Copy
{
    "category": "messaging:offline_notification",
    "type": string,                 // Message type: 'User', 'File', or 'Admin'
    "message": string,              // User input message
    "data": string,                 // Custom data field
    "custom_type": string,          // Custom message type
    "message_id": long,             // Message ID
    "created_at": long,             // 13-digit timestamp
    "app_id": string,               // Application's unique ID
    "unread_message_count": int,    // Total unread count of the user
    "channel": {
        "channel_url": string,      // Group channel URL
        "name": string,             // Group channel name
        "custom_type": string       // Group channel custom_type
    },
    "channel_type": string,         // Channel type: 'messaging', 'group_messaging', or 'chat'
    "sender": {
        "id": string,               // Sender's unique ID
        "name": string,             // Sender's nickname
        "profile_url": string       // Sender's profile image URL 
    },
    "recipient": {
        "id": string,               // Recipient's unique ID
        "name": string              // Recipient's nickname
    },
    "files": [],                    // If a message is a file link, this array represents files
    "translations": {},             // If a message has translations, this dict has locale:translation.
    "push_alert": string,           // A customized alert push notification 
    "push_sound": string,           // The location of a sound file for notification messages
    "audience_type": string,        // The type of audiences to receive notification messages
    "mentioned_users": {
        "user_id": string,                      // The ID of a mentioned user 
        "total_unread_mention_count": int,      // The number of messages which a user has been mentioned but has not read within the channels 
        "channel_unread_mention_count": int,    // The number of channels with messages which a user has been mentioned but has not read
        "is_hidden": boolean                    // Whether or not a mentioned user has hidden the channel from the list
    } 
}

Step 6: Enable multi-device support in the Dashboard

After the above implementation is completed, multi-device support should be enabled in your dashboard by going to Settings > Application > Notifications > Push notifications for multi-device users.
Multi-device support


Push notifications for HMS

This part covers the following step-by-step instructions of our push notifications for HMS:

Note: Move to Push notifications for FCM if you want to see the instructions for FCM push notifications.

Step 1: Generate app ID and app secret for HMS

Sendbird server requires your app ID and app secret to send notification requests to HMS on behalf of your server. This is required for HMS to authorize HTTP requests.

Note: If you already have your app ID and app secret, skip this step and go directly to Step 2: Register app ID and app secret to Sendbird Dashboard.

  1. Go to the AppGallery Connect. If you don't have a project for your client app, create a new project.
    Project detail
  2. Select your project card to move to the Project Settings.
  3. Go to Convention > App Information and copy your App ID and App secret to use them in your Sendbird Dashboard later.
    Project settings
  4. During the registration process, enter your package name, download the agconnect-services.json file, and place it in your Android app module root directory.
    Server key

Step 2: Register app ID and app secret to Sendbird Dashboard

Register your app ID and app secret to Sendbird server through the dashboard as follows:

  1. Sign in to your dashboard and go to Settings > Application > Notifications.
  2. Turn on Notifications and select Send when all devices are offline.
  3. Click the Add credentials button and register the app ID and app secret acquired at Step 1. Server key

Step 3: Set up Huawei Message Service and the HMS SDK

Add the following dependency for the Cloud Messaging Android library to your build.gradle files that are at the project level and app level.

Project level
App level
Light Color Skin
Copy
allprojects {
    repositories {
        ...
        maven { url 'https://developer.huawei.com/repo/' }
    }
}

buildscript {
    repositories {
        ...
        maven { url 'http://developer.huawei.com/repo/' }
    }
    dependencies {
        ...
        classpath 'com.huawei.agconnect:agcp:1.1.1.300'
    }
}
Light Color Skin
Copy
apply plugin: 'com.huawei.agconnect'
...

dependencies {
    // Retain other existing dependencies.
    ...
    // Replace {version} with the actual SDK version number, for example implementation 'com.huawei.hms:push:4.0.3.301'.
    implementation 'com.huawei.hms:push:{version}'
}

Then the Chat SDK writes and declares our push notifications with multi-device support in the manifest while you build your client app. If you declare another push service that extends FirebaseMessagingService in your client app's manifest, this multi-device support will not work in the app.

Note: To learn more about this step, refer to Huawei's Preparations guide. The Push Kit sample code for Android is another helpful reference.

Step 4: Implement multi-device support in your Android app

The following classes and interface are provided to implement push notifications with multi-device support:

Class or interfaceDescription

SendBirdHmsPushHandler

A class that provides the onNewToken(), onMessageReceived(), and other callbacks to handle a user's registration token and receive notification messages from HMS.

SendBirdPushHelper

A class that provides the methods to register and unregister a SendBirdHmsPushHandler handler, check if the same message has already been received, and more.

OnPushTokenReceiveListener

An interface that contains the onReceived() callback to receive a user's registration token from HMS.

These are used to inherit your MyHmsMessagingService class from the SendBirdHmsPushHandler class and implement the following:

Light Color Skin
Copy
public class MyHmsMessagingService extends SendBirdHmsPushHandler {

    private static final String TAG = "MyHmsMessagingService";
    private static final AtomicReference<String> pushToken = new AtomicReference<>();

    public interface ITokenResult {
        void onPushTokenReceived(String pushToken, SendBirdException e);
    }

    @Override
    public void onNewToken(String token) {
        Log.i(TAG, "onNewToken(" + token + ")");
        pushToken.set(token);
    }

    @Override
    public void onMessageReceived(Context context, RemoteMessage remoteMessage) {
        String channelUrl = null;
        try {
            if (remoteMessage.getDataOfMap().containsKey("sendbird")) {
                JSONObject sendBird = new JSONObject(remoteMessage.getDataOfMap().get("sendbird"));
                JSONObject channel = (JSONObject) sendBird.get("channel");
                channelUrl = (String) channel.get("channel_url");

                // Also if you intend on generating your own notifications as a result of a received HMS
                // message, here is where that should be initiated. See sendNotification method below.
                sendNotification(context, remoteMessage.getDataOfMap().get("message"), channelUrl);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean isUniquePushToken() {
        return false;
    }

    @Override
    protected Context getContext() {
        Log.e("==", "getContext()");
        // TODO: return application context
        Return APPLICATION_CONTEXT;
    }

    public static void sendNotification(Context context, String messageBody, String channelUrl) {
        // TODO: Customize your notification containing the received HMS message.
    }

    public static void getPushToken(ITokenResult listener) {
        String token = pushToken.get();
        if (!TextUtils.isEmpty(token)) {
            listener.onPushTokenReceived(token, null);
            return;
        }

        SendBirdPushHelper.getPushToken((newToken, e) -> {
            if (listener != null) {
                listener.onPushTokenReceived(newToken, e);
            }

            if (e == null) {
                pushToken.set(newToken);
            }
        });
    }
}

Note: Upon initial startup of your app, the HMS SDK generates a unique and app-specific registration token for the client app instance on your user's device. HMS uses this registration token to determine which device to send notification messages to.

In order to receive information about push notification events for the current user from Sendbird server, register a MyHmsMessagingService instance to the SendBirdPushHelper as an event handler. It is recommended to register the instance in the onCreate() method of the Application instance as follows:

Light Color Skin
Copy
public class MyApplication extends Application {
    private static final String APP_ID = "YOUR_APP_ID";
    ...
    
    @Override
    public void onCreate() {
        super.onCreate();
        SendBird.init(APP_ID, getApplicationContext());
        SendBirdPushHelper.registerHmsPushHandler(new MyHmsMessagingService());
    }
}

Also, register a MyHmsMessagingService instance when a user logs into Sendbird server as follows:

Light Color Skin
Copy
SendBird.connect(USER_ID, new SendBird.ConnectHandler() {
    @Override
    public void onConnected(User user, SendBirdException e) {
        if (e != null) {    //Error!
            return;
        }
        ...
        
        SendBirdPushHelper.registerHmsPushHandler(new MyHmsMessagingService());
    }
});

The instance should be unregistered when a users logs out from Sendbird server as follows:

Light Color Skin
Copy
SendBirdPushHelper.unregisterPushHandler(IS_UNREGISTER_ALL, new SendBirdPushHelper.OnPushRequestCompleteListener() {
    @Override
    public void onComplete(boolean isRegisted, String token) {
        SendBird.disconnect(new SendBird.DisconnectHandler() {
            @Override
            public void onDisconnected() {
                // TODO: Clear user-related data.  
            }
        });
    }

    @Override
    public void onError(SendBirdException e) {
    }
});

Step 5: Handle an HMS message payload

The following code shows how to receive and parse a notification message payload which consists of two properties: message and sendbird. The message property is a string generated according to a chosen notification template. The sendbird property is a JSON object which contains all the information about the message a user has sent. Within the MyHmsMessagingService.java, you can show the parsed messages to users as notifications by using your custom sendNotification() method.

Note: To learn more about how to implement code to receive and parse a HMS notification message, how notification messages are handled depending on the state of the receiving app, how to edit the app manifest, or how to override the onMessageReceived method, refer to Huawei's Receive messages in the Android app guide.

Light Color Skin
Copy
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    String channelUrl = null;
    try {
        if (remoteMessage.getDataOfMap().containsKey("sendbird")) {
            JSONObject sendbird = new JSONObject(remoteMessage.getDataOfMap().get("sendbird"));
            JSONObject channel = (JSONObject) sendbird.get("channel");
            channelUrl = (String) channel.get("channel_url");

            // If you want to customize a notification with the received HMS message,
            // write your method like the sendNotification() below.
            sendNotification(context, remoteMessage.getData().get("message"), channelUrl);
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

...

public static void sendNotification(Context context, String messageBody, String channelUrl) {
    // TODO: Implement your own way to create and show a notification containing the received HMS message.
}

The following is a complete payload format of the sendbird property, which contains a set of provided key-value items.

Light Color Skin
Copy
{
    "category": "messaging:offline_notification",
    "type": string,          // Message type: 'User', 'File', or 'Admin'
    "message": string,              // User input message
    "data": string,                 // Custom data field
    "custom_type": string,          // Custom message type
    "message_id": long,             // Message ID
    "created_at": long,             // 13-digit timestamp
    "app_id": string,               // Application's unique ID
    "unread_message_count": int,    // Total unread count of the user
    "channel": {
        "channel_url": string,      // Group channel URL
        "name": string,             // Group channel name
        "custom_type": string       // Group channel custom_type
    },
    "channel_type": string,      // 'messaging', 'group_messaging', or 'chat'
    "sender": {
        "id": string,               // Sender's unique ID
        "name": string,             // Sender's nickname
        "profile_url": string       // Sender's profile image URL 
    },
    "recipient": {
        "id": string,               // Recipient's unique ID
        "name": string              // Recipient's nickname
    },
    "files": [],      // If a message is a file link, this indicates files
    "translations": {},             // The items of locale:translation.
    "push_alert": string,           // A customized alert push notification 
    "push_sound": string,   // The location of a sound file for notifications
    "audience_type": string,       // The type of audiences for notifications
    "mentioned_users": {
        "user_id": string,                 // The ID of a mentioned user 
        "total_unread_mention_count": int,      // The number of messages which a user has been mentioned but has not read within the channels 
        "channel_unread_mention_count": int,    // The number of channels with messages which a user has been mentioned but has not read
        "is_hidden": boolean                    // Whether or not a mentioned user has hidden the channel from the list
    } 
}

Step 6: Enable multi-device support in the Dashboard

After the above implementation is completed, multi-device support should be enabled in your dashboard by going to Settings > Application > Notifications > Push notifications for multi-device users.

After the above implementation is completed, go to Settings > Application > Notifications > Push notifications for multi-device users and enable multi-device support in your dashboard.

Multi-device support