Log in from multiple devices

Updated

Log in to Agora Chat from multiple devices

Agora Chat supports logging in to the same account from up to 4 devices at the same time by default. You can increase the number of devices per platform up to 10 by going to Agora Console > Project management > Relevant project > Agora Chat configuration > Features > Multi Device.

In cases of multiple device login, all logged-in devices synchronize the following information and operations:

  • Messages, including online messages, offline messages, push notifications (if the third-party push service is enabled, the offline device receives it), the corresponding receipts and read status, and so on;
  • Friends and group-related operations;
  • Message-thread-related operations;
  • Conversation-related operations.

The following table summarizes the strategy of forcing other devices to log out and the automatic login security check in the single-device and multi-device login use-cases:

Single/multi-device login Forced logout strategy Automatic login security check

Single-device login The newly logged-in device will force the current device to log out. The logged-out device will receive the ConnectionListener#onLogout callback. For devices that log in automatically, the device will automatically reconnect to the Agora server after going offline. If the reconnection is successful, the current logged-in device will be forced to log out by default (for multiple devices, the earliest logged-in device will be logged out). If you want to keep the current device logged in, contact support@agora.io. In this use-case, the device that logs in automatically won't be able to log in and will receive error 214, indicating that the number of currently logged-in devices exceeds the limit.

Multi-device login If the number of logged-in devices on one end reaches the limit, the device that logged in the latest will force the device that logged in the earliest to log out. The logged-out device will receive the ConnectionListener#onLogout callback. Agora Chat only supports forced logout for the devices on the same end.

Single/multi-device login Forced logout strategy Automatic login security check

Single-device login The newly logged-in device will force the current device to log out. The logged-out device will receive the AgoraChatClientDelegate#userAccountDidLoginFromOtherDevice event. For devices that log in automatically, the device will automatically reconnect to the Agora server after going offline. If the reconnection is successful, the current logged-in device will be forced to log out by default (for multiple devices, the earliest logged-in device will be logged out). If you want to keep the current device logged in, contact support@agora.io. In this use-case, the device that logs in automatically won't be able to log in and will receive error 214, indicating that the number of currently logged-in devices exceeds the limit.

Multi-device login If the number of logged-in devices on one end reaches the limit, the device that logged in the latest will force the device that logged in the earliest to log out. The logged-out device will receive the AgoraChatClientDelegate#userAccountDidLoginFromOtherDevice event. Agora Chat only supports forced logout for the devices on the same end.

Single/multi-device loginForced logout strategy
Single-device loginThe newly logged-in device will force the current device to log out. The logged-out device will receive the onDisconnected event.
Multi-device loginIf the number of logged-in devices on one end reaches the limit, the device that logged in the latest will force the device that logged in the earliest to log out. Agora Chat only supports forced logout for the devices on the same end. When multiple ends are logged in, the use of a fixed device ID affects the forced logout strategy. The SDK generates an ID as the unique device identifier. Previously, the SDK used a different random string as the device identifier for each opened tab. Starting from v1.3.1, the SDK has the ConnectionParameters#isFixedDeviceId parameter, which you can set to use a random device ID or a fixed device ID when initializing the SDK: - (Default) true: Use a fixed device ID. The device ID is stored in local storage. Even when multiple devices are logged in, only one tab can be opened in the same browser. If two are opened, the new tab will force the previous one offline. - false: Use a random device ID. Each tab uses a different device ID. When logging in with multiple devices, a user can open multiple tabs in the same browser. If the number of devices exceeds the set number, the newly opened tab will force the first opened tab offline.

The Agora server provides a RESTful interface to force a specified account to log out from a single device.

Single/multi-device login Forced logout strategy Automatic login security check

Single-device login The newly logged-in device will force the current device to log out. The logged-out device will receive the ConnectionEventHandler#onUserDidLoginTooManyDevice event. For devices that log in automatically, the device will automatically reconnect to the Agora server after going offline. If the reconnection is successful, the current logged-in device will be forced to log out by default (for multiple devices, the earliest logged-in device will be logged out). If you want to keep the current device logged in, contact support@agora.io. In this use-case, the device that logs in automatically won't be able to log in and will receive error 214, indicating that the number of currently logged-in devices exceeds the limit.

Multi-device login If the number of logged-in devices on one end reaches the limit, the device that logged in the latest will force the device that logged in the earliest to log out. The logged-out device will receive the ConnectionEventHandler#onUserDidLoginTooManyDevice event. Agora Chat only supports forced logout for the devices on the same end.

Single/multi-device login Forced logout strategy Automatic login security check

