logo
On this page

Multi-device login


Function introduction

ZIM SDK supports the configuration of custom multi-device logins, which means that users can log in to multiple devices simultaneously with the same account, ensuring that the user's conversations, messages, groups, rooms and other data communicate with each other.

Note
  • To use this feature, please subscribe to the Professional or Ultimate package, and contact the technical support team to activate the service and configure the login policy.
  • This feature only supports SDK version 2.11.0 and above.

Common login policies

Multi-device login supports configuration on 7 platforms including Android, iOS, Windows, Mac, Linux, iPad, and Web.

  • Across Windows, macOS, Linux, Android, iOS, and iPadOS, a single user account to be simultaneously active on up to 10 devices.
  • Multi-instance login is supported on the Web platform, with no more than 10 login instances.

The following are the three login policies supported by the ZIM SDK: single-device login, dual-device login, and multi-device login.

Login policiesSpecific explanation
Single device login (by default)Only supports users logging into the account on one device at a time. If the account is logged into another device, the account on the original device will be logged out.
Dual-device loginAllows users to log in to their accounts on any of the Windows, Mac, Linux, Android, iOS, and iPad devices while keeping their accounts online on the web device.
Multi-device loginAllows users to simultaneously log in to their accounts on multiple devices, including Windows, Mac, Linux, Android, iOS, iPad, Web, and Mini program. The following configurations are supported:
  • Multiple device and instance login on the same device at the same time.
  • Configure the logic for kicking each other offline; currently only supports offline kicking between Android and iOS devices, and offline kicking between Windows and Mac devices.

Implementation process

Contact ZEGOCLOUD technical support team to activate the multi-terminal login service. After configuring the multi-device login, you can call login on multiple devices to log in to the ZIM SDK. The implementation process is the same as a single-terminal login. For details on how to log in, please refer to the "Logging in ZIM" section in Send and receive messages.

When the number of login devices reaches the limit set by the policy, if you log in to the account on a new device, the account that was logged in the earliest on the original device will be kicked offline. You will be notified of this through the onConnectionStateChanged callback with the event set to KickedOut. For example, if the login specifies a maximum of 3 devices to be logged in, and the account has already been logged in on devices A, B, and C (in chronological order), logging in to the account on device D will kick the account on device A offline.

When the account is kicked offline, it is recommended to call the logout interface to log out of the ZIM service and switch the user interface to the login interface.

The impact of multi-device login on other functions

The codes for the following functions must also be changed after configuring multi-device login.

User information management

ZIM SDK provides user information synchronization function for multi-device login users.After a user updates his or her information through updateUserName, updateUserAvatarUrl, updateUserExtendedData interfaces on one device, other online clients can register the onUserInfoUpdated event to listen for user information being modified.

onUserInfoUpdated processing example

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onUserInfoUpdated(zim::ZIM * zim, const zim::ZIMUserFullInfo & info) override {
        // Can be obtained in info: user ID, user name, user avatar, user additional fields
        auto user_id = info.baseInfo.userID;
        auto user_name = info.baseInfo.userName;
        auto user_avatar_url = info.userAvatarUrl;
        auto user_extended_data = info.extendedData;
    }

...
}

Conversation management

Delete a single server conversation

When the user deletes the server conversation on one device through the deleteConversation interface(that is, isAlsoDeleteServerConversation set to true), other online clients can register onConversationChanged event to listen for the deletion of the conversation.

onConversationChanged example

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onConversationChanged(zim::ZIM *zim, 
                                       const std::vector<zim::ZIMConversationChangeInfo> &conversationChangeInfoList) override {
        for (const auto &conv_info : conversationChangeInfoList) {
            if (conv_info.event == zim::ZIMConversationEvent::ZIM_CONVERSATION_EVENT_DELETED) {
                // The conversation is deleted
            }
        }
    }

...
}

Delete all server conversations

When the user deletes all server conversations on one device through the deleteAllConversations interface(that is, isAlsoDeleteServerConversation set to true), other clients can use onConversationsAllDeleted event to listen for the deletion of the.

onConversationsAllDeleted processing example

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onConversationsAllDeleted(zim::ZIM *zim, 
                                       const ZIMConversationsAllDeletedInfo &info) override {
        // The other end deleted all sessions
   }
...
}

Clear all unread conversations

When the user clears all unread conversations on one device through clearConversationTotalUnreadMessageCount. Other clients can listen for the notification of all conversations having their unread message count cleared through the onConversationTotalUnreadMessageCountUpdated event.

onConversationTotalUnreadMessageCountUpdated processing example

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onConversationTotalUnreadMessageCountUpdated(zim::ZIM *zim, 
                                       unsigned int totalUnreadMessageCount) override {
        //After clearing all unread messages in all conversations on other devices, the value of totalUnreadMessageCount in the current device will be 0
   }
...
}

Message management

Message Synchronization

When a user logs in to a new device, the SDK does not automatically synchronize the existing messages from the old device to the new device. Users need to actively call the queryHistoryMessage interface to retrieve the messages stored on the ZIM server. For more details, please refer to Get message history . As for the local messages stored on the old device, they cannot be retrieved.

Deleting server message

When a user deletes server messages in a conversation through the deleteMessages, deleteAllMessage , with (that is isAlsoDeleteServerMessage set to true), other online clients can listen for the onMessageDeleted to be notified of the deleted messages.

