跳到主要内容

XMDT — Unity

一个 UPM 包 com.alogame.kycsdk,封装了 Android 和 iOS 两页所描述的同一套原生 SDK。原生二进制文件已内置在包中,因此构建时不需要 JitPack、CocoaPods 或 SPM 解析,也无需改动 Gradle 或 Xcode。

环境
环境Base URL
Devhttps://api-xmdt.dev.alogame.vn
Prodhttps://api-xmdt.alogame.vn

两者都已上线。你的 gameId 必须先由 Alogame 运营方开通 XMDT,两个环境才能使用——参见服务器集成。

请先阅读

服务器集成 说明了你的服务器为生成 sessionToken 所需的唯一一次调用。你的客户端从不直接访问 Alogame 的身份 API,也永远看不到你的 HMAC 密钥。

环境要求: Unity 2021.3+、Android minSdkVersion 24+、iOS 15+。必须通过 Unity Hub 安装 Android 和/或 iOS 的 Build Support —— 缺少平台模块时,包内的原生代码路径会被完全编译排除,控制台没有报错并不能说明任何问题。

1. 添加包​

Package Manager → + → Add package from git URL:

https://github.com/alo-game/alogame-kyc-sdk-unity.git#0.1.4

请固定 tag。更新的 tag 见 releases。

这是发布仓库,不是源码仓库

它为每个 tag 发布已编译的 .aar 与 .xcframework,并附带本包自身的 C#/Java/Swift 胶水代码(可读源码)。它不是私有的 gitlab.oeg.vn 源码仓库(你的 Unity 也无权访问)。

请使用 0.1.2 及以上版本

0.1.0 与 0.1.1 发布的 .xcframework 缺少 resource bundle。在 iOS 上,界面绘制的瞬间即崩溃:Fatal error: unable to find bundle named AlogameKycKit_AlogameKycKit。

2. 初始化​

启动时调用一次:

C#
using Alogame.KycSdk;

AlogameKycSdk.Init(AlogameKycEnv.Dev);

在编辑器和桌面平台上,所有调用都是带日志的空操作,因此没有设备也能在 Play Mode 里正常运行游戏。

OEG 品牌游戏

Init 增加了一个可选的第二个参数 brand——AlogameKycBrand.Alo(默认)或 AlogameKycBrand.Oeg。它只改变屏幕头部显示的 logo;env 仍然是选择网络端点的唯一开关。

C#
AlogameKycSdk.Init(AlogameKycEnv.Dev, AlogameKycBrand.Oeg);

3. 设置 game role​

拿到服务器返回的 sessionToken 之后(见服务器集成):

C#
AlogameKycSdk.SetGameRole(
uid: "player_account_name", // 必须与服务器生成 session 时使用的 `username` 一致
sessionToken: sessionToken,
serverId: "server_01", // 可选
roleId: "character_123" // 可选
);

uid 与 sessionToken 总是来自同一次服务器响应 —— 绝不要只传其一。切换到不同的 uid 会清除前一个 uid 已缓存的验证状态。

4. 打开界面​

C#
using UnityEngine;
using Alogame.KycSdk;

public class XmdtFlow : MonoBehaviour
{
public void StartXmdt()
{
AlogameKycSdk.Show(new Listener(this));
}

private sealed class Listener : AlogameKycListener
{
private readonly XmdtFlow _owner;
public Listener(XmdtFlow owner) { _owner = owner; }

public override void OnResult(AlogameKycResult result)
{
switch (result)
{
case AlogameKycResult.Success _:
break; // 仅为 UI 信号 —— 请看下方警告
case AlogameKycResult.Failed f:
Debug.LogWarning("XMDT failed: " + f.Reason + " " + f.Message);
break;
case AlogameKycResult.Cancelled _:
break; // 玩家关闭了表单 —— 仅在 xmdtRequired 为 false 时可能发生
}
}

public override void OnSessionTokenNeeded(string uid)
{
// 见下方“刷新过期 token”
}
}
}
OnResult 只是 UI 信号,不是凭证

Success 表示玩家设备声称流程已完成 —— 被修改过的客户端可以在完全没有验证的情况下伪造这个回调。在放行任何依赖 XMDT 的内容之前,请从你的服务器再次调用 POST /xmdt/session,并以该响应中的 xmdtCompleted 字段为准。见服务器集成。

每次 Show() 只会触发恰好一次 OnResult,且始终在 Unity 主线程上,在原生界面关闭之后 —— 你可以在其中直接调用 Unity API 并展示自己的 UI。OnSessionTokenNeeded 可能在此之前触发零次或多次。

SDK 完全拥有它自己的界面 —— 姓名、出生日期、手机号输入、OTP 和同意条款全部在内部处理,玩家输入的任何内容都不会暴露给你的游戏。

流程已打开时再次调用 Show() 会被忽略(记录日志,不会崩溃)。

已验证过的 uid 不会打开任何界面

如果 session 表明玩家已完成 XMDT,Show() 会直接短路返回 Success,不展示任何界面。这是预期行为 —— 但在测试时意味着每个 uid 只能走一次完整流程。请每次测试都换用新的 uid。

处理 Failed​

