Chat

Ask tech team
From QuickBlox Developers (API docs, code samples, SDK)
Jump to: navigation, search

Contents

Introduction

QuickBlox Chat is a quick and reliable chat solution which combines benefits of scalable cloud hosted XMPP chat server, seamless Single Sign-On authorization via Users, incoming IM / chat alerts via Push Notifications and file attachments via Content.

SDKs and code samples are available for iOS, Android, Windows Phone, BlackBerry 5-7 and BB10, also Web (including Facebook and Wordpress) and desktop – QuickBlox Chat is the best and most comprehensive solution so far to have your users communicate cross-platform.

Features

Robust, quick, ‘keep-alive’ connection. Unlimited concurrent connections thanks to QuickBlox auto-scalable AWS powered cloud chat servers infrastructure.

  • 1:1 chat (private user to user chat / IM)
  • Group chat (unlimited chat rooms)
  • Incoming chat alerts (push notifications) for offline users (via Messages)
  • File attachments - cloud hosted via Content so both users don’t have to be online for the transfer to take place. XMPP p2p file transfers are also supported. Allow users to send photos, videos and other files.
  • Location based chat – integrated with Location, have your users chat over map (Google Map, Apple maps, Bing) and see distance to each other, hide or share their location, see internal or Facebook check-ins of other users, manage POIs
  • Photos / Avatars – have users’ Facebook, Linkedin or custom profile photos next to their chat messages
  • Quoting – display citations in chat room replies
  • AR chat – chat in Augmented Reality view
  • Voice chat / call – enable 1:1 voice calls in your app
  • Video chat / call – best video chat SDK for your app
  • Video chat recording – record your video calling session
  • NAT traversal – our TURN server and optimization system take care of NAT traversal and traffic compression making sure your chat, voice and video traffic reaches all users across networks with different configurations
  • 1:1 chat history (Chat-to-CustomObjects plugin)

Connecting to server

Note: these settings are already integrated into iOS/Android/Web SDKs and code samples so you may ignore this section if you’re iOS/Android/Web developer.

Server

Main server: chat.quickblox.com.

MUC (Multi Users Chat): muc.chat.quickblox.com. Important: users registration, authentication and removal must be done via Users API (and not XMPP). 


Login / ID

Each user gets a JID (Jabber ID) in the following format:


<user_id>-<app_id>@chat.quickblox.com

Note: JID is assigned automatically provided users has authenticated at least once in the context of this application. Also note that users will have different JIDs for different apps. For example, user freddy (user_id = 128) chats in both Gunslinger (application_id = 44) and Shoot-a-Zombie (application_id = 78), he will get the following JIDs: 128-44@chat.quickblox.com, 128-78@chat.quickblox.com.

Password

Your user’s password for XMPP connection depends on what type of user authentication via Users you have applied for this particular user:

  • standard login+password authentication: use same password
  • Facebook/Twitter authentication: use session token as password:
QBUUser *user = [QBUUser user];
user.ID = 47892;
user.password = [QBBaseModule sharedModule].token;
QBUser user = new QBUser();
user.setId(47892);
try {
    user.setPassword(BaseService.getBaseService().getToken());
}catch(BaseServiceException e) {
    e.printStackTrace();  
    // means you have not created a session before 
}

Group chat

Room naming convention

To support namespaces you have to use App_ID in room's JID (Jabber ID), for example:

<app_id>_footballfans@muc.chat.quickblox.com

where footballfans is a room name

User nick

Use userID as a nickname.

XMPP features supported

