设计插件
设计生命周期安全、仅依赖 SDK 的 Turboism 插件,并在能力不可用时安全地失败关闭。
一个持久可靠的 Turboism 插件具有一个用户可见的用途,仅依赖 SDK,并将主机集成、调度、安全与清理工作交由 Runtime 负责。
保持边界精简
Plugin -> SDK -> Runtime policy -> versioned Adapter/Provider -> Cubism/Editor不要为 Runtime 相关事项添加插件本地抽象。请复用 PluginContext 服务来处理配置、存储、任务、事件、UI、用户文件和 Cubism 访问。
避免:
- 直接依赖 Runtime 或
com.live2d.*; - 反射和原始主机对象;
- 不受管理的 executor、线程和定时器;
- 遍历 Swing/AWT 主机小部件;
- 全局可变注册表;
- 推测性的工厂和扩展层。
规划生命周期
使用实际存在的四个生命周期方法:
init— 保留 context、注册 schema,并构建插件私有状态。enable— 注册操作、事件、UI 和任务。disable— 停止活动行为,但不假定会热卸载。shutdown— 在 Runtime 生命周期稳定后释放插件私有状态。
除非有意提前关闭,否则将每个可关闭的注册项或句柄放入 DisposableScope。
将权限与可用性分开
权限回答插件是否可以跨越风险边界。能力回答 Runtime 和当前主机版本是否可以执行该操作。
请同时设计两条路径:
- 通过受支持的 Provider 成功执行;
- 明确的不可用、不受支持、过期、拒绝、超时、背压或拒绝执行结果。
绝不要将权限视为 Provider 存在的证明。
围绕 Editor 所有权设计写入
对于附加到 Editor 的模型,Editor 创作状态是写入的唯一事实来源。一次安全写入可能需要:
- 验证;
- 主机线程调度;
- 事务与 Undo;
- 脏状态和刷新处理;
- 回滚或明确的部分失败;
- generation/过期目标拒绝;
- 若声称数据持久化,则进行保存/重新打开验证。
不要把 Cubism Core 变异为第二个独立的创作状态,也不要围绕只用于求值的变异伪造 Undo 条目。
在边界处使用不可变值
事件、UI 描述符、快照、选择、配置值和任务请求都应是不可变的 SDK 或插件自有值。
不要泄漏:
- 主机对象;
- 主机 UI 控件;
- 原生句柄;
- 主机 ClassLoader;
- 可变的 Cubism 自有数组;
- 不受限制的文件系统路径。
一个操作对应一个贡献项
将用户行为注册为 Action,然后把菜单、工具栏、面板或上下文菜单贡献项绑定到其操作 ID。这样无需主机 UI 也可以测试行为。
测试最小的真实契约
仅有生命周期日志的插件需要构造函数/生命周期测试。带注册项的插件应使用记录型/伪造的 PluginContext,并验证:
- 请求的权限和不可用路径;
- 注册与 scope 清理;
- disable/shutdown 行为;
- 不可变事件和 DTO 行为;
- 配置迁移和修订冲突;
- 在适用时任务取消或拒绝。
主机版本声明需要项目中风险更高的验证工作流;伪造测试不能证明已为真实主机做好准备。
设计检查清单
- 插件有一个明确用途。
- 生产代码仅依赖 SDK。
- Manifest v2 声明准确的入口点、资源、依赖和最低权限。
- 注册项和句柄可关闭且受 scope 管理。
- 不可用的 Provider 以有用诊断信息安全地失败关闭。
- 配置、存储和用户文件使用正确的服务。
- 不存在不受管理的线程、executor、定时器、主机对象或反射桥接。
- 写入保持 Editor 所有权和 Undo 语义。
- 最小的聚焦测试覆盖实际契约。