# 首款外部游戏 SDK 接入验收清单

更新日期：2026-09-11。本文依据当前仓库实现编写，用于外部 H5 游戏和 Android 游戏的首次接入。复选框代表待完成的接入验收，不代表已经在外部游戏或真实支付环境通过。

## 1. 当前交付边界

| 部分 | 已有交付 | 首款外部游戏仍需完成 |
| --- | --- | --- |
| H5 SDK | `packages/sdk/starlight-sdk-0.1.0.tgz`；ESM、CommonJS、浏览器 IIFE（`window.Starlight`）、自包含类型声明；业务 API、PKCE、事件及会话管理 | 自己的游戏后端兑换接口、平台应用配置、游戏身份接入和实际页面适配 |
| H5 界面 | `apps/playground` 中的 React 参考 UI，包含登录、侧边中心、悬浮球和演示场景 | 提取 UI 并适配宿主样式、画布、横竖屏、iframe、软键盘和输入事件；无界面 SDK 不会自动注入这些 UI |
| Android SDK | `android/dist/starlight-sdk-0.1.0.aar`；原生登录、游戏内悬浮球、平台中心、钱包订单、设备管理；SDK 与示例 Java 编译通过 | Android Studio/Gradle 完整构建、实际 APK 集成、真机或模拟器运行及生命周期验收 |
| 账号服务 | 登录、用途隔离验证码、找回密码、游戏标识映射、一次性凭证兑换、有效会话撤销 | 外部游戏配置与注册生命周期、真实短信和正式账号运营流程 |
| 角色与发货 | 当前按账号与逻辑游戏生成一个内置演示角色，发货直接更新本地 SQLite 演示资产 | 外部角色可信绑定、多区服/多角色模型、远端游戏履约协议与回调 |
| 充值 | 演示支付与内部平台币记账，优惠券、订单关闭、演示退款、对账 | 正式支付供应商、支付通知验签、远程履约签名、实际退款与资金核对 |

当前不是无需游戏方配合即可替换任意现成游戏账号的工具。首次接入应先完成账号闭环，再扩展角色和充值。正式部署不能把本地演示服务、演示密钥或演示支付开关直接作为上线配置。

## 2. 接入准备与应用映射

- [ ] 确定游戏名称、负责方、接入域名/包名、后端负责人、角色和商品来源。
- [ ] 为 H5 与 Android 分别分配 `appId`，在平台可信配置中绑定同一个逻辑 `gameId`，用于同游戏两端身份互通。
- [ ] 为不同游戏使用不同逻辑 `gameId`；验证同一平台账号在不同游戏得到不同 `gameUserId`，角色、礼包和订单范围不串用。
- [ ] 外部接入不复用 `starlight-h5`、`starlight-android`、`starlight-second` 这些演示标识。
- [ ] 在开发者控制台创建逻辑游戏及 H5 / Android 客户端，提交平台审核；审核开通后取得 App ID，并按受控流程配置或轮换服务端密钥。应用扩端与敏感资料变更需重新审核。
- [ ] 明确新增 `gameId` 的角色初始化策略。当前注册逻辑仅为内置 `star-realm`、`moon-realm` 建立演示角色；单独添加新 app 记录不能自动获得完整外部游戏支持。
- [ ] 为首款游戏配置独立服务端兑换凭据，限定其应用范围；密钥不进入网页、APK、资源文件、埋点、公开配置或浏览器日志。
- [ ] 区分平台账号令牌和游戏自己的业务会话；令牌传输走 HTTPS，跨域仅允许实际接入域名，日志脱敏。

同账号互通只代表身份映射相同。两端进度互通仍依赖游戏自己的存档与角色后端，不能由 SDK 单独保证。

## 3. 必须通过的账号交换闭环

1. 客户端初始化对应 `appId`，玩家主动提交登录并同意当前版本协议。
2. SDK 生成随机 `codeVerifier`、S256 `codeChallenge` 和 `state`，向账号服务提交登录。
3. SDK 校验返回的 `state`，取得短期一次性 `code`。
4. 客户端把 `{ appId, code, codeVerifier }` 发送到自己的游戏后端。
5. 游戏后端调用 `POST /api/server/auth/exchange`，通过 `X-API-Key` 提供服务端凭据，兑换平台会话与可信身份。
6. 游戏后端按可信 `gameUserId` 查找或创建自身玩家，建立游戏业务会话；将 SDK 所需 `SessionResponse` 返回客户端。不要直接把平台会话当成所有游戏接口的通用授权。
7. H5 的 `exchange` 回调返回兑换结果；Android 使用原始 `Authorization` 对象调用 `completeGameLogin(authorization, result)`。