All standard XMPP libraries are supported (please check the list here http://xmpp.org/xmpp-software/libraries/). All standard XEPs and the following additional ones (below) are supported:


XEP-0095 & XEP-0096 are not supported, instead QuickBlox own TURN server takes care of NAT traversal for voice and video traffic streaming.

Chat 2.0

Overview

QuickBlox provides a new way to integration Chat communication features into your application. We call it Chat 2.0.

We processed all users’ feedback and developed new Chat module which works out of out box and provides all the features users need.

Pre-Requirements

In order to start using Chat 2.0, you should know the following:

  1. This feature will be available on the Starter tier for free users for a limited time, after which point some features will be moved to the Advanced plan - and only Advanced plan subscribers will be able to use all of the new Chat 2.0 features.

  2. Chat messages won't be saved to chat history by default - this is an optional setting. If you want to save messages to the server-side - add the save_to_history parameter to your XMPP chat messages:

Server-side chat history

Chat 2.0 introduces a very simple server-side chat history functionality. This features is useful for many cases such as moderation, restoring messages on a new device via REST, making chat logs be easily downloadable, etc. We (Quickblox) are not able to read your messages - only you, as the account owner, have access to them.

Just by adding a few custom parameters to your XMPP messages, the messages will be stored on the server (in a Custom Objects like format). Please note that by using Chat 2.0, you are not automatically storing your messages. See below for how to enable server-side chat history in the iOS and Android SDK.

QBChatMessage *message = [QBChatMessage message];
...
[message setCustomParameters:@{@"save_to_history": @YES}];
...
QBChatMessage chatMessage = new QBChatMessage();
...
chatMessage.setProperty("save_to_history", "1");
...

The correctly formatted XML message will look something like this:

<message id="1114269126" to="11492_53fc460b515c128132016675@muc.chat.quickblox.com" type="groupchat">
	<body xmlns="jabber:client">This is the message text!</body>
	<extraParams xmlns="jabber:client">
		<save_to_history>1</save_to_history>
		<date_sent>1409146118</date_sent>
	</extraParams>
</message>

You'll notice there's also a date_sent field in the extra parameters. This is optional - if you don't supply it, the server will automatically add it when it receives the message. But if for example, you need to "resend" a message that failed, you can use this field to specify the correct time. It is in a unix timestamp format.

You can then view this history in the dashboard, or you can retrieve messages via the REST API.

SDK

  • iOS SDK - Chat 2.0 is available starting from iOS SDK 1.9.1
  • Android SDK - will be available in the middle of the August, but it's possible to use Q-municate, open source code of a chat application which uses Chat 2.0
  • Javascript SDK - will be available in late-August along with the release of Q-municate for Web.

REST API

Chat REST API provides an access to Chat history. We operate with 2 models: Chat Dialog and Chat Message.

Dialog model

Chat Dialog model describes a dialog entity between users (1-1 chat or group chat).

Fields:

Field name Type Description Value Example
_id ObjectID ID of dialog. Generated automatically by server after dialog creation 53a1be95e4b08a80c999dccd
type Enum Type of dialog. Possible values: 1(PUBLIC_GROUP), 2(GROUP), 3(PRIVATE) 2
name String Name of a group chat. Make sense if type=1(PUBLIC_GROUP) or 2(GROUP) Chat with Bob, Sam, Garry
photo String Photo of a group chat. Make sense if type=1(PUBLIC_GROUP) or 2(GROUP). Can contain a link to a file in Content module, Custom Objects module or just a web link 454533
xmpp_room_jid String JID of XMPP room for group chat to connect. Nil if type=3(PRIVATE). Generated automatically by server after dialog creation 92_53a1bdaf535c12eae7000dd1
@muc.chat.quickblox.com
occupants_ids Array of UInteger Array of users' IDs - dialog occupants. Does not make sense if type=1(PUBLIC_GROUP) 44,7893,4567
last_message String Last sent message in this dialog Is anybody here?
last_message_date_sent Timestamp Timestamp of last sent message in this dialog 1403174078
last_message_user_id UInteger ID of user who sent last message in this dialog 45643
unread_messages_count Integer Number of unread messages in this dialog for current user. 12

Message model

Chat Message model describes a chat message in a dialog

Fields:

Field name Type Description Value Example
_id ObjectID ID of message. Generated automatically by server after message creation 43a1be9554b08a87c999d8cd
chat_dialog_id ObjectID ID of dialog to which current message is connected. Generated automatically by server after message creation 63a18e95e4308a80c993dccd
message String Message body Is anybody here?
date_sent Timestamp Message date sent 1403174078
sender_id UInteger Message sender ID 564444
recipient_id UInteger Message recipient ID 39572
read Boolean Flag which indicates was this message read or not by current user 1
attachments Array of attachments objects Each attachment object contains 3 keys:type(audio/video/image), id(link to file ID in QuickBlox), url(link to file in Internet) [{"type":"video","id":"12312"},{"type":"audio","url":"http://mysite.com/audio.wav"}]
Custom parameters Key-value Chat message can contain any other user custom parameters age=25

API requests

URL HTTP Verb Action Description Success HTTP Status Code
/chat/Dialog GET Retrieve dialogs 200
/chat/Dialog POST Create dialog 201
/chat/Dialog/{id} PUT Update dialog 200
/chat/Message GET Retrieve messages 200
/chat/Message POST Create message 201
/chat/Message/{id1},{id2},{id3}...?chat_dialog_id={id} PUT Update message 200
/chat/Message/{id1} DELETE Delete message 200

Retrieve dialogs

Get all dialogs associated with current user. Server will return all dialogs where current user id is in occupants_ids field OR if type=1(PUBLIC_GROUP). To detect current user id server uses session token.

Parameters
Operator Applied fields Description Usage example
{field_name} all Search records with field which contains exactly specified value type=2
{field_name}[{search_operator}] all Search record with field which contains value according to specified value and operator.

Possible filters: lt, lte, gt, gte, ne, in, nin, all, or, ctn
type[in]=1,2
limit standalone operator Limit search results to N records. Useful for pagination. Default value - 100 limit=50
skip standalone operator Skip N records in search results. Useful for pagination. Default (if not specified): 0 skip=50
count standalone operator Count search results. Response will contain only count of records found count=1
sort_desc/sort_asc type,last_message_date_sent Search results will be sorted by specified field in ascending/descending order sort_desc=last_message_date_sent
Request
curl -X GET -H "QB-Token: 4d617908bf432bd0a72e2e089ed500e76a2c1a3b" https://api.quickblox.com/chat/Dialog
curl -X GET -H "QB-Token: 4d617908bf432bd0a72e2e089ed500e76a2c1a3b" https://api.quickblox.com/chat/Dialog.json
NSMutableDictionary *extendedRequest = [NSMutableDictionary new];
extendedRequest[@"limit"] = @(100);
//extendedRequest[@"skip"] = @(100);
 
[QBChat dialogsWithExtendedRequest:extendedRequest delegate:self];
QBCustomObjectRequestBuilder customObjectRequestBuilder = new QBCustomObjectRequestBuilder();
customObjectRequestBuilder.setPagesLimit(100);
 
QBChatService.getChatDialogs(null, customObjectRequestBuilder, this);
Response
<?xml version="1.0" encoding="UTF-8"?>
<chat_dialogs type="array">
  <chat_dialog>
    <_id>53a2bd40e4b0ffe278f44a66</_id>
    <last_message>Is anybody here?</last_message>
    <last_message_date_sent type="integer">1403606412</last_message_date_sent>
    <last_message_user_id type="integer">299</last_message_user_id>
    <name nil="true"/>
    <photo nil="true"/>
    <occupants_ids type="array">
      <occupants_id type="integer">298</occupants_id>
      <occupants_id type="integer">299</occupants_id>
    </occupants_ids>
    <type type="integer">3</type>
    <xmpp_room_jid nil="true"/>
    <unread_messages_count type="integer">0</unread_messages_count>
  </chat_dialog>
  <chat_dialog>
    <_id>53a1be95e4b08a80c999dccd</_id>
    <last_message>Hey guys!</last_message>
    <last_message_date_sent type="integer">1403550532</last_message_date_sent>
    <last_message_user_id type="integer">299</last_message_user_id>
    <name>Chat with Sam, Bob, Garry</name>
    <photo>567681</photo>
    <occupants_ids type="array">
      <occupants_id type="integer">299</occupants_id>
      <occupants_id type="integer">3105</occupants_id>
      <occupants_id type="integer">290</occupants_id>
    </occupants_ids>
    <type type="integer">2</type>
    <xmpp_room_jid>92_53a970c5535c123fed00053b@muc.chat.quickblox.com</xmpp_room_jid>
    <unread_messages_count type="integer">5</unread_messages_count>
  </chat_dialog>
</chat_dialogs>
{ 
    "limit" : 100,
    "skip" : 0
    "items" : [ 
     { 
         "_id" : "53a2bd40e4b0ffe278f44a66",
         "last_message" : "Is anybody here?",
         "last_message_date_sent" : 1403606412,
         "last_message_user_id" : 299,
         "name" : null,
         "photo" : null,
         "occupants_ids" : [ 
            298,
            299
         ],
         "type" : 3,
         "unread_messages_count" : 0,
         "xmpp_room_jid" : null
      },
      { "_id" : "53a970c5535c123fed00053b",
        "last_message" : "Hey guys!",
        "last_message_date_sent" : "1403550532",
        "last_message_user_id" : 299,
        "name" : "Chat with Sam, Bob, Garry",
        "photo" : "567681",
        "occupants_ids" : [ 
            290,
            299,
            3105
         ],
        "type" : 2,
        "unread_messages_count" : 5,
        "xmpp_room_jid" : "92_53a970c5535c123fed00053b@muc.chat.quickblox.com"
      }
    ]
}
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:[QBDialogsPagedResult class]]) {
        QBDialogsPagedResult *pagedResult = (QBDialogsPagedResult *)result;
        NSArray *dialogs = pagedResult.dialogs;
        NSLog(@"Dialogs: %@", dialogs);
    }
}
@Override
public void onSuccess(ArrayList<QBDialog> result, Bundle args) {
    // do something with result
}
 
@Override
public void onError(List<String errors){
    // do something with errors
}

Create dialog

Create a dialog.