Single-device login The newly logged-in device will force the current device to log out. The logged-out device will receive the ChatConnectEventListener#onUserDidLoginFromOtherDevice event. For devices that log in automatically, the device will automatically reconnect to the Agora server after going offline. If the reconnection is successful, the current logged-in device will be forced to log out by default (for multiple devices, the earliest logged-in device will be logged out). If you want to keep the current device logged in, contact support@agora.io. In this use-case, the device that logs in automatically won't be able to log in and will receive error 214, indicating that the number of currently logged-in devices exceeds the limit.

Multi-device login If the number of logged-in devices on one end reaches the limit, the device that logged in the latest will force the device that logged in the earliest to log out. The logged-out device will receive the ChatConnectEventListener#onUserDidLoginFromOtherDevice event. Agora Chat only supports forced logout for the devices on the same end.

Understand the tech

During initialization, the SDK generates a login ID to identify the device when multiple devices log in and push messages, and sends this ID to the server. The server automatically sends new messages to the user's logged-in device, monitors operations on other devices, and synchronizes multiple devices. The SDK provides the following multi-device use-case functions:

  • Get the login ID list of the other logged-in devices of the current user;

  • Get the list of online logged-in devices of the specified account;

  • Force the specified account to log out from a single device;

  • Force the specified account to log out from all devices;

  • Get friend or group operations on other devices.

  • Set the name of the login device;

  • Set the platform of the login device;

  • Get notified about multi-device synchronization.

Chat SDK generates a new unique login ID every time a user logs in and sends the ID to the server. The server automatically sends new messages to the device where the user logs in, and can automatically monitor friend or group operations on other devices.

Prerequisites

Before starting this procedure, initialize and connect the SDK to the server. See SDK quickstart for details.

Implement multi-device login

Get the login ID list of other logged-in devices of the current user

Call getSelfIdsOnOtherPlatform to get the login ID list of other logged-in devices, and then select the target login ID as the message recipient to send a message to the specified device.

// A synchronous method that will block the current thread. The asynchronous method is asyncGetSelfIdsOnOtherPlatform(ValueCallBack).
List ids = ChatClient.getInstance().contactManager().getSelfIdsOnOtherPlatform();
// Select a login ID as the message recipient.
String toChatUserId = ids.get(0);
// Create a text message, content is the message text, toChatUserId passes in the login ID as the message recipient.
ChatMessage message = ChatMessage.createTextSendMessage(content, toChatUserId);
// Send a message.
ChatClient.getInstance().chatManager().sendMessage(message);

Get the list of online logged-in devices for the specified account

Call getLoggedInDevicesFromServerWithToken to get the list of online logged-in devices for the specified account from the server by passing in the user ID and user token.

    try {
        List deviceInfos = ChatClient.getInstance().getLoggedInDevicesFromServerWithToken(userId, token);
    } catch (HyphenateException e) {
        e.printStackTrace();
    }

Force the specified account to log out from a single device

Call kickDeviceWithToken and pass in the user ID and user token to force the specified account to log out from a single logged-in device. Before calling this method, obtain the device ID through the ChatClient#getLoggedInDevicesFromServerWithToken and DeviceInfo#getResource methods. The logged-out device will receive the ConnectionListener#onLogout event.

You can also use this interface without logging in.

// userId: User ID, token: User token. Need to be executed in an asynchronous thread.
List deviceInfos = ChatClient.getInstance().getLoggedInDevicesFromServerWithToken(userId, token);
// userId: User ID, token: User token, resource: Device ID. Need to be executed in an asynchronous thread.
ChatClient.getInstance().kickDeviceWithToken(userId, token, deviceInfos.get(selectedIndex).getResource());

Force the specified account to log out from all devices

Call kickAllDevicesWithToken and pass in the user ID and user token to force the specified account to log out from all logged-in devices. The logged-out device will receive the ConnectionListener#onLogout event.

You can also use this interface without logging in.

    try {
        ChatClient.getInstance().kickAllDevicesWithToken(userId,token);
    } catch (HyphenateException e) {
        e.printStackTrace();
    }

Get operations on other devices

Let's say that account A logs in on devices A and B at the same time and performs operations on device A. Device B will receive notifications corresponding to these operations.

You need to implement the MultiDeviceListener class to listen to operations on other devices, and then call the addMultiDeviceListener method to add multi-device listening.