- [ ] 服务端错误密钥、错误 appId、错误 verifier、过期 code、重复兑换全部拒绝。
- [ ] 客户端关闭登录、切换账号或 Activity 销毁后，旧响应不能恢复旧身份。
- [ ] 后端兑换失败时显示真实错误；不能凭客户端 ID、昵称或“登录成功”事件自行建立可信身份。
- [ ] 游戏后端有请求超时和适当重试/状态处理；一次性 code 已消费后不能无限重放。
- [ ] 接入正式流程不调用 `/api/demo/game/session` 或 Android `exchangeWithDemoBackend`。
- [ ] 退出、封禁、密码重置、当前设备撤销会清理游戏旧角色、连接、聊天订阅及内存缓存。
- [ ] 明确平台会话撤销与游戏独立会话的关联策略。当前没有自动向外部游戏推送“退出/封禁”事件；游戏后端需补验证、同步或撤销通道，不能承诺外部游戏会话自动立即失效。

## 4. 首款外部 H5 游戏

- [ ] 通过实际 `.tgz` 安装，或复制 SDK `dist` 产物到自己的静态资源服务；验证没有依赖未发布的 contracts 类型包。
- [ ] 根据宿主选择 ESM 或普通 script IIFE。IIFE 调用 `new Starlight.StarlightSDK(...)`；ESM 导入 `StarlightSDK`。
- [ ] 提供游戏后端 `exchange` 回调；`openCenter`、`showFloating`、`hideFloating` 是通知宿主 UI 的事件能力，不会自行渲染面板。
- [ ] 为 `center`、`floating`、`session`、`error` 事件实现宿主处理，并在组件卸载时取消监听。
- [ ] 复用 React 参考 UI 时，替换演示游戏场景与固定 appId，并将角色、商品与订单页面接到实际模型。
- [ ] 在真实目标浏览器测试 Web Crypto、Fetch、structuredClone 和 ES2022；使用 HTTPS 或 localhost 安全上下文。
- [ ] 若游戏位于 iframe，决定 SDK 所在层级；悬浮球不能自动跨 iframe 边界，跨窗口通信必须明确校验来源和消息结构。
- [ ] 验证横屏/竖屏、触摸拖动吸边、游戏画布点击穿透、全屏切换、键盘弹起、Tab/Esc 和屏幕阅读器标签。
- [ ] 分别验证打开弹窗后取消、支付中关闭弹窗、切号后旧响应返回、断网后重试及页面刷新。SDK 默认内存模式；参考 H5 已启用 sessionStorage，刷新时先 `/api/me` 验证候选，再恢复登录，宿主可按需求接入同一适配器。
- [ ] 验证登录后连续刷新、退出后刷新、会话撤销后刷新、过期后刷新、恢复时断网与重试、不同 appId/API origin 隔离；不得在服务端验证前显示已登录身份。
- [ ] sessionStorage 仅用于标签页会话恢复，JavaScript 仍可访问其中凭据；不把它当作 HttpOnly cookie 或长期自动登录方案。外部游戏自己的会话也需要恢复。
- [ ] 使用当前有效会话列表验证退出其他设备、退出当前设备和改密后的会话变化。

## 5. 首款外部 Android 游戏

