Skip to content

Use case: real-time chat

Activity Feed as Chat

Overview

With a combination of the GetSocial Activity Feed and Notifications API, you can implement real-time user-to-user or group chat.

Just like news feeds, chats keep users engaged in your app and give them one more reason to get back.

Implementation guide

This guide shows you how to create chat-like Activity Feeds for each pair (or group) of users who want to chat and send notifications about new messages with Notifications API.

0. Prerequisite

  1. Integrate GetSocial SDK. Check the detailed guide on Android, iOS or Unity.

  2. Setup push notifications. Check the detailed setup guide on Android, iOS or Unity.

1. Design UI

UI defines the look and feel for your chat view, making it visually distinct from Activity Feed. Core elements include:

  • Different message styling for sender and recipient.
  • List of messages with an input field.

2. Generate unique identifier for chat

Create a unique Activity Feed for each pair (or group) of users who want to chat. For consistency, you have to ensure that they get same chat id (feed id, in fact).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
String generateChatId(String... userIds) {
    // Sort to get the same chat id for same participants
    Arrays.sort(userIds);

    StringBuilder builder = new StringBuilder("chat");
    for (String id : userIds) {
        builder.append("_").append(id);
    }

    return builder.toString();
}
1
2
3
4
5
6
7
- (NSString *)chatIdForUsers: (NSArray *) userIds
{
    NSArray *sortedIds = [userIds sortedArrayUsingSelector:@selector(compare:)];
    NSString *chatId = [sortedIds componentsJoinedByString:@"_"];

    return [@"chat_" stringByAppendingString:chatId];
}
1
2
3
4
5
6
func generateChatId(_ userIds : [String]) -> String {
    // Sort to get the same chat id for same participants
    let chatId = userIds.sorted().joined(separator: "_")

    return "chat_\(chatId)"
}
1
2
3
4
5
6
7
private string GenerateChatId(params string[] userIds)
{
    // Sort to get the same chat id for same participants
    Array.Sort(userIds);

    return "chat_" + string.Join("_", userIds);
}

Feed Naming

Use prefix’s like “chat_” to distinguish chat feeds from regular ones on Developer’s Dashboard.

Feed ID Restrictions

Feed name could contain only alphanumeric symbols: letters [a-z], numbers [0-9], -, _, .; and should not be longer than 64 symbols.

3. Load messages