//Implement `MultiDeviceListener` to listen to operations on other devices.
private class ChatMultiDeviceListener implements MultiDeviceListener {
//@param event event.
    @Override
    //@param target friend's user ID; @param ext event extended information.
    public void onContactEvent(int event, String target, String ext) {
        EMLog.i(TAG, "onContactEvent event"+event);
        String message = null;
        switch (event) {
            //The current user deletes friends on other devices.
            case CONTACT_REMOVE:
            break;
            //The current user accepts friend requests on other devices.
            case CONTACT_ACCEPT:
            break;
            //The current user rejects friend requests on other devices.
            case CONTACT_DECLINE:
            break;
            //The current user adds a user to the blocklist on other devices.
            case CONTACT_BAN:
            break;
            //The current user removes a user from the blocklist on other devices.
            case CONTACT_ALLOW:
            break;
            default:
            break;
        }
    }

    @Override
    public void onGroupEvent(int event, String groupId, List userIds) {
        EMLog.i(TAG, "onGroupEvent event"+event);
        switch (event) {
            //The current user created a group on another device.
            case GROUP_CREATE:
            break;
            //The current user destroyed a group on another device.
            case GROUP_DESTROY:
            break;
            //The current user joined a group on another device.
            case GROUP_JOIN:
            break;
            //The current user left a group on another device.
            case GROUP_LEAVE:
            break;
            //The current user initiated a group application on another device.
            case GROUP_APPLY:
            break;
            //The current user approved the group application on another device.
            case GROUP_APPLY_ACCEPT:
            break;
            //The current user rejected the group application on another device.
            case GROUP_APPLY_DECLINE:
            break;
            //The current user invited group members on other devices.
            case GROUP_INVITE:
            break;
            //The current user accepted the invitation to join the group on other devices.
            case GROUP_INVITE_ACCEPT:
            break;
            //The current user rejected the invitation to join the group on other devices.
            case GROUP_INVITE_DECLINE:
            break;
            //The current user kicked members out of the group on other devices.
            case GROUP_KICK:
            break;
            //The current user added members to the group blocklist on other devices.
            case GROUP_BAN:
            break;
            //The current user removed members from the group blocklist on other devices.
            case GROUP_ALLOW:
            break;
            //The current user blocked the group on other devices.
            case GROUP_BLOCK:
            break;
            //The current user unblocked the group on other devices.
            case GROUP_UNBLOCK:
            break;
            //The current user transferred group ownership on other devices.
            case GROUP_ASSIGN_OWNER:
            break;
            //The current user adds an administrator on other devices.
            case GROUP_ADD_ADMIN:
            break;
            //The current user removes the administrator on other devices.
            case GROUP_REMOVE_ADMIN:
            break;
            //The current user mutes users on other devices.
            case GROUP_ADD_MUTE:
            break;
            //The current user removes the muting on other devices.
            case GROUP_REMOVE_MUTE:
            break;
            //The current user sets custom attributes for group members on other devices.
            case GROUP_METADATA_CHANGED:
            break;
            default:
            break;
        }
    }

    @Override
    public void onChatThreadEvent(int event, String target, List userIds) {
        EMLog.i(TAG, "onChatThreadEvent event"+event);
        switch (event) {
            case THREAD_CREATE:
            //The current user creates a message thread on other devices.
            break;
            case THREAD_DESTROY:
            //The current user destroys the message thread on other devices.
            break;
            case THREAD_JOIN:
            //The current user joins the message thread on other devices.
            break;
            case THREAD_LEAVE:
            //The current user leaves the message thread on other devices.
            break;
            case THREAD_UPDATE:
            //The current user updates the message thread on other devices.
            break;
            case THREAD_KICK:
            //The current user kicks a member out of the message thread on other devices.
            break;
            default:
            break;

        }
    }

    @Override
    public void onConversationEvent(int event, String conversationId, Conversation.ConversationType type) {
        EMLog.i(TAG, "onConversationEvent event"+event);
        switch (event) {
            case CONVERSATION_PINNED:
            //The current user pins a conversation on other devices.
            break;
            case CONVERSATION_UNPINNED:
            //The current user unpins a conversation on other devices.
            break;
            case CONVERSATION_DELETED:
            //The current user deletes a conversation on other devices.
            break;
            case CONVERSATION_MARK_UPDATE:
            //The current user updates the conversation tag on other devices, including adding and removing conversation tags.
            break;
            default:
            break;
        }
    }

    @Override
    public void onMessageRemoved(String conversationId, String deviceId) {
        EMLog.i(TAG, "onMessageRemoved conversationId "+conversationId);
        //The current user unidirectionally deletes message history of a conversation on other devices from the server.
    }
}

ChatMultiDeviceListener chatMultiDeviceListener = new ChatMultiDeviceListener();

//Add a multi-device listener.
ChatClient.getInstance().addMultiDeviceListener(chatMultiDeviceListener);

//Remove a multi-device listener.
ChatClient.getInstance().removeMultiDeviceListener(chatMultiDeviceListener);