- [ ] 宿主引入真实 AAR，使用兼容 AGP/Gradle/JDK 和最低 API 23；完成 Manifest 合并、R8 混淆与签名 APK 构建。
- [ ] 正式 `Config` 使用 HTTPS origin 和 `demo=false`。示例允许明文的 Manifest 仅限本地演示，不能不加区分复制到正式宿主。
- [ ] SDK 网络权限合并通过；悬浮球附着宿主 Activity，不申请跨应用悬浮权限。
- [ ] 在主线程调用涉及 UI 的方法，绑定原始授权对象完成登录；不用已弃用的单参数 `completeGameLogin`。
- [ ] **首款集成采用示例的每 Activity 生命周期策略：Activity 销毁时 `sdk.destroy()`，宿主清空 SDK 引用；新 Activity 新建实例并重新登录。**
- [ ] `detachActivity()` 仅拆除浮球、对话框并使旧界面事务失效，不清除其 `final Listener`。它不是 listener 重绑定或完整释放接口。
- [ ] 不在旧 Activity 实现 Listener 的情况下，跨 Activity 重建复用同一个 SDK。即使调用 `destroy()`，若外部单例仍强引用 SDK，也会通过 Listener 保留旧 Activity；必须同时释放外部引用。
- [ ] 如需跨 Activity 保留会话，先设计非 Activity 的生命周期路由监听器并解绑旧宿主，或后续实现受控宿主重绑定能力；当前示例没有提供该方案。
- [ ] 实测旋转、Activity 重建、返回键、后台/前台、低内存进程恢复、连续开关平台中心、设备撤销时窗口关闭及迟到回调。
- [ ] 实测软键盘遮挡、刘海/挖孔安全区、系统手势、多窗口、主流 ROM、网络切换与弱网。
- [ ] 实测平台中心进入设备管理、撤销本设备、其他设备、全部其他设备；页面不保留旧账户资料。
- [ ] 用模拟器 `10.0.2.2:18787` 或真机 `adb reverse` 验证本地服务；再用受控 HTTPS 测试环境验证证书与网络策略。

当前 AAR 与示例 Java 已编译，尚未完成真机/模拟器运行验收，不把编译通过等同于上述检查通过。H5 与 Android 页面功能也并非完全一致；例如 Android 当前没有 H5 的完整忘记密码和改密界面，首次接入需决定扩展原生页或可信的账号中心入口。

## 6. 角色绑定与多区服缺口

当前 `SessionResponse.role` 来自平台内置角色，每个账号与逻辑游戏只有一个角色。礼包和订单校验其 `roleId`，任意外部角色 ID 将返回 `ROLE_FORBIDDEN`。不能仅在前端把 `roleId` 替换为正式游戏角色。

- [ ] 定义 `gameUserId`、区服 ID、外部角色 ID、角色名称之间的可信映射，明确多角色选择及角色转服规则。
- [ ] 由游戏后端创建/上报绑定，并验证角色属于当前玩家；客户端字段仅作为选择意图，不能作为归属证据。
- [ ] 扩展平台角色模型、创建/同步接口、查询接口及订单关联，替换目前“账号 + gameId 单角色”的假设。
- [ ] 校验订单绑定角色、礼包领取角色和游戏发货角色一致；切角色后旧订单仍保持创建时目标，不随客户端当前角色改变。
- [ ] 以两账号、两角色、两区服、同游戏两端及另一逻辑游戏组合验证隔离。
- [ ] 角色删除、转服、合服或订单付款后角色不可用时，有明确失败、补发及人工处理流程。

## 7. 订单、真实支付和远端履约

当前可创建订单，使用 `demo` 或内部 `wallet` 支付，并直接更新演示资产。没有已经接通的微信/支付宝/渠道充值 SDK，也没有用于外部游戏发货的签名回调实现。

- [ ] 商品由可信后台/游戏后端定义，使用整数分和服务端商品快照；不信任客户端价格、钻石数量或优惠额度。
- [ ] 按实际发行渠道接入支付供应商，明确收款主体、商品范围、退款及结算责任。
- [ ] 补支付下单、供应商凭据管理、异步通知验签、订单查询、超时关闭、证书轮换和退款回调。
- [ ] 校验回调中的商户、应用、订单、金额、币种及交易状态，拒绝伪造、重放或跨订单通知。
- [ ] 客户端“支付成功”仅用于提示与查询，不作为发货凭据。
- [ ] 为平台到游戏后端设计履约协议：订单号、目标角色、商品快照、发货事件 ID、时间戳、签名版本及可验证的服务端签名。
- [ ] 游戏后端验证签名和目标应用，以发货事件/订单唯一键幂等入账；返回可查询的处理结果，不以 HTTP 200 单独代替到账事实。
- [ ] 平台维护持久化重试、指数退避、死信/人工补单和审计；区分“付款已确认”和“游戏已履约”。
- [ ] 增加外部资产回收/退款协议；当前直接回收 SQLite 演示钻石，不能代表远端游戏可以退款。
- [ ] 未支付订单可以取消且释放占券；取消与支付并发时以服务端最终状态为准。付款成功订单不能走未付关闭流程。
- [ ] 继续支付先查原订单；创建失败重试保留原 requestId。模拟断网发生在请求前、付款后与返回前，确认不会重复扣款/发货。
- [ ] 做平台、供应商及游戏三方对账；金额、付费平台币、赠送余额分别核对，正式资金不得沿用演示初始余额。
- [ ] 跨厂商平台币、平台月卡与优惠补贴在接入前明确使用范围、发放来源和结算规则；当前演示钱包按平台账号共享，并非完整的跨厂商清结算系统。