Use type=1(PUBLIC_GROUP) to create a public group dialog. All the users from your application will be able to join it. Server will create a public group chat and return a detailed information about newly created dialog. Field xmpp_room_jid will contain a Chat room JID to which you should connect to start chatting.

Use type=2(GROUP) to create a group dialog only for specific users provided in occupants_ids. Server will create an only members group chat and return a detailed information about newly created dialog. Field xmpp_room_jid will contain a Chat room JID to which you should connect to start chatting.

Use type=3(PRIVATE) to create a private dialog between 2 users. Server will return a detailed information about newly created dialog. If user sends a chat message to some user and private dialog wasn't created - it will be created automatically with 1st chat message.

Parameters
Parameter Required Description Usage example
type yes Type of new dialog. Possible values: 1(PUBLIC_GROUP), 2(GROUP) or 3(PRIVATE) type=2
occupants_ids yes if type=2(GROUP) or 3(PRIVATE) IDs of dialog occupants - users, who will be able to chat in this dialog. Don't need to pass current user ID - it will be added automatically occupants_ids=56,558,12334
name no Name of a new dialog. Ignored when type=3(PRIVATE) name=Chat with Bob, Sam, Garry
photo no Photo of a new dialog. Ignored when type=3(PRIVATE) photo=67834
Request
curl -X POST \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d "type=2&name=Chat with Bob, Sam, Garry&occupants_ids=55,678,22" \
https://api.quickblox.com/chat/Dialog
curl -X POST \
-H "Content-Type: application/json" \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d '{"type": 2, "name": "Chat with Bob, Sam, Garry", "occupants_ids": "55,678,22"}' \
https://api.quickblox.com/chat/Dialog.json
QBChatDialog *chatDialog = [QBChatDialog new];
chatDialog.name = @"Chat with Bob, Sam, Garry";
chatDialog.occupantIDs = @[@(55), @(678), @(22)];
chatDialog.type = QBChatDialogTypeGroup;
 
[QBChat createDialog:chatDialog delegate:self];
ArrayList<Integer> occupantIdsList = new ArrayList<Integer>();
occupantIdsList.add(55);
occupantIdsList.add(678);
occupantIdsList.add(22);
 
QBRoomChatManager roomChatManager = QBChatService.getInstance().getRoomChatManager();
roomChatManager.createDialog("Chat with Bob, Sam, Garry", QBDialogType.GROUP, occupantIdsList, this);
Response
<?xml version="1.0" encoding="UTF-8"?>
<chat_dialog>
  <_id>53aaa06f535c12cea9007496</_id>
  <last_message nil="true"/>
  <last_message_date_sent nil="true"/>
  <last_message_user_id nil="true"/>
  <name>Chat with Bob, Sam, Garry</name>
  <photo nil="true"/>
  <occupants_ids type="array">
    <occupants_id type="integer">55</occupants_id>
    <occupants_id type="integer">678</occupants_id>
    <occupants_id type="integer">22</occupants_id>
  </occupants_ids>
  <type type="integer">2</type>
  <xmpp_room_jid>92_53aaa06f535c12cea9007496@muc.chat.quickblox.com</xmpp_room_jid>
  <unread_messages_count type="integer">0</unread_messages_count>
</chat_dialog>
{
  "_id": "53aaa06f535c12cea9007496",
  "last_message": null,
  "last_message_date_sent": null,
  "last_message_user_id": null,
  "name": "Chat with Bob, Sam, Garry",
  "photo": null,
  "occupants_ids": [
    55,
    678,
    22
  ],
  "type": 2,
  "xmpp_room_jid": "92_53aaa06f535c12cea9007496@muc.chat.quickblox.com",
  "unread_messages_count": 0
}
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:[QBChatDialogResult class]]) {
        QBChatDialogResult *res = (QBChatDialogResult *)result;
        NSLog(@"Dilog: %@", res.dialog);
    }
}
@Override
public void onSuccess(QBDialog dialog, Bundle args) {
    // do something with dialog
}
 
@Override
public void onError(List<String> errors) {
    // do something with errors
}

Update dialog

Update a dialog. Works only if type=1(PUBLIC_GROUP) or 2(GROUP).

Users who are in occupants_ids can update a dialog with type=2(GROUP). If type=1(PUBLIC_GROUP) - only dialog’s owner can update it.

Fields to update
Field Available operators Description Usage example
occupants_ids pull_all,push_all Update dialog occupants.

Use push_all operator to add new occupants.
Use pull_all to remove occupants
push_all[occupants_ids][]=55,56

pull_all[occupants_ids][]=22,23
name Name of a new dialog name=Chat with Garry and John
Request
curl -X PUT \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d "name=Chat with Garry and John, Garry&pull_all[occupants_ids][]=22" \
https://api.quickblox.com/chat/Dialog/53aac0cd535c12b50600962c
curl -X PUT \
-H "Content-Type: application/json" \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d '{"name": "Chat with Garry and John", "pull_all": {"occupants_ids": [22]}}' \
https://api.quickblox.com/chat/Dialog/53aac0cd535c12b50600962c.json
NSMutableDictionary *extendedRequest = [NSMutableDictionary new];
extendedRequest[@"pull_all[occupants_ids][]"] = @"22";
extendedRequest[@"name"] = @"Chat with Garry and John";
 
[QBChat updateDialogWithID:@"53aac0cd535c12b50600962c" extendedRequest:extendedRequest delegate:self];
QBCustomObjectUpdateBuilder requestBuilder = new QBCustomObjectUpdateBuilder();
requestBuilder.pullAll(com.quickblox.internal.module.chat.Consts.DIALOG_OCCUPANTS, 22);
//
QBRoomChatManager roomChatManager = QBChatService.getInstance().getRoomChatManager();
roomChatManager.updateDialog("53aac0cd535c12b50600962c", "Chat with Garry and John", requestBuilder, this);
Response
<?xml version="1.0" encoding="UTF-8"?>
<chat_dialog>
  <_id>53aac0cd535c12b50600962c</_id>
  <last_message nil="true"/>
  <last_message_date_sent nil="true"/>
  <last_message_user_id nil="true"/>
  <name>Chat with Bob, Sam, Garry</name>
  <photo nil="true"/>
  <occupants_ids type="array">
    <occupants_id type="integer">55</occupants_id>
    <occupants_id type="integer">678</occupants_id>
  </occupants_ids>
  <type type="integer">2</type>
  <xmpp_room_jid>92_53aac0cd535c12b50600962c@muc.chat.quickblox.com</xmpp_room_jid>
  <unread_messages_count type="integer">0</unread_messages_count>
</chat_dialog>
{
  "_id": "53aac0cd535c12b50600962c",
  "last_message": null,
  "last_message_date_sent": null,
  "last_message_user_id": null,
  "name": "Chat with Bob, Sam, Garry",
  "photo": null,
  "occupants_ids": [
    55,
    678,
  ],
  "type": 2,
  "xmpp_room_jid": "92_53aac0cd535c12b50600962c@muc.chat.quickblox.com",
  "unread_messages_count": 0
}
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:[QBChatDialogResult class]]) {
        QBChatDialogResult *res = (QBChatDialogResult *)result;
        NSLog(@"Dilog: %@", res.dialog);
    }
}
@Override
public void onSuccess(QBDialog dialog, Bundle args) {
    // do something with dialog
}
 