Example of calling the interface

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onMessageDeleted(zim::ZIM * /*zim*/, const zim::ZIMMessageDeletedInfo &deletedInfo) override {
        if (deletedInfo.messageDeleteType == zim::ZIM_MESSAGE_DELETE_TYPE_MESSAGE_LIST_DELETED)
        {
            // Multiple messages in a session are deleted
            for (const auto& message : deletedInfo.messageList)
            {
             // Iterate through each deleted message
            }
        } else if (deletedInfo.messageDeleteType ==
                   zim::ZIM_MESSAGE_DELETE_TYPE_CONVERSATION_ALL_MESSAGES_DELETED)
        {
            // All current messages for a session are deleted
        } else if (deletedInfo.messageDeleteType ==
                   zim::ZIM_MESSAGE_DELETE_TYPE_ALL_CONVERSATION_MESSAGES_DELETED)
        {
            // all messages for all sessions are deleted
        }
...
}

Set message receipt as read

When a user sets a message receipt as read through the sendMessageReceiptsRead, sendConversationMessageReceiptRead interface on one device, other online clients can listen for the onMessageReceiptChanged and onConversationMessageReceiptChanged event to be notified that the account has set the message receipt as read.

Example of calling the interface

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onMessageReceiptChanged(zim::ZIM * /*zim*/,
                const std::vector<zim::ZIMMessageReceiptInfo> & infos) override {
        for (const auto &info : infos) {
            if (info.isSelfOperated) {
                // Message receipt set as read by the user
            }
        }
    }

    virtual void onConversationMessageReceiptChanged(zim::ZIM *zim, 
                const std::vector<zim::ZIMMessageReceiptInfo> &infos) override {
        for (const auto &info : infos) {
            if (info.isSelfOperated) {
                // Conversation receipt set as read by the user
            }
        }
    }

...
}

Room management

By default, the room module's related interfaces and events do not support multi-device login. When a user joins a room on device A, and then joins the same room on device B, device A will be kicked out of the room. Device A will receive the event as KickedOutByOtherDevice through the onRoomStateChanged.

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onRoomStateChanged(zim::ZIM *zim, zim::ZIMRoomState state, zim::ZIMRoomEvent event,
                                    const std::string &extendedData,
                                    const std::string &roomID) override {
        if (state == zim::ZIMRoomState::ZIM_ROOM_STATE_DISCONNECTED &&
            event == zim::ZIMRoomEvent::ZIM_ROOM_EVENT_KICKED_OUT_BY_OTHER_DEVICE) {
            // Kicked out of the room due to multi-device login
        }
    }
...
}

If you need to support multi-device login for the room feature, please contact the ZEGOCLOUD technical support to enable it. After enabling the feature, multiple devices with the same UserID will not be kicked out of the same room. You need to maintain the room member list and remove duplicate UserIDs.

Group management

After enabling the multi-device login service, ZIM SDK will automatically synchronize group-related data between multiple devices.

Call invitation management

When the user is logged in on both device A and device B, and receives a call invitation, if the user accepts the invitation on device A(calling callAccept)or after rejecting the invitation(calling callReject) :

  1. Device A can know the result of the operation through the callbacks(ZIMCallAcceptanceSentCallback or ZIMCallRejectionSentCallback), and close the invitation popup window to perform other business operations.
  2. Device B should use the onCallUserStateChanged callback to know the call user state of the current user(ZIMCallUserState)as Accepted or Rejected,and close the invitation popup window to perform other business operations.

Each device can receive user state change events within the call invitation, as shown in the following table:

callUserStateDevice ADevice B
Inviting✔️✔️
Received✔️✔️
Accepted✔️✔️
Rejected✔️✔️
Timeout
Cancelled
Quit✔️

Example of calling the interface

const std::string self_user_id = "user_id";
const std::string current_call_id = "call_id";

zim::ZIMCallAcceptConfig accept_config;
accept_config.extendedData = "extra_1";

zim::ZIMCallRejectConfig reject_config;
reject_config.extendedData = "extra_1";

// Device A accepts the invitation
zim_->callAccept(current_call_id, accept_config, [=] (const std::string &callID, const ZIMError &errorInfo) {
        // Close the popup box for call waiting operation. Call ends.
});
// Device A rejects the invitation
zim_->callReject(current_call_id, reject_config, [=] (const std::string &callID, const ZIMError &errorInfo) {
        // Close the popup box for call waiting operation. Call ends.
 }];

// Device B listens for callUserStateChanged

class zim_event_handler : public zim::ZIMEventHandler {
...

    virtual void onCallUserStateChanged(zim::ZIM * /*zim*/,
                                               const zim::ZIMCallUserStateChangeInfo &info,
                                               const std::string &callID) override {
        for (const auto &user_info : callUserList) {
            if (user_info.userID == self_user_id &&
                (user_info.state == zim::ZIMCallUserState::ZIM_CALL_USER_STATE_ACCEPTED ||
                 user_info.state == zim::ZIMCallUserState::ZIM_CALL_USER_STATE_REJECTED)) {
                 // When Device A has accepted or rejected, close the popup box for call waiting operation.
            }
        });
    }
...
}

Previous

Manage users

Next

Offline login