To load message use GetSocial.getActivities. Messages are sorted historically (newest posts first), so be sure to reverse the order of messages before showing them to the user.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
GetSocial.getActivities(ActivitiesQuery.postsForFeed(chatId).withLimit(50), new Callback<List<ActivityPost>>() {
    @Override
    public void onSuccess(List<ActivityPost> messages) {
        // Reversing list to have resulting posts in right order
        Collections.reverse(messages);

        // Show messages on the UI
        showMessages(messages);
    }

    @Override
    public void onFailure(GetSocialException e) {
        Log.e("GetSocial", "Activities loading failed, error: " + e.getMessage());
    }
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
GetSocialActivitiesQuery *query = [GetSocialActivitiesQuery postsForFeed:chatId];
[query setLimit:50];

[GetSocial activitiesWithQuery:query
    success:^(NSArray<GetSocialActivityPost *> *messages) {
        // Reversing list to have resulting posts in right order
        messages = [[messages reverseObjectEnumerator] allObjects];

        // Show messages on the UI
        [self showMessages:messages];
    }
    failure:^(NSError *error) {
        NSLog(@"Failed to get messages, error: %@", error);
    }
];
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let query = GetSocialActivitiesQuery.posts(forFeed: chatId)
query.setLimit(50)

GetSocial.activities(with: query, 
    success: { (messages: [GetSocialActivityPost]) in
        // Reversing list to have resulting posts in right order
        let messages = messages.reversed()

        // Show messages on the UI
        self.showMessages(messages)
    }) { (error: Error) in
        print("Failed to get messages, error: \(error.localizedDescription)")
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var chatId = GenerateChatId(new[] {GetSocial.User.Id, Receiver.Id});
var query = ActivitiesQuery.PostsForFeed(chatId).WithLimit(50);

GetSocial.GetActivities(query, messages =>
    {
        // Reversing list to have resulting posts in right order
        messages.Reverse();

        // Show messages on the UI
        ShowMessages(messages);
    },
    error =>
    {
        Debug.Log("Failed to get messages, error: " + error);
    });

4. Post message

To send a message, it’s enough to specify its text. Sender info is attached to it by SDK. Using ActivityPostContent you can also share media content like images, gifs and videos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
ActivityPostContent messageContent = ActivityPostContent
    .createBuilderWithText("Hi, it's nice to have a separate chat!").build();

GetSocial.postActivityToFeed(chatId, messageContent, new Callback<ActivityPost>() {
    @Override
    public void onSuccess(ActivityPost chatMessage) {
        Log.i("GetSocial", "You message was successfully posted!");
    }

    @Override
    public void onFailure(GetSocialException e) {
        Log.e("GetSocial", "Posting failed, error: " + e.getMessage());
    }
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
GetSocialActivityPostContent *messageContent = [GetSocialActivityPostContent new];
postContent.text = @"Hi, it's nice to have a separate chat!";

[GetSocial postActivity:messageContent 
                 toFeed:chatId
                success:^(GetSocialActivityPost *post) {
                    NSLog(@"Successfully posted a message.");
                } failure:^(NSError *error) {
                    NSLog(@"Failed to post a message, error: %@", error);
                }];
1
2
3
4
5
6
7
8
let messageContent = GetSocialActivityPostContent()
messageContent.text = "Hi, it's nice to have a separate chat!"

GetSocial.postActivity(messageContent, toFeed: "chatId", success: { (post : GetSocialActivityPost) in
    print("Successfully posted a message.")
}) { (error : Error) in
    print("Failed to post a message, error: \(error.localizedDescription)")
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var feedId = GenerateChatId(new[] {GetSocial.User.Id, Receiver.Id});

var messageContentBuilder = ActivityPostContent.CreateBuilder();
messageContentBuilder.WithText("Hi, it's nice to have a separate chat!");

GetSocial.PostActivityToFeed(feedId, messageContentBuilder.Build(), post => { 
    Debug.Log("Successfully posted a message.");
}, error => {
    Debug.Log(Failed to post a message, error: " + error);
});

5. Notify recipient about the message

When you send a message in a chat, a notification for the recipient should be generated. Activity Feeds do not provide this functionality, so you have to send notifications manually using Notifications API.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void sendChatMessageNotification(String messageContent, String recipientId) {
    // Create custom Notification action, so when we receive we can distinguish that this is chat notification
    Action action = Action.builder("open_chat_message")
            .addActionData("open_messages_for_id", GetSocial.User.getId())
            .build();

    NotificationContent notificationContent = NotificationContent
            .notificationWithText(messageContent)
            .withTitle(GetSocial.User.getDisplayName())
            .withAction(action);

    GetSocial.User.sendNotification(Collections.singletonList(recipientId), notificationContent, new Callback<NotificationsSummary>() {
        @Override
        public void onSuccess(NotificationsSummary result) {
            Log.i("GetSocial", "Chat notification sent");
        }

        @Override
        public void onFailure(GetSocialException exception) {
            Log.e("GetSocial", "Failed to send chat notification, error: " + exception.getMessage());
        }
    });
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)sendNotificationForMessage:(NSString *)message recipient: (NSString *) recipientId
{
    // Sender user id to generate chat id on the recipient side
    NSDictionary *messageMetadata = @{@"sender_id" : GetSocialUser.userId};

    // Create custom Notification action, so when we receive we can distinguish that this is chat notification
    GetSocialActionBuilder *action = [[GetSocialActionBuilder alloc] initWithType:@"open_chat_message"];
    [action addActionData:messageMetadata];

    GetSocialNotificationContent *notificationContent = [GetSocialNotificationContent withText:message];
    [notificationContent setTitle:GetSocialUser.displayName];
    [notificationContent setAction:[action build]];

    [GetSocialUser sendNotification:@[ recipientId ]
        withContent:notificationContent
        success:^(GetSocialNotificationsSummary *summary) {
            NSLog(@"Chat notification sent");
        }
        failure:^(NSError *error) {
            NSLog(@"Failed to send chat notifications, error: %@", error);
        }];
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func sendNotification(message: String, recepientId : String) {
    // Sender user id to generate chat id on the recipient side
    let messageMetadata = ["sender_id" : GetSocialUser.userId()]

    // Create custom Notification action, so when we receive we can distinguish that this is chat notification
    let action = GetSocialActionBuilder.init(type: GetSocialActionType(rawValue: "open_chat_message"))
    action.addActionData(messageMetadata)

    let noficiationContent = GetSocialNotificationContent.withText(message)
    noficiationContent.setTitle(GetSocialUser.displayName()!)
    noficiationContent.setAction(action.build())

    GetSocialUser.sendNotification([recepientId], with: noficiationContent, success: { (summary : GetSocialNotificationsSummary) in
        print("Chat notification sent")
    }) { (error : Error) in
        print("Failed to send chat notifications, error: \(error.localizedDescription)")
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
void SendNotification(string message, string recepientId)
{
    var builder = GetSocialAction.CreateBuilder("open_chat_message")
        .AddActionData("sender_id", GetSocial.User.Id);

    var notificationContent = NotificationContent.NotificationWithText(message)
        .WithTitle(GetSocial.User.DisplayName)
        .WithAction(builder.Build());

    var recepients = new List<string> { recepientId };

    GetSocial.User.SendNotification(recepients, notificationContent, summary => 
    {
        Debug.Log("Chat notification sent");
    }, error => 
    {
        Debug.Log("Failed to send chat notifications, error: " + error);
    });
}

6. Handle incoming notification

To enable behavior, like opening your chat view, it’s essential to set up listener, where you can receive notifications.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
GetSocial.setNotificationListener(new NotificationListener() {
    public boolean onNotificationReceived(Notification notification, boolean wasClicked) {
        if ("open_chat_message".equals(notification.getAction().getType())) {
            String senderId = action.getData().get("sender_id");

            if (wasClicked) {
                // Show chat UI for Activity Feed with id chatId if notification was clicked by user
                showChatWithUser(senderId);
            } else {
                // you can check here if chat is open now with the user and append a message to the chat
                if (hasChatOpenWithUser(senderId)) {
                    appendMessageToChat(notification.getText());
                }
            }
            return true;
        }

        return false;
    }
});
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[GetSocial setNotificationHandler:^BOOL(GetSocialNotification *notification, BOOL wasClicked) {
    if ([@"open_chat_message" isEqualToString:notification.notificationAction.type]) {
        NSString *senderId = notification.notificationAction.data[@"sender_id"];

        if (wasClicked) {
            // Show chat UI for Activity Feed with id chatId if notification was clicked by user
            [self showChatWithUser:senderId];
        } else {
            // you can check here if chat is open now with the user and append a message to the chat
            if ([self hasChatOpenWithUser:senderId]) {
                [self appendMessageToChat:notification.text];
            }
        }

        return YES;
    }

    return NO;
}];
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
GetSocial.setNotificationHandler { (notification: GetSocialNotification, wasClicked : Bool) -> Bool in
    if ("open_chat_message" == notification.notificationAction.type.rawValue) {
        let senderId = notification.notificationAction.data[GetSocialActionDataKey(rawValue: "sender_id")]!
        if (wasClicked) {
            // Show chat UI for Activity Feed with id chatId if notification was clicked by user
            self.showChatWithUser(senderId);
        } else {
            // you can check here if chat is open now with user and append message to the chat
            if (self.hasChatOpenWithUser(senderId)) {
                self.appendMessageToChat(notification.text);
            }
        }
        return true
    }
    return false
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
GetSocial.SetNotificationListener((notification, wasClicked) =>
{
    if (notification.NotificationAction.Type.Equals("open_chat_message"))
    {
        var senderId = notification.NotificationAction.Data["sender_id"];
        if (wasClicked) 
        {
            // Show chat UI for Activity Feed with id chatId if notification was clicked by user
            ShowChatWithUser(senderId);
        } else
        {
            // you can check here if chat is open now with user and append message to the chat
            if (HasChatOpenWithUser(senderId))
            {
                AppendMessageToChat(notification.Text);
            }
        }

        return true;
    }
});

6. Managing chats on the Dashboard

All user to user chats are visible on the GetSocial Dashboard in the Activity Feed section. You can manage chats, just like any Activity Feed.

The only downside, Activity Feed names contain GetSocial User Ids which are not readable.

Chats on Dashboard

Try it out

Download DevFest Ukraine conference application to check out the user-to-user chat demo.

Try in the app

Also, you can find implementation in our Android, iOS or Unity demo applications on GitHub.

Next steps

Give us your feedback! Was this article helpful?

😀 🙁