Skip to content

AstralVR SDK 架构设计 ​

从 0 到 1 主导面向开发者的 AstralVR SDK 核心架构设计,运用面向接口编程与表驱动法,模块耦合度降低约 40%。

模块耦合度↓ 约 40%
功能模块6 个
扩展成本1 行注册

背景 ​

亿真网络在做元宇宙 UGC 平台 AstralVR。平台的内容供给依赖第三方开发者:他们需要一个 SDK,把自己在 Unity 里做的 3D 内容打包、统计、压缩并上传到平台。我作为 U3D 组长负责这套 SDK 的核心架构设计。

SDK 的功能范围:

模块功能
鉴权与登录用户登录、Token 管理
资源界面IMGUI 实现的登录、资源、描述介绍、上传界面
资源打包场景 + 资源的 AB 打包
数据统计场景面数、材质数、贴图大小等数据采集
压缩与上传ZIP 压缩后上传到腾讯 COS
本地化多语言支持

问题 ​

SDK 项目和普通业务代码不一样,它有两个硬约束:

  1. 模块多且互相独立:鉴权、打包、统计、上传彼此之间没有必然的调用关系,如果写成相互 new 的网状的依赖,任何一个模块的改动都会传导到全 SDK。
  2. 外部依赖会换:云存储今天是腾讯 COS,平台对接今天是 SpatialOS,明天都可能换。如果业务代码直接 import 第三方 SDK,替换成本是全量回归。

要解决的问题因此不是「把功能写出来」,而是「让功能之间不互相认识,让第三方依赖可以整体替换」。

方案 ​

整体结构 ​

mermaid
flowchart TD
    UI["IMGUI 界面层<br>登录 / 资源 / 上传"] --> REG["Service Registry<br>表驱动注册表"]
    REG --> AUTH["IAuthService<br>鉴权与 Token"]
    REG --> PACK["IPackService<br>AB 打包"]
    REG --> STAT["IStatService<br>资源数据统计"]
    REG --> UP["IUploadService<br>压缩上传"]
    UP --> COS["ICloudStorage<br>腾讯 COS 封装"]
    PACK -.不直接依赖.-> COS

两条设计原则支撑这个结构:

  • 面向接口编程:每个服务先定义接口(IAuthService / IPackService / IUploadService / IStatService),接口独立实现、互不依赖。调用方只持有接口,不持有实现类。
  • 表驱动法:不用 if-else 链分发服务,用字典做注册表。
csharp
// 不用 if-else 链,用 Dictionary 映射
var serviceMap = new Dictionary<string, IService> {
    ["auth"]   = new AuthService(),
    ["pack"]   = new PackService(),
    ["upload"] = new UploadService(),
};

新增服务只需要加一行注册,不修改核心逻辑——这是「开放扩展、关闭修改」最省事的实现方式。

单一职责切分 ​

  • SDK 只负责客户端工具链,不包含平台业务逻辑。
  • 腾讯 COS 对接独立封装为 ICloudStorage 接口,打包模块只依赖接口,不知道 COS 的存在。
  • SpatialOS 对接独立封装为 ISpatialService 接口,同理。

关键实现 ​

界面层与逻辑层分离。 四个 IMGUI 界面(登录、资源、描述、上传)只做展示和用户输入收集,所有动作都转发给注册表里的服务接口。界面不知道 AuthService 怎么管理 Token,也不知道 UploadService 先压缩还是先统计。

数据统计前置。 打包前由 IStatService 采集面数、材质数、贴图大小,一方面给开发者在上传界面看到资源体检结果,另一方面让平台侧能拒绝超限内容,把问题拦在上传之前。

上传链路串行化。 打包 → ZIP 压缩 → COS 上传是一条单向流水线,每步只接受上一步的产物作为输入,失败时能在明确的环节中断和重试,不会出现「压了一半开始传」的中间态。

登录态收敛在鉴权模块。 Token 的获取、刷新和失效都由 IAuthService 内部管理,上传等需要鉴权的服务通过接口取登录态,各自不保存一份——否则 Token 过期逻辑会散布到每个模块里,改一次漏一片。

本地化独立成模块。 多语言文案不进界面代码,由本地化模块统一供给,四个 IMGUI 界面只取 key。界面加文案和加语言是两次独立改动,互不阻塞。

指标 ​

指标结果
模块耦合度降低约 40%
新增服务成本注册表加一行,核心逻辑零改动
第三方替换成本替换接口实现即可,业务代码不动

SDK 最终支撑 AstralVR 平台上线,接口设计模式也在后续项目中复用。

复盘 ​

  1. SDK 架构的第一优先级是隔离变化:功能模块之间隔离,第三方依赖更要隔离。接口不值钱,值钱的是「换实现时业务代码一行不改」。
  2. 表驱动法在小规模项目里经常被嫌「过度设计」,但只要服务数量超过 3 个且会增长,注册表就比 if-else 链便宜。
  3. 这套「接口 + 注册表 + 第三方封装」的套路,后来在小鹏做 XMapEngine 的 Service 层设计时直接复用了——好的架构经验是可以带走的。

罗子初 · AI 座舱专家 · 8年端侧研发

Lv.1