@Override
public void onError(List<String> errors) {
    // do something with errors
}

Retrieve messages

Retrieve all chat messages within particular dialog. It's only possible to read chat messages in dialog if current user id is in occupants_ids field or if dialog's type=1(PUBLIC_GROUP). Server will return dialog's chat messages sorted descending by date_sent field.

All retrieved chat messages will be marked as read after request.

Parameters
Operator Applied fields Description Usage example
{field_name} all + subfields for attachments: attachments.type, attachments.id, attachments.url, Search records with field which contains exactly specified value sender_id=2960
{field_name}[{search_operator}] all except chat_dialog_id, attachments Search record with field which contains value according to specified value and operator.

Possible filters: lt, lte, gt, gte, ne, in, nin, all, or, ctn
sender_id[in]=134,2566
limit standalone operator Limit search results to N records. Useful for pagination. Default value - 100 limit=50
skip standalone operator Skip N records in search results. Useful for pagination. Default (if not specified): 0 skip=50
count standalone operator Count search results. Response will contain only count of records found count=1
sort_desc/sort_asc date_sent Search results will be sorted by specified field in ascending/descending order sort_desc=date_sent
Request
curl -X GET -H "QB-Token: 4d617908bf432bd0a72e2e089ed500e76a2c1a3b" \
https://api.quickblox.com/chat/Message?chat_dialog_id=53aadc78535c127f15009b6c
curl -X GET -H "QB-Token: 4d617908bf432bd0a72e2e089ed500e76a2c1a3b" \
https://api.quickblox.com/chat/Message.json?chat_dialog_id=53aadc78535c127f15009b6c
NSMutableDictionary *extendedRequest = [NSMutableDictionary new];
extendedRequest[@"limit"] = @(100);
 
[QBChat messagesWithDialogID:@"53aadc78535c127f15009b6c" extendedRequest:extendedRequest delegate:self];
QBDialog qbDialog = new QBDialog("53aadc78535c127f15009b6c");
 
QBCustomObjectRequestBuilder customObjectRequestBuilder = new QBCustomObjectRequestBuilder();
customObjectRequestBuilder.setPagesLimit(100);
 
QBChatService.getDialogMessages(qbDialog, customObjectRequestBuilder, this);
Response
<?xml version="1.0" encoding="UTF-8"?>
<chat_messages type="array">
  <chat_message>
    <_id>53aadcc7e4b077ddd43e804d</_id>
    <attachments type="array"/>
    <chat_dialog_id>53aadc78535c127f15009b6c</chat_dialog_id>
    <date_sent type="integer">1403706567</date_sent>
    <message nil="true"/>
    <recipient_id nil="true"/>
    <sender_id type="integer">298</sender_id>
    <read type="integer">1</read>
  </chat_message>
  <chat_message>
    <_id>53aadcc8e4b077ddd43e804f</_id>
    <attachments type="array"/>
    <chat_dialog_id>53aadc78535c127f15009b6c</chat_dialog_id>
    <date_sent type="integer">1403706568</date_sent>
    <message nil="true"/>
    <recipient_id nil="true"/>
    <sender_id type="integer">298</sender_id>
    <read type="integer">1</read>
  </chat_message>
  <chat_message>
    <_id>53aadcd0e4b077ddd43e8051</_id>
    <attachments type="array"/>
    <chat_dialog_id>53aadc78535c127f15009b6c</chat_dialog_id>
    <date_sent type="integer">1403706577</date_sent>
    <message nil="true"/>
    <recipient_id nil="true"/>
    <sender_id type="integer">298</sender_id>
    <read type="integer">1</read>
  </chat_message>
</chat_messages>
{
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "_id": "53aadcc7e4b077ddd43e804d",
      "attachments": [
 
      ],
      "chat_dialog_id": "53aadc78535c127f15009b6c",
      "date_sent": 1403706567,
      "message": null,
      "recipient_id": null,
      "sender_id": 298,
      "read": 1
    },
    {
      "_id": "53aadcc8e4b077ddd43e804f",
      "attachments": [
 
      ],
      "chat_dialog_id": "53aadc78535c127f15009b6c",
      "date_sent": 1403706568,
      "message": null,
      "recipient_id": null,
      "sender_id": 298,
      "read": 1
    },
    {
      "_id": "53aadcd0e4b077ddd43e8051",
      "attachments": [
 
      ],
      "chat_dialog_id": "53aadc78535c127f15009b6c",
      "date_sent": 1403706577,
      "message": null,
      "recipient_id": null,
      "sender_id": 298,
      "read": 1
    }
  ]
}
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:QBChatHistoryMessageResult.class]) {
        QBChatHistoryMessageResult *res = (QBChatHistoryMessageResult *)result;
        NSArray *messages = res.messages;
        NSLog(@"Messages: %@", messages);
    }
}
@Override
public void onSuccess(ArrayList<QBHistoryMessage> result, Bundle args) {
    // do something with result
}
 
@Override
public void onError(List<String errors){
    // do something with errors
}

Create message

Create a chat message. It’s possible to inject a new chat message to the chat history. In this case this new message won't be delivered to the recipient(s) by XMPP real time transport, it will be just added to the history.


Fields to set
Parameter Required Description Usage example
chat_dialog_id yes ID of a dialog to which this messages will be added chat_dialog_id=53db8798535c125e8e000902
message no text of the message (CGI-escaped) message=hello!
recipient_id no ID of a recipient. Useful only when dialog's type=3(PRIVATE) recipient_id=4124234
attachments[n][type/id/url] no Array of attachments objects. Each attachment object contains 3 keys:type(audio/video/image), id(link to file ID in QuickBlox), url(link to file in Internet) attachments[0][id]=47863&attachments[0][type]=image&attachments[1][url]=www.mysite.com/image.png&attachments[1][type]=image
Custom parameters no Key-value parameters. Chat message can contain any other custom parameters age=25
Request
curl -X POST \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d "chat_dialog_id=53a99a7be4b094c7c6d31b41&message=hello!&recipient_id=343&attachments[0][id]=47863&attachments[0][type]=image&age=25" \
https://api.quickblox.com/chat/Message.xml
curl -X POST \
-H "Content-Type: application/json" \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d '{"chat_dialog_id": "53a99a7be4b094c7c6d31b41", "message": "hello!", "recipient_id": 343,"attachments": [ {"type": "image", "id": "47863"}, {"type": "image", "id": "47863"} ], "age": "25"}' \
https://api.quickblox.com/chat/Message.json
-will be available in the nearest release-
-will be available in the nearest release-
Response
<chat_message>
  <_id>53e89d53535c127839025970</_id>
  <age>25</age>
  <attachments type="array">
    <attachment>
      <id>47863</id>
      <type>image</type>
    </attachment>
  </attachments>
  <chat_dialog_id>53a99a7be4b094c7c6d31b41</chat_dialog_id>
  <date_sent type="integer">1407753555</date_sent>
  <message>hello!</message>
  <recipient_id type="integer">343</recipient_id>
  <sender_id type="integer">1279282</sender_id>
