多端登录管理

更新时间:2026-01-08 02:48:44下载pdf

概述

多端登录功能允许用户查看当前账号已在哪些设备上登录,并支持远程登出指定设备。本文档介绍如何使用 SDK 提供的多端登录相关接口。

功能说明

多端登录功能包含以下核心接口:

  • getUserLoginMultiTerminal:获取当前账号在哪些设备上登录。
  • getMultiTerminalLogoutCode:获取设备登出校验码 loginOutCode
  • logoutMultiTerminal:指定登出某台设备。

接口说明

获取登录设备列表

方法签名

void getUserLoginMultiTerminal(IUserBusinessCallback<UserLoginMultiterminalVO> callback)

功能描述

获取当前账号在所有设备上的登录信息,包括设备 ID、操作系统、平台、登录状态和登录时间等。

参数说明

参数 类型 说明
callback IUserBusinessCallback 回调接口,返回登录设备列表

回调接口

IUserBusinessCallback<UserLoginMultiterminalVO>

public interface IUserBusinessCallback<ResponseValue> {
    /**
     * 成功回调
     * @param success 返回 UserLoginMultiterminalVO 对象
     */
    void onSuccess(ResponseValue success);

    /**
     * 失败回调
     * @param code 错误码
     * @param error 错误信息
     */
    void onError(String code, String error);
}

返回数据模型

UserLoginMultiterminalVO

public class UserLoginMultiterminalVO {
    private List<UserLoginMultiterminalBean> terminalLoginList;

    public List<UserLoginMultiterminalBean> getTerminalLoginList() {
        return terminalLoginList;
    }
}

UserLoginMultiterminalBean

public class UserLoginMultiterminalBean {
    private String terminalId;      // 设备唯一标识
    private String os;              // 操作系统
    private String osSystem;        // 操作系统版本
    private String platform;        // 平台信息
    private Integer status;         // 会话状态:0 - 无效,1 - 有效
    private Long loginTime;        // 登录时间(时间戳)

    // Getter 和 Setter 方法
    public String getTerminalId() { return terminalId; }
    public String getOs() { return os; }
    public String getOsSystem() { return osSystem; }
    public String getPlatform() { return platform; }
    public Integer getStatus() { return status; }
    public Long getLoginTime() { return loginTime; }
}

使用示例

ThingHomeSdk.getUserInstance().getUserLoginMultiTerminal(object : IUserBusinessCallback<UserLoginMultiterminalVO> {
    override fun onSuccess(result: UserLoginMultiterminalVO) {
        val deviceList = result.terminalLoginList
        if (!deviceList.isNullOrEmpty()) {
            for (device in deviceList) {
                Log.d("MultiTerminal", "设备ID: ${device.terminalId}")
                Log.d("MultiTerminal", "操作系统: ${device.os}")
                Log.d("MultiTerminal", "平台: ${device.platform}")
                Log.d("MultiTerminal", "状态: ${if (device.status == 1) "有效" else "无效"}")
                Log.d("MultiTerminal", "登录时间: ${Date(device.loginTime)}")
            }
        }
    }

    override fun onError(code: String, error: String) {
        Log.e("MultiTerminal", "获取设备列表失败: $code - $error")
    }
})

获取设备登出校验码

方法签名

void getMultiTerminalLogoutCode(String countryCode, String username, String password, 
                                String code, Boolean ifencrypt, 
                                Integer type, Integer verifyType, 
                                IUserBusinessCallback<MultiTerminalBean> callback)

功能描述

在进行设备登出操作前,需要先进行账号验证,验证通过后获取登出校验码 loginOutCode。该校验码用于后续的登出操作。

密码校验和验证码校验,都只需直接调用该方法,无需预先调用其他接口。

参数说明

