会话保持及重复登录检测
定期向服务器发送会话保持信号,并检查是否有其他设备重复登录的 API。
示例代码说明
本文档的示例代码仅供参考。使用 Update() 的回调调用方式会在每帧进行检查,因此在协程中直接调用回调可能更高效。在实际项目中应用时,请根据项目的架构和编码规范自由修改后使用。
URL 确认
此 API 使用 service-account.playnanoo.com 域名。
API 信息
- URL:
https://service-account.playnanoo.com/api/v20240401/alive - Method:
PUT - 需要认证: 是
请求参数
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| platform | string | 必需 | 平台(例如:"aos"、"ios") |
| device_id | string | 必需 | 设备唯一 ID |
| device_model | string | 必需 | 设备型号 |
| device_os | string | 必需 | 设备 OS |
| device_language | string | 必需 | 设备语言(例如:"KO"、"EN") |
DeviceInfo 继承
此 API 的 Req 类继承自 DeviceInfo。DeviceInfo 的所有属性将自动包含。
响应数据
正常响应
| 字段 | 类型 | 说明 |
|---|---|---|
| Status | string | 状态(正常:"success") |
错误响应
| 错误代码 | 说明 |
|---|---|
| 30006 | DuplicatedDeviceException - 已在其他设备上认证 |
Unity C# 实现
CheckAlive 类
using System;
using System.Collections;
using UnityEngine.Networking;
public class CheckAlive
{
static string path = "https://service-account.playnanoo.com/api/v20240401/alive";
[Serializable]
public class Req : DeviceInfo
{
public IEnumerator Send(
Action<Res> onSuccess,
Action<BaseResponse> onError)
{
yield return HttpClient.Send<Req, Res>(
UnityWebRequest.kHttpVerbPUT,
path,
requireToken: true,
body: this,
onSuccess: onSuccess,
onError: onError
);
}
}
[Serializable]
public class Res : BaseResponse
{
public string Status;
}
}
在单例管理器类中添加
在单例管理器中定期调用 CheckAlive 并检测重复登录。
// 变量声明
private bool _isDuplicate = false;
private Coroutine _aliveCoroutine;
private Action<bool> _duplicateCallback;
void Update()
{
// 如果注册了重复检测回调且检测到重复,则调用回调
if (_duplicateCallback != null && _isDuplicate)
{
_duplicateCallback.Invoke(true);
_isDuplicate = false; // 调用一次后重置
}
}
// 开始会话保持(最少 300 秒)
public void CheckAliveStart(int delayTime = 300)
{
if (_aliveCoroutine != null) return;
int timer = delayTime < 300 ? 300 : delayTime;
_aliveCoroutine = StartCoroutine(AliveStatus(timer));
}
// 停止会话保持
public void CheckAliveStop()
{
if (_aliveCoroutine != null)
{
StopCoroutine(_aliveCoroutine);
_aliveCoroutine = null;
}
}
IEnumerator AliveStatus(float delayTime)
{
while (true)
{
yield return new WaitForSeconds(delayTime);
if (string.IsNullOrEmpty(DataManager.Instance.AccessToken)) continue;
CheckAlive.Req req = new CheckAlive.Req();
yield return req.Send(
onSuccess: res =>
{
// 正常响应 - 非重复
},
onError: err =>
{
// 30006: DuplicatedDeviceException - 已在其他设备上认证
if (err != null && err.ErrorCode == "30006")
{
_isDuplicate = true;
}
}
);
}
}
// 注册重复登录检测回调
public void CheckDuplicate(Action<bool> callback)
{
_duplicateCallback = callback;
}
使用示例
基本用法
void Start()
{
// 登录成功后开始会话保持(每 300 秒)
YourSingleton.Instance.CheckAliveStart(300);
// 注册重复登录检测回调
YourSingleton.Instance.CheckDuplicate(OnCheckAccountDuplicate);
}
void OnCheckAccountDuplicate(bool isDuplicate)
{
if (isDuplicate)
{
Debug.LogError("Duplicate connection has been detected.");
// 强制登出处理
// 例如:跳转到登录界面、删除令牌等
}
}
登出时停止会话保持
public void Logout()
{
// 停止会话保持
YourSingleton.Instance.CheckAliveStop();
// 其他登出处理...
}
工作流程
- 登录成功后调用
CheckAliveStart(300) - 每 300 秒向服务器发送 alive 请求
- 正常响应:会话保持
- 错误 30006:已在其他设备登录 →
_isDuplicate = true - Update():检测到重复时调用注册的回调
- 回调处理:强制登出、显示通知等
注意事项
禁止重复调用
CheckAliveStart() 在整个应用中只能调用一次。
- 不能在多个场景或组件中重复调用。
- 重复调用时服务器可能会检测到异常请求模式,导致误报(false positive)重复登录错误(30006)。
- 请使用单例模式在一个地方管理会话保持。
- 虽然在计时器已运行的情况下内部会阻止重复调用,但在结构上建议保持单一调用点。