</chat_message>
{
    "_id":"53e8a3a4535c1242aa0270b9",
    "age":"25",
    "attachments":[{"id":"47863","type":"image"}],
    "chat_dialog_id":"53db8798535c125e8e000902",
    "date_sent":1407755172,
    "message":"hello!",
    "recipient_id":343,
    "sender_id":1279282
}
-will be available in the nearest release-
-will be available in the nearest release-

Update message

Update chat message. It’s possible only to mark messages as read. Update other fields isn’t possible at this stage.


Fields to update
Field Description Usage example
read Mark message as read read=1
Request
curl -X PUT \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d "read=1&chat_dialog_id=53a99a7be4b094c7c6d31b41" \
https://api.quickblox.com/chat/Message/53aabe15e4b077ddd43e7fd3.xml
curl -X PUT \
-H "Content-Type: application/json" \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
-d '{"read": "1", "chat_dialog_id": "53a99a7be4b094c7c6d31b41"}' \
https://api.quickblox.com/chat/Message/53aabe15e4b077ddd43e7fd3.json
QBChatHistoryMessage *message = [QBChatHistoryMessage new];
message.ID = @"53aabe15e4b077ddd43e7fd3";
message.dialogID = @"53a99a7be4b094c7c6d31b41";
message.read = YES;
 
[QBChat updateMessage:message delegate:self];
-will be available in the nearest release-
Response
Status 200 OK
Status 200 OK
- (void)completedWithResult:(Result *)result{
    if (result.success) {
        NSLog(@"done");
    }
}
-will be available in the nearest release-

Delete message

Remove chat message.

Each user from dialog’s occupant_ids field can remove message from this dialog. This doesn’t mean that this message will be removed completely for all the users in this dialog. It will be removed only for current user.

Request
curl -X DELETE \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
https://api.quickblox.com/chat/Message/53aabe15e4b077ddd43e7fd3.xml
curl -X DELETE \
-H "Content-Type: application/json" \
-H "QB-Token: eddf864695d72d33b959eec2ae6c640d817dfada" \
https://api.quickblox.com/chat/Message/53aabe15e4b077ddd43e7fd3.json
[QBChat deleteMessageWithID:@"53a04938e4b0afa821474844" delegate:self];
-will be available in the nearest release-
Response
Status 200 OK
Status 200 OK
- (void)completedWithResult:(Result *)result{
    if (result.success) {
        NSLog(@"done");
    }
}
-will be available in the nearest release-


Dashboard

Chat 2.0 provides a really powerful way to manage Chat history in Dashboard. Go to admin panel, Chat module. There are 2 new tabs: Dialogs and Alerts.

Dialogs

Dialogs tab contains all dialogs in your application, with next columns:

  • id - ID of a dialog
  • type - Type of a dialog: PRIVATE, GROUP or PUBLIC GROUP
  • name - Name of a dialog
  • occupants ids - Users IDs who chat in this dialog
  • last message - Latest sent message in this dialog
  • last message user id - ID of User who sent latest message in this dialog
  • room_jid - JID of XMPP room for group chat to connect. Empty if type is PRIVATE
  • last message date sent - Timestamp of latest sent message in this dialog
  • history - link to chat history for this dialog


Chat2.0 dialogs.png

You can create new dialog here or update existing one. To edit dialog just click on dialog's ID - popup with dialog's info will appear. To create a new dialog click on New Dialog button, New Dialog popup will appear:

Chat2.0 dialogs new.png

Enter name, choose type and set occupants for this group. Then click Create button - newly created dialog will be added to the dialogs list.

History

By clicking history link in each dialog you can view chat messages in this dialog:

Chat2.0 messages.png


There are next columns:

  • message - chat message body
  • Sender Id - User who sent message
  • Recipient Id - User who received message
  • Attachments - Information about message attachments
  • Custom parameters - Message custom parameters
  • Date sent - Date sent of message


You can use Search box to filter messages.

Alerts

Alerts tab allows you to setup automatic push notifications for offline user. It means if your opponent is offline while you writing a message - he can automatically receive push notification.

Chat2.0 alerts.png


There are next settings:

  • Alert text - text of your push notification
  • Environment - set Push Notifications environment here
  • Templates - set push notification template here. Use template variables to engage your push message
  • Badge counter - set badge counter to include a counter info into your push message. Useful to include unread counter - number of unread messages user has
  • Sound - set push notification sound (for iOS only)


Use cases

Retrieve all chats

Here is how typical screen with all your chats looks like:

Chat2.0 chatslist.png

Request Dialogs each time user logins to app, use Retrieve Dialogs request:

NSMutableDictionary *extendedRequest = [NSMutableDictionary new];
extendedRequest[@"limit"] = @(100);
//extendedRequest[@"skip"] = @(100);
 
[QBChat dialogsWithExtendedRequest:extendedRequest delegate:self];
 
 
#pragma mark -
#pragma mark QBActionStatusDelegate
 
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:[QBDialogsPagedResult class]]) {
        QBDialogsPagedResult *pagedResult = (QBDialogsPagedResult *)result;
        NSArray *dialogs = pagedResult.dialogs;
        NSLog(@"Dialogs: %@", dialogs);
    }
}
QBCustomObjectRequestBuilder customObjectRequestBuilder = new QBCustomObjectRequestBuilder();
customObjectRequestBuilder.setPagesLimit(100);
 
QBChatService.getChatDialogs(null, customObjectRequestBuilder, new QBEntityCallbackImpl<ArrayList<QBDialog>>() {
    @Override
    public void onSuccess(ArrayList<QBDialog> dialogs, Bundle args) {
        Log.i(TAG, "dialogs: " + dialogs);
    }
 
    @Override
    public void onError(List<String> errors) {
        // handle errors
    }
});

Create new chat

According to REST API, Create a dialog query, you don't need to create a dialog for 1-1(private) chat - it will be created automatically with 1st chat message. But you can create it anyway if you need this for in your application.

Create new group chat

When user would like to start a group chat - he should create a group chat dialog first.

Chat2.0 chatnew.png

User should choose other users to add them to a new group dialog. Also he should choose a name for new group chat:

QBChatDialog *chatDialog = [QBChatDialog new];
chatDialog.name = @"Chat with Bob, Sam, Garry";
chatDialog.occupantIDs = @[@(55), @(678), @(22)];
chatDialog.type = QBChatDialogTypeGroup;
 
