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).

```java tab=”Android(Java)”
String generateChatId(String… userIds) {
// Sort to get the same chat id for same participants
Arrays.sort(userIds);

1
2
3
4
5
6
StringBuilder builder = new StringBuilder("chat");
for (String id : userIds) {
    builder.append("_").append(id);
}

return builder.toString();

}
kotlin tab=”Android(Kotlin)”
fun generateChatId(userIds: Array) : String {
// Sort to get the same chat id for same participants
return “chat_${userIds.sorted().joinToString(separator = “_”)}”
}
```

```objc tab=”iOS(Objective-C)”
- (NSString *)chatIdForUsers: (NSArray *) userIds
{
NSArray *sortedIds = [userIds sortedArrayUsingSelector:@selector(compare:)];
NSString *chatId = [sortedIds componentsJoinedByString:@”_”];

1
return [@"chat_" stringByAppendingString:chatId];

}
swift tab=”iOS(Swift)”
func generateChatId(_ userIds : [String]) -> String {
// Sort to get the same chat id for same participants
let chatId = userIds.sorted().joined(separator: “”)

return “chat
(chatId)”
}
```

```csharp tab=”Unity”
private string GenerateChatId(params string[] userIds)
{
// Sort to get the same chat id for same participants
Array.Sort(userIds);

1
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.

java tab="Android(Java)" 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()); } });

```kotlin tab=”Android(Kotlin)”
GetSocial.getActivities(ActivitiesQuery.postsForFeed(chatId), object : Callback>{
override fun onSuccess(activityPostList: List) {
// Reversing list to have resulting posts in right order
val messages = activityPostList.reversed()

1
2
3
4
5
6
7
    // Show messages on the UI
    showMessages(messages)
}

override fun onFailure(exception: GetSocialException) {
    print("Failed to get messages, error: ${exception.message}")
}

})

```objc tab="iOS(Objective-C)"
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);
    }
];

```swift tab=”iOS(Swift)”
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()

1
2
3
4
5
    // Show messages on the UI
    self.showMessages(messages)
}) { (error: Error) in
    print("Failed to get messages, error: \(error.localizedDescription)")
}

csharp tab=”Unity”
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.

```java tab=”Android(Java)”
ActivityPostContent messageContent = ActivityPostContent
.createBuilderWithText(“Hi, it’s nice to have a separate chat!”).build();

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

1
2
3
4
@Override
public void onFailure(GetSocialException e) {
    Log.e("GetSocial", "Posting failed, error: " + e.getMessage());
}

});
kotlin tab=”Android(Kotlin)”
val messageContent = ActivityPostContent
.createBuilderWithText(“Hi, it’s nice to have a separate chat!”).build()
GetSocial.postActivityToFeed(chatId, messageContent, object: Callback{
override fun onSuccess(chatMessage: ActivityPost) {
print(“Successfully posted a message.”)
}

override fun onFailure(exception: GetSocialException) {
print(“Failed to post a message, error: ${exception.message}”)
}

})
```

```objc tab=”iOS(Objective-C)”
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);
}];

```swift tab="iOS(Swift)"
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)")
}

```csharp tab=”Unity”
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.  

```java tab="Android(Java)"
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());
        }
    });
}

```kotlin tab=”Android(Kotlin)”
private fun sendChatMessageNotification(messageContent: String, recipientId: String) {
// Create custom Notification action, so when we receive we can distinguish that this is chat notification
val action = Action.builder(“open_chat_message”)
.addActionData(“open_messages_for_id”, GetSocial.User.getId())
.build()
val notificationContent = NotificationContent
.notificationWithText(messageContent)
.withTitle(GetSocial.User.getDisplayName())
.withAction(action)
GetSocial.User.sendNotification(listOf(recepientId), notificationContent
, object : Callback {
override fun onSuccess(summary: NotificationsSummary) {
print(“Chat notification sent”)
}

1
2
3
4
        override fun onFailure(exception: GetSocialException) {
            print("Failed to send chat notifications, error: ${exception.message}")
        }
    })

}
objc tab=”iOS(Objective-C)”
- (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);
}];
}
```

```swift tab=”iOS(Swift)”
func sendNotification(message: String, recipientId : String) {
// Sender user id to generate chat id on the recipient side
let messageMetadata = [“sender_id” : GetSocialUser.userId()]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 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)")
}

}
csharp tab=”Unity”
void SendNotification(string message, string recipientId)
{
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 { 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.

```java tab=”Android(Java)”
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”);

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
        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;
}

});
kotlin tab=”Android(Kotlin)”
GetSocial.setNotificationListener { notification, wasClicked ->
if (“open_chat_message”.equals(notification.action.type)) {
val senderId = notification.action.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 the user and append a message to the chat
if (hasChatOpenWithUser(senderId)) {
appendMessageToChat(notification.getText())
}
}
return@setNotificationListener true
}
false
}
```

```objc tab=”iOS(Objective-C)”
[GetSocial setNotificationHandler:^BOOL(GetSocialNotification *notification, BOOL wasClicked) {
if ([@”open_chat_message” isEqualToString:notification.notificationAction.type]) {
NSString *senderId = notification.notificationAction.data[@”sender_id”];

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    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;

}];
swift tab=”iOS(Swift)”
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
}
```

```csharp tab=”Unity”
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);
}
}

1
2
    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?

😀 🙁