参数 类型 必填 说明
countryCode String 国家区号,例如:“86”
username String 用户名(手机号或邮箱)
password String 条件必填 密码(当 verifyType = 1 时必填,当 verifyType = 2 时可为空)
code String 条件必填 验证码(当 verifyType = 2 时必填,当 verifyType = 1 时为空)
ifencrypt Boolean 密码是否加密(当 verifyType = 1 时必须为 true,当 verifyType = 2 时可传 false
type Integer 账号类型:1 - 手机号,2 - 邮箱
verifyType Integer 验证方式:1 - 密码验证,2 - 验证码验证
callback IUserBusinessCallback 回调接口

验证方式说明

  • 方式一:密码验证(verifyType = 1)

    • usernamepassword:必填
    • ifencrypt:必须为 true
    • code:传 null

    直接调用该方法即可完成验证并获取 loginOutCode

  • 方式二:验证码验证(verifyType = 2)

    • usernamecode:必填
    • password:可不填写(传 null
    • ifencrypt:传 false

    使用验证码验证时,需要先调用 sendVerifyCodeWithUserName 发送验证码(type = 8),获取验证码后再调用本方法。

返回数据模型

MultiTerminalBean

public class MultiTerminalBean {
    private String loginOutCode;    // 登出校验码
    private long expireTime;        // 校验码过期时间(秒级时间戳)

    public String getLoginOutCode() {
        return loginOutCode;
    }

    public long getExpireTime() {
        return expireTime;
    }
}

使用示例

示例 1:使用密码验证

val countryCode = "86"
val username = "13800138000"  // 手机号或邮箱
val password = "your_password"
val type = 1  // 1 - 手机号,2 - 邮箱
val verifyType = 1  // 1 - 密码验证

ThingHomeSdk.getUserInstance().getMultiTerminalLogoutCode(
    countryCode,
    username,
    password,
    null,  // code
    true,   // ifencrypt 必须为 true
    type,
    verifyType,
    object : IUserBusinessCallback<MultiTerminalBean> {
        override fun onSuccess(result: MultiTerminalBean) {
            val loginOutCode = result.loginOutCode
            val expireTime = result.expireTime
            Log.d("MultiTerminal", "登出校验码: $loginOutCode")
            Log.d("MultiTerminal", "过期时间: ${Date(expireTime * 1000)}")
            // 保存 loginOutCode,用于后续登出操作
        }

        override fun onError(code: String, error: String) {
            Log.e("MultiTerminal", "获取登出校验码失败: $code - $error")
        }
    }
)

示例 2:使用验证码验证

// 步骤 1:发送验证码
val countryCode = "86"
val username = "13800138000"
val type = 1  // 1 - 手机号,2 - 邮箱

ThingHomeSdk.getUserInstance().sendVerifyCodeWithUserName(
    username,
    null,  // region
    countryCode,
    8,     // type = 8,表示登出账号验证验证码
    object : IResultCallback {
        override fun onSuccess() {
            // 验证码发送成功,提示用户输入验证码
        }

        override fun onError(code: String, error: String) {
            Log.e("MultiTerminal", "发送验证码失败: $code - $error")
        }
    }
)

// 步骤 2:用户输入验证码后,获取登出校验码
val verifyCode = "123456"  // 用户输入的验证码
val verifyType = 2  // 2 - 验证码验证

ThingHomeSdk.getUserInstance().getMultiTerminalLogoutCode(
    countryCode,
    username,
    null,  // password 验证码验证时可不填写
    verifyCode,  // code 验证码
    false, // ifencrypt
    type,
    verifyType,
    object : IUserBusinessCallback<MultiTerminalBean> {
        override fun onSuccess(result: MultiTerminalBean) {
            val loginOutCode = result.loginOutCode
            // 保存 loginOutCode,用于后续登出操作
        }

        override fun onError(code: String, error: String) {
            Log.e("MultiTerminal", "获取登出校验码失败: $code - $error")
        }
    }
)

登出指定设备

方法签名

void logoutMultiTerminal(String terminalId, String loginOutCode, IBooleanCallback callback)

功能描述

使用设备 ID 和登出校验码,远程登出指定的设备。登出成功后,该设备将无法继续使用当前账号。

参数说明

参数 类型 必填 说明
terminalId String 设备唯一标识,从 getUserLoginMultiTerminal 获取
loginOutCode String 登出校验码,从 getMultiTerminalLogoutCode 获取
callback IBooleanCallback 回调接口

回调接口

IBooleanCallback

public interface IBooleanCallback {
    /**
     * 成功回调
     */
    void onSuccess();

    /**
     * 失败回调
     * @param code 错误码
     * @param error 错误信息
     */
    void onError(String code, String error);
}

使用示例

// terminalId 从 getUserLoginMultiTerminal 获取
val terminalId = "device_terminal_id_12345"
// loginOutCode 从 getMultiTerminalLogoutCode 获取
val loginOutCode = "logout_code_abc123"

ThingHomeSdk.getUserInstance().logoutMultiTerminal(terminalId, loginOutCode, object : IBooleanCallback {
    override fun onSuccess() {
        Log.d("MultiTerminal", "设备登出成功")
        // 可以刷新设备列表,确认设备已登出
    }

    override fun onError(code: String, error: String) {
        Log.e("MultiTerminal", "设备登出失败: $code - $error")
    }
})

账号被登出监听

功能描述

当账号在其他设备上被登出时,当前设备可以通过监听器接收到通知。这能有效满足及时响应用户在其他设备上的登出操作的需求,例如:清理本地缓存、跳转到登录页面等。

方法签名

ThingHomeSdk.setOnNeedLoginListener(INeedLoginListener needLoginListener);

回调接口

needLoginListener.onNeedLogin(Context context);

使用示例

ThingHomeSdk.setOnNeedLoginListener(new INeedLoginListener() {
  @Override
  public void onNeedLogin(Context context) {

  }
});

完整使用流程

场景:用户查看登录设备并登出其他设备

class MultiTerminalManager {
    private val userManager: IThingUser = ThingHomeSdk.getUserInstance()

    /**
     * 步骤 1:获取登录设备列表
     */
    fun getLoginDevices() {
        userManager.getUserLoginMultiTerminal(object : IUserBusinessCallback<UserLoginMultiterminalVO> {
            override fun onSuccess(result: UserLoginMultiterminalVO) {
                val deviceList = result.terminalLoginList
                // 显示设备列表给用户
                displayDeviceList(deviceList)
            }

            override fun onError(code: String, error: String) {
                Log.e("MultiTerminal", "获取设备列表失败: $code - $error")
            }
        })
    }

    /**
     * 步骤 2:用户选择要登出的设备,进行账号验证并获取登出校验码
     * 使用密码验证方式
     */
    fun prepareLogoutDeviceWithPassword(
        terminalId: String,
        countryCode: String,
        username: String,
        password: String,
        type: Int
    ) {
        userManager.getMultiTerminalLogoutCode(
            countryCode,
            username,
            password,
            null,  // code
            true,   // ifencrypt 密码验证时必须为 true
            type,
            1,      // 使用密码验证
            object : IUserBusinessCallback<MultiTerminalBean> {
                override fun onSuccess(result: MultiTerminalBean) {
                    val loginOutCode = result.loginOutCode
                    // 步骤 3:执行登出操作
                    logoutDevice(terminalId, loginOutCode)
                }

                override fun onError(code: String, error: String) {
                    Log.e("MultiTerminal", "获取登出校验码失败: $code - $error")
                }
            }
        )
    }

    /**
     * 步骤 2:用户选择要登出的设备,进行账号验证并获取登出校验码
     * 使用验证码验证方式
     */
    fun prepareLogoutDeviceWithCode(
        terminalId: String,
        countryCode: String,
        username: String,
        verifyCode: String,
        type: Int
    ) {
        userManager.getMultiTerminalLogoutCode(
            countryCode,
            username,
            null,  // password 验证码验证时可不填写
            verifyCode,  // code
            false, // ifencrypt
            type,
            2,     // 使用验证码验证
            object : IUserBusinessCallback<MultiTerminalBean> {
                override fun onSuccess(result: MultiTerminalBean) {
                    val loginOutCode = result.loginOutCode
                    // 步骤 3:执行登出操作
                    logoutDevice(terminalId, loginOutCode)
                }

                override fun onError(code: String, error: String) {
                    Log.e("MultiTerminal", "获取登出校验码失败: $code - $error")
                }
            }
        )
    }

    /**
     * 步骤 3:登出指定设备
     */
    private fun logoutDevice(terminalId: String, loginOutCode: String) {
        userManager.logoutMultiTerminal(terminalId, loginOutCode, object : IBooleanCallback {
            override fun onSuccess() {
                Log.d("MultiTerminal", "设备登出成功")
                // 刷新设备列表
                getLoginDevices()
            }

            override fun onError(code: String, error: String) {
                Log.e("MultiTerminal", "设备登出失败: $code - $error")
            }
        })
    }

    private fun displayDeviceList(deviceList: List<UserLoginMultiterminalBean>?) {
        // 在 UI 上显示设备列表
    }
}

注意事项

登录状态要求

调用这些接口前,需要确保用户已登录(ThingHomeSdk.getUserInstance().isLogin() 返回 true)。

校验码有效期

loginOutCode 有时效性,从 getMultiTerminalLogoutCode 返回的 expireTime 可以获取过期时间。建议在获取后尽快使用。

设备标识

terminalId 是设备的唯一标识,用于区分不同的登录设备。同一个账号在不同设备上登录会有不同的 terminalId

验证方式选择:

  • 密码验证(verifyType = 1):
    • usernamepassword:必填
    • ifencrypt:必须为 true
    • code:传 null
    • 直接调用 getMultiTerminalLogoutCode 即可,无需预先调用其他接口
  • 验证码验证(verifyType = 2):
    • usernamecode:必填
    • password:可不填写(传 null
    • ifencrypt:传 false
    • 需要先调用 sendVerifyCodeWithUserName 发送验证码(type=8),获取验证码后再调用本方法

错误处理

所有接口都提供了错误回调,建议在 UI 上给用户友好的错误提示。

当前设备识别

可以通过对比 terminalId 与当前设备的标识来判断是否为当前设备,避免误登出当前正在使用的设备。

当前设备标识 deviceId 获取方法如下:

String deviceId = PhoneUtil.getDeviceID(mContext);

账号被登出监听

建议在应用启动时注册 ThingHomeSdk.setOnNeedLoginListener(INeedLoginListener needLoginListener) 监听器,以便及时响应账号在其他设备上被登出的情况,及时清理本地数据并引导用户重新登录。