[QBChat createDialog:chatDialog delegate:self];
 
 
#pragma mark -
#pragma mark QBActionStatusDelegate
 
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:[QBChatDialogResult class]]) {
        QBChatDialogResult *res = (QBChatDialogResult *)result;
        QBChatDialog *dialog = res.dialog;
        NSLog(@"Dialog: %@", res.dialog);
    }
}
ArrayList<Integer> occupantIdsList = new ArrayList<Integer>();
occupantIdsList.add(55);
occupantIdsList.add(678);
occupantIdsList.add(22);
 
QBRoomChatManager roomChatManager = QBChatService.getInstance().getRoomChatManager();
roomChatManager.createDialog("Chat with Bob, Sam, Garry", QBDialogType.GROUP, occupantIdsList, new QBEntityCallbackImpl<QBDialog>() {
    @Override
    public void onSuccess(QBDialog dialog, Bundle args) {
        Log.i(TAG, "dialog: " + dialog);
    }
 
    @Override
    public void onError(List<String> errors) {
        // handle errors
    }
});

After this you should join this group chat to be able send and receive messages:

// Login to chat if you hadn't done this before
// ...
 
 
// Use a newly created dialog and its 'roomJID' field to join a room
QBChatRoom *groupChat = [chatDialog chatRoom];
self.thisGroupChat = groupChat;
[self.thisGroupChat joinRoomWithHistoryAttribute:@{@"maxstanzas": @"0"}];
 
...
 
#pragma mark -
#pragma mark QBChatDelegate
 
- (void)chatRoomDidEnter:(QBChatRoom *)room{
   // joined here, now you can send and receive chat messages within this dialog
}
// Login to chat if you hadn't done this before
// ...
 
// Use a newly created dialog and its 'roomJID' field to join a room
String roomJid = dialog.getRoomJid() 
 
QBRoomChatManager roomChatManager = QBChatService.getInstance().getRoomChatManager();
QBRoomChat currentChatRoom = roomChatManager.createRoom(roomJid);
 
currentChatRoom.join(new QBEntityCallback() {
    @Override
    public void onSuccess(Object o, Bundle bundle) {
        Log.i(TAG, "onSuccess");
        // joined here, now you can send and receive chat messages within this dialog
    }
 
    @Override
    public void onSuccess() {
        Log.i(TAG, "onSuccess");
        // joined here, now you can send and receive chat messages within this dialog
    }
 
    @Override
    public void onError(final List list) {
        Log.i(TAG, "onError: " + list);
    }
});

To notify all occupants that you created a group chat we use chat notifications - it's simple chat message with extra parameters inside. These parameters used to separate chat notifications from regular text chat messages:

- (QBChatMessage *)createChatNotificationForGroupChatCreation:(QBDialog *)dialog
{
    // create message:
    QBChatMessage *inviteMessage = [QBChatMessage message];
    inviteMessage.text = @"optional text";
 
    NSMutableDictionary *customParams = [NSMutableDictionary new];
    customParams[@"xmpp_room_jid"] = dialog.roomJID;
    customParams[@"name"] = dialog.name;
    customParams[@"_id"] = dialog.ID;
    customParams[@"type"] = @(dialog.type);
    customParams[@"occupants_ids"] = [dialog.occupantIDs componentsJoinedByString:@","];
 
    // Add notification_type=1 to extra params when you created a group chat 
    //
    customParams[@"notification_type"] = @"1";
 
    inviteMessage.customParameters = customParams;
 
    return inviteMessage;
}
 
...
 
for (NSString *occupantID in dialog.occupantIDs) {
 
    QBChatMessage *inviteMessage = [self createChatNotificationForGroupChatCreation:dialog];
 
    NSTimeInterval timestamp = (unsigned long)[[NSDate date] timeIntervalSince1970];
    customParams[@"date_sent"] = @(timestamp);
 
    // send notification
    //
    inviteMessage.recipientID = [occupantID integerValue];
    [[QBChat instance] sendMessage:inviteMessage];
}
public static QBChatMessage createChatNotificationForGroupChatCreation(QBDialog dialog) {
    String dialogId = String.valueOf(dialog.getDialogId());
    String roomJid = dialog.getRoomJid();
    String occupantsIds = TextUtils.join(",", dialog.getOccupants());
    String dialogName = dialog.getName();
    String dialogTypeCode = String.valueOf(dialog.getType().ordinal());
 
    QBUser user = AppSession.getSession().getUser();
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("optional text");
 
    // Add notification_type=1 to extra params when you created a group chat 
    //
    chatMessage.setProperty("notification_type", "1");
 
    chatMessage.setProperty("_id", dialogId);
    if (!TextUtils.isEmpty(roomJid)) {
        chatMessage.setProperty("room_jid", roomJid);
    }
    chatMessage.setProperty("occupants_ids", occupantsIds);
    if (!TextUtils.isEmpty(dialogName)) {
        chatMessage.setProperty("name", dialogName);
    }
    chatMessage.setProperty("type", dialogTypeCode);
 
    return chatMessage;
}
 
...
 
for (Integer userID : dialog.getOccupants()) {
 
    QBChatMessage chatMessage = createChatNotificationForGroupChatCreation(dialog);
 
    long time = DateUtils.getCurrentTime();
    chatMessage.setProperty("date_sent", time + "");
 
    QBPrivateChat chat = QBChatService.getInstance().getPrivateChatManager().getChat(userID);
    if (chat == null) {
        chat = chatService.getPrivateChatManager().createChat(userID, null);
    }
 
    try {
        chat.sendMessage(chatMessage);
    } catch (Exception e) {
        // error
    }
}

Create new 1-1(private) chat

If you would like to create a private chat dialog too - use next snippets:

QBChatDialog *chatDialog = [QBChatDialog new];
chatDialog.type = QBChatDialogTypePrivate;
 
[QBChat createDialog:chatDialog delegate:self];
 
 
#pragma mark -
#pragma mark QBActionStatusDelegate
 
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:[QBChatDialogResult class]]) {
        QBChatDialogResult *res = (QBChatDialogResult *)result;
        QBChatDialog *dialog = res.dialog;
        NSLog(@"Dialog: %@", res.dialog);
    }
}
QBPrivateChatManager privateChatManager = QBChatService.getInstance().getPrivateChatManager();
privateChatManager.createDialog(opponentId, new QBEntityCallbackImpl<QBDialog>() {
    @Override
    public void onSuccess(QBDialog dialog, Bundle args) {
        og.i(TAG, "dialog: " + dialog);
    }
 
    @Override
    public void onError(List<String> errors) {
        // handle errors
    }
});

Update group chat

User can update group chat name, add new occupants or leave this group chat. To add more occupants use push operator. To leave group chat (remove yourself) - use pull all operator:

Chat2.0 groupchatdetails.png

NSMutableDictionary *extendedRequest = [NSMutableDictionary new];
extendedRequest[@"push[occupants_ids][]"] = @"378"; // Add user with ID 378
// extendedRequest[@"pull_all[occupants_ids][]"] = @"22"; // Remove yourself (user with ID 22)
extendedRequest[@"name"] = @"Team room";
 