C#
switch (f.Reason)
{
case AlogameKycFailReason.NotInitialized:
case AlogameKycFailReason.NoGameRole:
// 你这边的集成错误 —— 没有先调用 Init()/SetGameRole()。
// 绝不要展示给玩家;请修正调用顺序。
break;
case AlogameKycFailReason.SessionUnavailable:
case AlogameKycFailReason.SessionInvalid:
// 无法获得可用的 session token。重新生成一个再重试。
break;
case AlogameKycFailReason.OtpAttemptsExceeded:
case AlogameKycFailReason.OtpUnavailable:
case AlogameKycFailReason.RateLimited:
// 触发了防滥用限制。展示笼统的“请稍后再试” —— 不要暴露具体是哪一种限制。
break;
case AlogameKycFailReason.ServiceUnavailable:
// 玩家已在界面内重试过之后,身份服务仍不可用。让他们稍后再试。
break;
case AlogameKycFailReason.UnknownError:
// 向前兼容的兜底分支。绝不会崩溃。
break;
}

可恢复的问题 —— OTP 输错、校验失败、网络短暂抖动 —— 都在 SDK 界面内部处理,永远不会到达 OnResult。上面每一个 reason 都代表流程无法继续,而不是玩家打错了字。

刷新过期 token​

原生 Android 与 iOS 集成可用的闭包式 tokenProvider 在这里刻意不予暴露:C# 委托无法作为活跃回调跨越 JNI / P-Invoke 边界。Unity 改用委托路径:

C#
public override void OnSessionTokenNeeded(string uid)
{
StartCoroutine(MintThen(uid, token =>
{
if (string.IsNullOrEmpty(token)) AlogameKycSdk.AbortPendingToken();
else AlogameKycSdk.ProvideSessionToken(token);
}));
}

必须且只能响应其中之一。若两者都不实现,过期 token 会让流程以 SessionUnavailable 结束,而不是一直挂起。

这个包会对你的构建做什么​

没有需要你配置的东西 —— 但在此列出,以免出现意外:

Android。 Unity 会把内置的 .aar 合并进它生成的 Gradle 工程。包内的 IPostGenerateGradleAndroidProject 钩子会向该工程追加 org.jetbrains.kotlin:kotlin-stdlib —— 原生 SDK 由 Kotlin 编写,而以裸文件形式内置的 .aar 不带 POM,Gradle 无从得知它的传递依赖。该钩子只做追加,绝不重写你的配置。

iOS。 一个 IPostprocessBuildWithReport 钩子会设置 Unity 不会设置的三项:SWIFT_VERSION(桥接层是 Swift,而 Unity 的模板 target 都不使用 Swift)、AlogameKycKit.framework 的嵌入步骤,以及 LD_RUNPATH_SEARCH_PATHS。缺少最后一项时,App 能干净地构建出来,然后在启动时崩溃:Library not loaded: @rpath/AlogameKycKit.framework/AlogameKycKit。

iOS 构建后请在 Unity 控制台确认这一行 —— 若不存在,说明钩子没有运行,App 启动即会崩溃:

[AlogameKycSdk] embedded the device slice (…) and configured rpath.
请在真机上测试 iOS

真机是唯一经过完整验证的配置。模拟器构建目前尚未跑通:一次尝试被以 “This app needs to be updated by the developer” 拒绝 —— 即 x86_64 二进制运行在 arm64 模拟器运行时上 —— 而强制 ARCHS=arm64 又会在链接阶段失败。

根本原因始终未查明,且更可能是构建配置问题,而非硬性限制。Unity 6000.5 确实提供了 arm64 的模拟器 variation,而本包的 postprocess 钩子在目标 SDK 为模拟器时也已经会选取 .xcframework 中的 simulator slice。请把模拟器视为尚未验证,而不是不可能。

示例​

Package Manager → 本包 → Samples → Reference Scene → Import。把 AlogameKycSample 挂到任意 GameObject 上,在 Inspector 中填入 sessionToken,然后构建到设备。

参考​

成员用途
AlogameKycSdk.Init(env)在其他一切之前调用一次
AlogameKycSdk.SetGameRole(uid, sessionToken, serverId?, roleId?)uid 与 sessionToken 必须同时传入
AlogameKycSdk.SetPrefill(fullName)可选 —— 预填姓名字段
AlogameKycSdk.IsVerified()内存缓存,仅用于 UI 状态 —— 绝不能当作门禁
AlogameKycSdk.Show(listener)打开界面
AlogameKycSdk.ProvideSessionToken(token) / AbortPendingToken()响应 OnSessionTokenNeeded
AlogameKycEnvDev | Prod
AlogameKycResultSuccess | Failed(Reason, Message) | Cancelled
AlogameKycFailReason9 个封闭取值 —— 见上文
AlogameKycListener抽象类:OnResult(必须实现)、OnSessionTokenNeeded(可选)

AlogameKycListener 采用抽象类而非带默认成员的接口,因此本包可在 2021.3 起的所有 Unity 版本上工作,而不需要 2021.2+ 才具备的 C# 8 支持。

IsVerified() 读取的是最近一次成功流程留下的内存缓存 —— 不是授权依据,与 OnResult 的注意事项相同。仅用于 UI 状态,绝不能当作门禁本身。