在真实支付和远端履约未完成前，首款外部游戏只验收账号或清晰标识的沙箱充值，不向真实玩家承诺充值到账。

## 8. Unity / Cocos 桥接顺序

| 优先级 | 交付内容 | 验收要点 |
| --- | --- | --- |
| P0 | 一款实际 H5 宿主 + 一款原生 Android 宿主完成账号交换与退出 | 先验证平台/游戏服务端边界，再复制接入方式 |
| P1 | 首款目标引擎的桥接；按已确定的 Unity 或 Cocos 版本实现 | 初始化、登录、退出、悬浮球、中心入口、主线程回调、错误与取消、Activity 生命周期 |
| P1 | 该引擎的角色绑定和订单桥接 | 只传身份/角色选择意图；价格与发货由服务端校验，回调不直接加资产 |
| P2 | 第二种引擎与版本兼容矩阵 | 插件安装、构建模板、混淆、横竖屏、全屏、触摸事件与包体依赖冲突 |

Unity Android 可通过 JNI/C# 桥接 Java SDK，Unity WebGL 需 JavaScript 插件适配；Cocos Web 可接 JavaScript SDK，Cocos Android 需按目标版本实现原生反射/JNI/脚本桥接。当前仓库未交付已验收的 Unity 或 Cocos 插件，不能把提供 AAR/JS 等同于这些引擎即插即用。

## 9. 首款接入交付证据

- [ ] 保存接入应用映射、服务端密钥范围、协议版本和环境说明；不把密钥写入验收文档。
- [ ] 保存 SDK/AAR 版本、文件 SHA-256、游戏构建版本及设备/浏览器版本。
- [ ] 保存登录、取消、切号、会话撤销、角色隔离、未付订单关闭和支付重试的脱敏记录。
- [ ] 若含支付，保存真实供应商沙箱及远端游戏后端的验签、幂等、掉单补发和退款测试结果。
- [ ] Android 保存安装运行、旋转、返回、软键盘及低内存场景的实际记录；不能以 Java 编译日志代替。
- [ ] 明确未通过项及是否阻止首发，由游戏接入负责人、平台后端负责人和测试负责人共同确认。

现有本地长测与 SDK 自动化结果见 `docs/SOAK_TEST.md`、`reports` 和 SDK 测试。它们支持当前演示实现的稳定性判断，但不覆盖尚未接入的外部游戏、真实支付供应商或 Android 设备运行。

## 本轮 H5 / Android 接口审计补充

Android 已补齐 headless 授权、密码、订单/权益/消息/客服API；新增 exportSession/restoreSession 显式候选恢复，宿主加密保存、验证前不发布、退出删除保存数据。它们不自动提供对应的新原生页面，final Listener 生命周期和真机验收仍必须完成。

H5 已修复恢复到期内存会话时旧身份残留，工单列表支持 limit/before/nextCursor 和单工单读取；支付/退款/礼包/优惠/每日福利支持可选 requestId 供稳定重试。无独立注册路由，验证码首登自动注册。现有开发者控制台已支持应用创建、审批、扩端复审和密钥轮换，接入使用实际开通的 App ID；新逻辑游戏可建立隔离内置演示角色，但不是外部多区服/角色已接通。

验证明确失效与业务401的区别、公开短信/登录不携带旧token、恢复期间断网/取消/切号、API origin与App ID隔离、订单重试和工单第二页。真实支付、外部履约与设备运行边界不变。