[QBChat updateDialogWithID:@"53aac645535c12bd3b008a40" extendedRequest:extendedRequest delegate:self];
 
 
#pragma mark -
#pragma mark QBActionStatusDelegate
 
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:[QBChatDialogResult class]]) {
        QBChatDialogResult *res = (QBChatDialogResult *)result;
        QBChatDialog *dialog = res.dialog;
        NSLog(@"Dialog: %@", res.dialog);
    }
}
QBCustomObjectUpdateBuilder requestBuilder = new QBCustomObjectUpdateBuilder();
requestBuilder.push("occupants_ids", 378);
// requestBuilder.pullAll("occupants_ids", 22); // Remove yourself (user with ID 22)
 
QBRoomChatManager roomChatManager = QBChatService.getInstance().getRoomChatManager();
roomChatManager.updateDialog("53aac645535c12bd3b008a40", "Team room", requestBuilder, new QBEntityCallbackImpl<QBDialog>() {
    @Override
    public void onSuccess(QBDialog dialog, Bundle args) {
        Log.i(TAG, "dialog: " + dialog);
    }
 
    @Override
    public void onError(List<String> errors) {
        // handle errors
    }
});


To notify all occupants that you updated a group chat we use chat notifications - it's simple chat message with extra parameters inside. These parameters used to separate chat notifications from regular text chat messages:

- (QBChatMessage *)createChatNotificationForGroupChatUpdate:(QBDialog *)dialog
{
    // create message:
    QBChatMessage *inviteMessage = [QBChatMessage message];
    inviteMessage.text = @"optional text";
 
    NSMutableDictionary *customParams = [NSMutableDictionary new];
    customParams[@"xmpp_room_jid"] = dialog.roomJID;
    customParams[@"name"] = dialog.name;
    customParams[@"_id"] = dialog.ID;
    customParams[@"type"] = @(dialog.type);
    customParams[@"occupants_ids"] = [dialog.occupantIDs componentsJoinedByString:@","];
 
    // Add notification_type=2 to extra params when you updated a group chat 
    //
    customParams[@"notification_type"] = @"2";
 
    inviteMessage.customParameters = customParams;
 
    return inviteMessage;
}
 
...
 
for (NSString *occupantID in dialog.occupantIDs) {
 
    QBChatMessage *inviteMessage = [self createChatNotificationForGroupChatUpdate:dialog];
 
    NSTimeInterval timestamp = (unsigned long)[[NSDate date] timeIntervalSince1970];
    customParams[@"date_sent"] = @(timestamp);
 
    // send notification
    //
    inviteMessage.recipientID = [occupantID integerValue];
    [[QBChat instance] sendMessage:inviteMessage];
}
public static QBChatMessage createChatNotificationForGroupChatUpdate(QBDialog dialog) {
    String dialogId = String.valueOf(dialog.getDialogId());
    String roomJid = dialog.getRoomJid();
    String occupantsIds = TextUtils.join(",", dialog.getOccupants());
    String dialogName = dialog.getName();
    String dialogTypeCode = String.valueOf(dialog.getType().ordinal());
 
    QBUser user = AppSession.getSession().getUser();
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("optional text");
 
    // Add notification_type=2 to extra params when you updated a group chat 
    //
    chatMessage.setProperty("notification_type", "2");
 
    chatMessage.setProperty("_id", dialogId);
    if (!TextUtils.isEmpty(roomJid)) {
        chatMessage.setProperty("room_jid", roomJid);
    }
    chatMessage.setProperty("occupants_ids", occupantsIds);
    if (!TextUtils.isEmpty(dialogName)) {
        chatMessage.setProperty("name", dialogName);
    }
    chatMessage.setProperty("type", dialogTypeCode);
 
    return chatMessage;
}
 
...
 
for (Integer userID : dialog.getOccupants()) {
 
    QBChatMessage chatMessage = createChatNotificationForGroupChatUpdate(dialog);
 
    long time = DateUtils.getCurrentTime();
    chatMessage.setProperty("date_sent", time + "");
 
    QBPrivateChat chat = QBChatService.getInstance().getPrivateChatManager().getChat(userID);
    if (chat == null) {
        chat = chatService.getPrivateChatManager().createChat(userID, null);
    }
 
    try {
        chat.sendMessage(chatMessage);
    } catch (Exception e) {
        // error
    }
}

List chat messages

All chat messages are stored in history and user can request a chat history for particular dialog.

Chat2.0 listmessages.png

NSMutableDictionary *extendedRequest = [NSMutableDictionary new];
extendedRequest[@"limit"] = @(100);
 
[QBChat messagesWithDialogID:@"53b413f3e4b077ddd43e85e0" extendedRequest:extendedRequest delegate:self];
 
 
#pragma mark - QBActionStatusDelegate
#pragma mark 
 
- (void)completedWithResult:(Result *)result{
    if (result.success && [result isKindOfClass:QBChatHistoryMessageResult.class]) {
        QBChatHistoryMessageResult *res = (QBChatHistoryMessageResult *)result;
        NSArray *messages = res.messages;
        NSLog(@"Messages: %@", messages);
    }
}
QBDialog qbDialog = new QBDialog("53aadc78535c127f15009b6c");
 
QBCustomObjectRequestBuilder customObjectRequestBuilder = new QBCustomObjectRequestBuilder();
customObjectRequestBuilder.setPagesLimit(100);
 
QBChatService.getDialogMessages(qbDialog, customObjectRequestBuilder, new QBEntityCallbackImpl<ArrayList<QBHistoryMessage>>() {
    @Override
    public void onSuccess(ArrayList<QBHistoryMessage> messages, Bundle args) {
        Log.i(TAG, "messages\n: " + messages);
    }
 
    @Override
    public void onError(List<String> errors) {
        // handle errors
    }
});

You can use a list of available filters to better manage your request and returned data.

Send/Receive messages

To send a message use same way you use now - no updates with Chat 2.0.

1-1 (private) chat

To send a message in 1-1 chat - choose opponent's user ID and create a body of chat message:

[[QBChat instance] setDelegate:self];
 
...
 
QBChatMessage *message = [QBChatMessage message];
[message setText:@"Hey there"];
//
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"save_to_history"] = @YES;
[message setCustomParameters:params];
//
[message setRecipientID:305]; // ID of your opponent
//
[[QBChat instance] sendMessage:message];
 
 
#pragma mark -
#pragma mark QBChatDelegate
 
- (void)chatDidReceiveMessage:(QBChatMessage *)message{
 
}
try {
    // create a message
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("Hey there");
    chatMessage.setProperty("save_to_history", "1"); // Save to Chat 2.0 history
    int opponentID = 305;
    //
    QBPrivateChat privateChat = privateChatManager.getChat(opponentID);
    if (privateChat == null) {
        privateChat = privateChatManager.createChat(opponentID, privateChatMessageListener);
    }
    privateChat.sendMessage(chatMessage);
} catch (XMPPException e) {
    e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
}
 
...
 
