Skip to main content
CMD (Command) messages are special message types that can only be sent from the server to the client for parsing, used to implement server-to-client control instructions and system notifications.

Listen for CMD Messages

Basic Listening

WKIM.getInstance().getCMDManager().addCmdListener("key", cmd -> {
    // Handle cmd message
    handleCommand(cmd);
});

// Remove listener
WKIM.getInstance().getCMDManager().removeCmdListener("key");

Complete Usage Example

public class CommandManager {
    
    private static final String LISTENER_KEY = "CommandManager";
    
    public void initialize() {
        // Add command listener
        WKIM.getInstance().getCMDManager().addCmdListener(LISTENER_KEY, this::handleCommand);
    }
    
    private void handleCommand(WKCMD cmd) {
        if (cmd == null || cmd.cmdKey == null) {
            return;
        }
        
        Log.d("CommandManager", "Received command: " + cmd.cmdKey);
        
        switch (cmd.cmdKey) {
            case "user_status_change":
                handleUserStatusChange(cmd.paramJsonObject);
                break;
                
            case "group_member_update":
                handleGroupMemberUpdate(cmd.paramJsonObject);
                break;
                
            case "system_notification":
                handleSystemNotification(cmd.paramJsonObject);
                break;
                
            case "force_logout":
                handleForceLogout(cmd.paramJsonObject);
                break;
                
            case "message_recall":
                handleMessageRecall(cmd.paramJsonObject);
                break;
                
            case "typing_status":
                handleTypingStatus(cmd.paramJsonObject);
                break;
                
            case "online_status":
                handleOnlineStatus(cmd.paramJsonObject);
                break;
                
            default:
                Log.w("CommandManager", "Unknown command type: " + cmd.cmdKey);
                handleUnknownCommand(cmd);
                break;
        }
    }
    
    // Handle user status change
    private void handleUserStatusChange(JSONObject params) {
        try {
            String userId = params.getString("user_id");
            int status = params.getInt("status");
            
            // Update user status
            UserStatusManager.updateUserStatus(userId, status);
            
            // Notify UI update
            EventBus.getDefault().post(new UserStatusChangedEvent(userId, status));
            
        } catch (JSONException e) {
            Log.e("CommandManager", "Failed to parse user status change command", e);
        }
    }
    
    // Handle group member update
    private void handleGroupMemberUpdate(JSONObject params) {
        try {
            String groupId = params.getString("group_id");
            String action = params.getString("action"); // add, remove, update
            JSONArray members = params.getJSONArray("members");
            
            switch (action) {
                case "add":
                    // Add group members
                    handleGroupMemberAdd(groupId, members);
                    break;
                case "remove":
                    // Remove group members
                    handleGroupMemberRemove(groupId, members);
                    break;
                case "update":
                    // Update group member info
                    handleGroupMemberInfoUpdate(groupId, members);
                    break;
            }
            
        } catch (JSONException e) {
            Log.e("CommandManager", "Failed to parse group member update command", e);
        }
    }
    
    // Handle system notification
    private void handleSystemNotification(JSONObject params) {
        try {
            String title = params.getString("title");
            String content = params.getString("content");
            String type = params.optString("type", "info");
            
            // Show system notification
            NotificationHelper.showSystemNotification(title, content, type);
            
        } catch (JSONException e) {
            Log.e("CommandManager", "Failed to parse system notification command", e);
        }
    }
    
    // Handle force logout
    private void handleForceLogout(JSONObject params) {
        try {
            String reason = params.optString("reason", "Account logged in from another device");
            
            // Clear local data
            clearLocalData();
            
            // Disconnect
            WKIM.getInstance().getConnectionManager().disconnect();
            
            // Navigate to login page
            Intent intent = new Intent(context, LoginActivity.class);
            intent.putExtra("logout_reason", reason);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            context.startActivity(intent);
            
        } catch (Exception e) {
            Log.e("CommandManager", "Failed to handle force logout command", e);
        }
    }
    
    // Handle message recall
    private void handleMessageRecall(JSONObject params) {
        try {
            String messageId = params.getString("message_id");
            String channelId = params.getString("channel_id");
            byte channelType = (byte) params.getInt("channel_type");
            
            // Update local message status
            MessageManager.recallMessage(messageId, channelId, channelType);
            
            // Notify UI update
            EventBus.getDefault().post(new MessageRecalledEvent(messageId, channelId, channelType));
            
        } catch (JSONException e) {
            Log.e("CommandManager", "Failed to parse message recall command", e);
        }
    }
    
    // Handle typing status
    private void handleTypingStatus(JSONObject params) {
        try {
            String channelId = params.getString("channel_id");
            byte channelType = (byte) params.getInt("channel_type");
            String userId = params.getString("user_id");
            boolean isTyping = params.getBoolean("is_typing");
            
            // Update typing status
            TypingStatusManager.updateTypingStatus(channelId, channelType, userId, isTyping);
            
            // Notify UI update
            EventBus.getDefault().post(new TypingStatusEvent(channelId, channelType, userId, isTyping));
            
        } catch (JSONException e) {
            Log.e("CommandManager", "Failed to parse typing status command", e);
        }
    }
    
