更新时间:2025-11-20 10:07:45下载pdf
多端登录功能允许用户查看当前账号已在哪些设备上登录,并支持远程登出指定设备。本文档介绍如何使用 SDK 提供的多端登录相关接口。
多端登录功能包含以下核心接口:
getUserLoginMultiTerminal:获取当前账号在哪些设备上登录。getMultiTerminalLogoutCode:获取设备登出校验码 loginOutCode。logoutMultiTerminal:指定登出某台设备。registerTerminalLogoutListener:注册账号被登出监听(当账号在其他设备上被登出时接收通知)。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)
username 和 password:必填ifencrypt:必须为 truecode:传 null直接调用该方法即可完成验证并获取 loginOutCode。
方式二:验证码验证(verifyType = 2)
username 和 code:必填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")
}
})
当账号在其他设备上被登出时,当前设备可以通过监听器接收到通知。这能有效满足及时响应用户在其他设备上的登出操作的需求,例如:清理本地缓存、跳转到登录页面等。
请注意,该功能需要依赖 thingsmart-businessapiextensionkit 模块。
fun registerTerminalLogoutListener(callback: INotificationCallback)
fun unregisterTerminalLogoutListener()
INotificationCallback
interface INotificationCallback {
fun onSuccess()
}
import com.thingclips.businessapiextensionkit.ThingSmartExtNotificationFunc
import com.thingclips.businessapiextensionkit.callback.INotificationCallback
// 注册监听
ThingSmartExtNotificationFunc.registerTerminalLogoutListener(object : INotificationCallback {
override fun onSuccess() {
// 账号在其他设备上被登出
Log.d("MultiTerminal", "账号被其他设备登出")
// 执行清理操作,例如:
// 1. 清理本地用户数据
// 2. 跳转到登录页面
// 3. 清理缓存等
handleTerminalLogout()
}
})
// 注销监听(在不需要时调用,例如 Activity 销毁时)
ThingSmartExtNotificationFunc.unregisterTerminalLogoutListener()
class MainActivity : AppCompatActivity() {
private var terminalLogoutCallback: INotificationCallback? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 确保已初始化(如果用户刚登录,需要先初始化)
if (!ThingSmartExtNotificationFunc.isInitialized()) {
ThingSmartExtNotificationFunc.initialize()
}
// 注册多终端登出监听
terminalLogoutCallback = object : INotificationCallback {
override fun onSuccess() {
runOnUiThread {
// 账号被其他设备登出,执行清理操作
Log.d("MultiTerminal", "账号被其他设备登出")
// 清理用户数据
ThingHomeSdk.getUserInstance().removeUser()
// 跳转到登录页面
val intent = Intent(this@MainActivity, LoginActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
}
}
}
ThingSmartExtNotificationFunc.registerTerminalLogoutListener(terminalLogoutCallback!!)
}
override fun onDestroy() {
super.onDestroy()
// 注销监听,避免内存泄漏
terminalLogoutCallback?.let {
ThingSmartExtNotificationFunc.unregisterTerminalLogoutListener()
}
}
}
当用户退出登录时,ThingSmartExtNotificationFunc 的资源会被自动销毁。因此,在用户登录成功后,需要重新调用 initialize() 方法进行初始化,然后才能注册监听器。
初始化示例
// 在用户登录成功后调用
ThingSmartExtNotificationFunc.initialize()
// 初始化完成后,注册监听器
ThingSmartExtNotificationFunc.registerTerminalLogoutListener(object : INotificationCallback {
override fun onSuccess() {
// 处理账号被登出的逻辑
}
})
完整示例:在登录成功后初始化
// 登录成功回调中
fun onLoginSuccess() {
// 1. 初始化多终端登出监听功能
ThingSmartExtNotificationFunc.initialize()
// 2. 注册监听器
ThingSmartExtNotificationFunc.registerTerminalLogoutListener(object : INotificationCallback {
override fun onSuccess() {
// 账号在其他设备上被登出
handleTerminalLogout()
}
})
}
资源销毁机制:当前账号退出登录时,ThingSmartExtNotificationFunc 的资源会被自动销毁(调用 destroy() 方法),此时 isInitialized 会被设置为 false。
登录后重新初始化:由于退出登录时资源会被销毁,因此在用户重新登录成功后,必须重新调用 initialize() 方法进行初始化,然后才能注册监听器。否则监听器无法正常工作。
监听器注册时机:建议在用户登录成功后立即调用 initialize() 初始化,然后注册监听器,确保能够及时接收到登出通知。
监听器注销:在不需要监听时(例如 Activity 销毁、用户退出登录等),务必调用 unregisterTerminalLogoutListener() 注销监听,避免内存泄漏。
线程安全:onSuccess() 回调可能不在主线程执行,如果需要在回调中更新 UI,请使用 runOnUiThread() 或 Handler 切换到主线程。
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。
username 和 password:必填ifencrypt:必须为 truecode:传 nullgetMultiTerminalLogoutCode 即可,无需预先调用其他接口username 和 code:必填password:可不填写(传 null)ifencrypt:传 falsesendVerifyCodeWithUserName 发送验证码(type=8),获取验证码后再调用本方法所有接口都提供了错误回调,建议在 UI 上给用户友好的错误提示。
可以通过对比 terminalId 与当前设备的标识来判断是否为当前设备,避免误登出当前正在使用的设备。
建议在应用启动时注册 registerTerminalLogoutListener 监听器,以便及时响应账号在其他设备上被登出的情况,及时清理本地数据并引导用户重新登录。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