private QBPrivateChatManagerListener privateChatManagerListener = new QBPrivateChatManagerListener() {
    @Override
    public void chatCreated(final QBPrivateChat privateChat, final boolean createdLocally) {
        if(!createdLocally){
             privateChat.addMessageListener(privateChatMessageListener);
        }
    }
};
 
private QBMessageListener<QBPrivateChat> privateChatMessageListener = new QBMessageListener<QBPrivateChat>() {
    @Override
    public void processMessage(final QBPrivateChat privateChat, final QBChatMessage chatMessage) {
 
    }
};
 
QBChatService.getInstance().getPrivateChatManager().addPrivateChatManagerListener(privateChatManagerListener);

Group chat

Before send and receive messages in group chat you have to be joined to this group chat as described in Create new group chat section.

[[QBChat instance] setDelegate:self];
 
...
 
QBChatMessage *message = [QBChatMessage message];
[message setText:@"Hey there"];
//
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"save_to_history"] = @YES;
[message setCustomParameters:params];
//
[message setRecipientID:305]; // ID of your opponent
//
[[QBChat instance] sendChatMessage:message toRoom:groupRoom];
 
 
#pragma mark -
#pragma mark QBChatDelegate
 
- (void)chatRoomDidReceiveMessage:(QBChatMessage *)message fromRoomJID:(NSString *)roomJID{
 
}
try {
    // create a message
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("Hey there");
    chatMessage.setProperty("save_to_history", "1"); // Save to Chat 2.0 history
    //
    currentChatRoom.sendMessage(chatMessage);
} catch (XMPPException e) {
    e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
}
 
...
 
private QBMessageListener<QBRoomChat> roomChatMessageListener = new QBMessageListener<QBRoomChat>() {
    @Override
    public void processMessage(final QBRoomChat roomChat, final QBChatMessage chatMessage) {
 
    }
};
 
currentChatRoom.addMessageListener(roomChatMessageListener);

Send and receive a message with attachment

Send attachment

It's possible to add attachments to message: for example, image, audio file or video file. We don't have any restrictions here - you can attach any type of file.

To send a message with attachments you should use the same way as you send regular message with text, but add to it an attachment object. Attachment can be:


To send a message with attachment you should upload a file to Content module, Custom Objects module using sample above or use an url to any file in Internet. Then you should incorporate an ID to file to message.

For example, we use Content module to store attachments. Next snippets show how to upload a file to Content module and send it as an attach:

// Upload a file to the Content module
NSData *image = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image45" ofType:@"png"]];
//
[QBContent TUploadFile:image fileName:@"image45" contentType:@"image/png" isPublic:NO delegate:self];
 
#pragma mark -
#pragma mark QBActionStatusDelegate
 
- (void)completedWithResult:(Result *)result{
 
    // success result
    if(result.success){
        // Upload file result
        if([result isKindOfClass:QBCFileUploadTaskResult.class]){
 
            // get uploaded file ID
            QBCFileUploadTaskResult *res = (QBCFileUploadTaskResult *)result;
            NSUInteger uploadedFileID = res.uploadedBlob.ID;
 
            // Create chat message with attach
            //
            QBChatMessage *message = [QBChatMessage message];
 
            ...
 
            QBChatAttachment *attachment = QBChatAttachment.new;
            attachment.type = @"image";
            attachment.ID = [NSString stringWithFormat:@"%d", uploadedFileID]; // use 'ID' property to store an ID of a file in Content or CustomObjects modules
           //  attachment.url = @"http://mysite.com/avatar.png"; // use 'url' property to store an url to file in Internet
           [message setAttachments:@[attachment]];
    }else{
        NSLog(@"Errors=%@", result.errors);
    }
}
// Upload file to Content module
File image = new File("path to image");
QBContent.uploadFileTask(image, false, new QBCallbackImpl() {
    @Override
    public void onComplete(Result result) {
        if (result.isSuccess()) {
            // get uploaded file ID
            QBFileUploadTaskResult res = (QBFileUploadTaskResult) result;
            Integer id = res.getFile().getId();
 
            // Create chat message with attach
            //
            QBChatMessage chatMessage = new QBChatMessage();
 
            ...
 
            QBAttachment attachment = new QBAttachment("image");
            attachment.setId(String.valueOf(id)); // use 'Id' property to store an ID of a file in Content or CustomObjects modules
            // attachment.setUrl("http://mysite.com/avatar.png"); // use 'url' property to store an url to file in Internet
            chatMessage.addAttachment(attachment);
        }
    }
});

Receive attachment

For example we use Content module to store attachments. Next snippets allow to receive a message with an attachment and download it:

#pragma mark -
#pragma mark QBChatDelegate
 
- (void)chatDidReceiveMessage:(QBChatMessage *)message{
    for(QBChatAttachment *attachment in message.attachments){
        // download file by ID
        [QBContent TDownloadFileWithBlobID:[attachment.ID integerValue] delegate:self];
    }
}
 
#pragma mark -
#pragma mark QBActionStatusDelegate
 
- (void)completedWithResult:(Result *)result{
    // Download file result
    if(result.success && [result isKindOfClass:QBCFileDownloadTaskResult.class]){
        // extract image
        QBCFileDownloadTaskResult *res = (QBCFileDownloadTaskResult *)result;
        UIImage *image = [UIImage imageWithData:res.file];
    }else{
        NSLog(@"Errors=%@", result.errors);
    }
}
private QBMessageListener<QBPrivateChat> privateChatMessageListener = new QBMessageListener<QBPrivateChat>() {
    @Override
    public void processMessage(final QBPrivateChat privateChat, final QBChatMessage chatMessage) {
         for(QBAttachment attachment : chatMessage.getAttachments()){
 
             // Download file 
             QBContent.downloadFileTask(Integer.parseInt(attachment.getId()), new QBCallbackImpl() {
                 @Override
                 public void onComplete(Result result) {
                     QBFileDownloadResult qbFileDownloadResult = (QBFileDownloadResult) result;
                     if (result.isSuccess()) {
                         byte[] content = qbFileDownloadResult.getContent();       // that's downloaded file content
                         InputStream is = qbFileDownloadResult.getContentStream(); // that's downloaded file content
 
                     }
                 }
             });
         }
    }
};

Datetime issue

All the users in conversation have to have same date_sent value for chat messages. In additional, the same value should be stored to chat history.

To resolve this issue we recommend a flow when each user sets by himself a date_sent value when sending a message:

QBChatMessage *message = [QBChatMessage message];
...
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"date_sent"] = @((int)[[NSDate date] timeIntervalSince1970];
...
[message setCustomParameters:params];
QBChatMessage chatMessage = new QBChatMessage();
...
long time = System.currentTimeMillis()/1000;
chatMessage.setProperty("date_sent", time + "");
...

Chat server validates this value (check a difference between client's and server's timestamps - it should not be more than 5 seconds). If a difference is less then 5 seconds - server will use client's value, otherwise - ignore client's value and use own.