    // Handle online status
    private void handleOnlineStatus(JSONObject params) {
        try {
            JSONArray users = params.getJSONArray("users");
            
            for (int i = 0; i < users.length(); i++) {
                JSONObject user = users.getJSONObject(i);
                String userId = user.getString("user_id");
                boolean isOnline = user.getBoolean("is_online");
                long lastSeen = user.optLong("last_seen", 0);
                
                // Update online status
                OnlineStatusManager.updateOnlineStatus(userId, isOnline, lastSeen);
            }
            
            // Notify UI update
            EventBus.getDefault().post(new OnlineStatusUpdatedEvent());
            
        } catch (JSONException e) {
            Log.e("CommandManager", "Failed to parse online status command", e);
        }
    }
    
    // Handle unknown command
    private void handleUnknownCommand(WKCMD cmd) {
        // Log unknown command for debugging and extension
        Log.w("CommandManager", "Received unknown command: " + cmd.cmdKey + ", params: " + cmd.paramJsonObject);
        
        // Can send to server for statistics
        AnalyticsManager.trackUnknownCommand(cmd.cmdKey);
    }
    
    // Clean up resources
    public void destroy() {
        WKIM.getInstance().getCMDManager().removeCmdListener(LISTENER_KEY);
    }
    
    // Clear local data
    private void clearLocalData() {
        // Clear user info
        UserManager.clearUserData();
        
        // Clear conversation list
        ConversationManager.clearConversations();
        
        // Clear message cache
        MessageManager.clearMessageCache();
        
        // Clear other local data
        PreferenceManager.clearAllData();
    }
}

WKCMD Data Structure

Command Object Properties

public class WKCMD {
    // Command ID
    public String cmdKey;
    
    // Command parameters
    public JSONObject paramJsonObject;
}

Property Description

PropertyTypeDescription
cmdKeyStringCommand unique identifier, used to distinguish different types of commands
paramJsonObjectJSONObjectCommand parameters, containing data required for command execution

Common Command Types

System Commands

Command TypeDescriptionParameter Example
force_logoutForce logout{"reason": "Account logged in from another device"}
system_notificationSystem notification{"title": "System Maintenance", "content": "System will be maintained tonight"}
server_config_updateServer configuration update{"config_key": "max_file_size", "value": "100MB"}
Command TypeDescriptionParameter Example
user_status_changeUser status change{"user_id": "123", "status": 1}
online_statusOnline status update{"users": [{"user_id": "123", "is_online": true}]}
user_info_updateUser info update{"user_id": "123", "nickname": "New Nickname"}
Command TypeDescriptionParameter Example
message_recallMessage recall{"message_id": "msg123", "channel_id": "ch123"}
typing_statusTyping status{"channel_id": "ch123", "user_id": "123", "is_typing": true}
message_readMessage read{"channel_id": "ch123", "message_id": "msg123"}
Command TypeDescriptionParameter Example
group_member_updateGroup member update{"group_id": "g123", "action": "add", "members": [...]}
group_info_updateGroup info update{"group_id": "g123", "name": "New Group Name"}
group_permission_changeGroup permission change{"group_id": "g123", "user_id": "123", "role": "admin"}

Best Practices

1. Command Handler Pattern

public abstract class CommandHandler {
    protected String commandType;
    
    public CommandHandler(String commandType) {
        this.commandType = commandType;
    }
    
    public abstract void handle(JSONObject params);
    
    public boolean canHandle(String cmdKey) {
        return commandType.equals(cmdKey);
    }
}

public class CommandDispatcher {
    private Map<String, CommandHandler> handlers = new HashMap<>();
    
    public void registerHandler(CommandHandler handler) {
        handlers.put(handler.commandType, handler);
    }
    
    public void dispatch(WKCMD cmd) {
        CommandHandler handler = handlers.get(cmd.cmdKey);
        if (handler != null) {
            handler.handle(cmd.paramJsonObject);
        } else {
            Log.w("CommandDispatcher", "No handler found for command: " + cmd.cmdKey);
        }
    }
}

// Usage example
CommandDispatcher dispatcher = new CommandDispatcher();
dispatcher.registerHandler(new UserStatusCommandHandler());
dispatcher.registerHandler(new MessageRecallCommandHandler());
dispatcher.registerHandler(new SystemNotificationCommandHandler());

WKIM.getInstance().getCMDManager().addCmdListener("Dispatcher", dispatcher::dispatch);

2. Asynchronous Processing

public class AsyncCommandManager {
    private ExecutorService executorService = Executors.newCachedThreadPool();
    
    public void initialize() {
        WKIM.getInstance().getCMDManager().addCmdListener("AsyncManager", this::handleCommandAsync);
    }
    
    private void handleCommandAsync(WKCMD cmd) {
        executorService.execute(() -> {
            try {
                processCommand(cmd);
            } catch (Exception e) {
                Log.e("AsyncCommandManager", "Command processing exception", e);
            }
        });
    }
    
    private void processCommand(WKCMD cmd) {
        // Time-consuming command processing logic
        switch (cmd.cmdKey) {
            case "sync_data":
                syncDataFromServer(cmd.paramJsonObject);
                break;
            case "update_cache":
                updateLocalCache(cmd.paramJsonObject);
                break;
        }
    }
    
    public void destroy() {
        WKIM.getInstance().getCMDManager().removeCmdListener("AsyncManager");
        executorService.shutdown();
    }
}

3. Memory Management

@Override
protected void onDestroy() {
    super.onDestroy();
    
    // Remove all command listeners
    WKIM.getInstance().getCMDManager().removeCmdListener("ActivityKey");
    
    // Clean up command dispatcher
    if (commandDispatcher != null) {
        commandDispatcher.clear();
    }
    
    // Clean up async tasks
    if (executorService != null && !executorService.isShutdown()) {
        executorService.shutdown();
    }
}

Next Steps