# ShrinkContext.AppAdapter ShrinkApp ↔ ShrinkContext 的桥接层:提供当前默认的 ContextLoader 宿主、声明式组合 Profile、诊断工具,并保留 `IShrinkAppModuleInstaller` 兼容适配。当前架构与边界见仓库根 `DESIGN.md`。 Godot 和普通 .NET 项目安装 `ShrinkSDK.Context.AppAdapter`;可打包源码位于 `DotNet~`。 ## 组成 | 类型 | 职责 | |---|---| | `ShrinkAppInstallerComponent` | 安装器 → 组件:`DependsOn` 映射为 `app.module.*` 注入键(依赖缺失**等待**而非抛错);发布模块键;apply = RegisterServices + InitializeAsync | | `ShrinkAppLoaderHost` | 加载器驱动的 ShrinkApp 宿主:发现安装器(注入覆盖可测试)、应用声明式组合、经 `ShrinkContextLoader` 增量协调、运行中按模块开关 | | `ShrinkAppCompositionProfile` | ScriptableObject/JSON 组合文档:描述条目启用、显式排除、isolate 与 intercept;组件工厂仍由代码目录注册 | | `ShrinkAppLoaderBootstrapper` | `hostingMode == ContextLoader` 时自动创建常驻宿主,应用 `Resources/ShrinkAppComposition`,并把服务容器接回 `ShrinkApp.Services` | | `ShrinkContextDiagnosticsWindow` | `ShrinkSDK/上下文/诊断与组合`:查看运行时 fiber/依赖/事务、编辑 Profile JSON、读取可选的 ModFramework 常驻统计并运行容量基准 | ## 启用方式 `ShrinkAppSettings.hostingMode` 设为 `ContextLoader`(Inspector 或资产字段)。经典项目默认 `ClassicHost`,行为零变化。 ```csharp // 场景业务等待宿主完成;失败时直接收到启动异常。 await ShrinkAppLoaderBootstrapper.WaitUntilStartedAsync(cancellationToken); // 运行中按模块开关(宿主与其余模块不重启) var host = ShrinkAppLoaderBootstrapper.Instance!.Host; await host.SetModuleDisabledAsync("shrink.network", true); ``` `ShrinkAppLoaderBootstrapper.StartError` 保留最近一次启动异常;启动失败同时发布 `ShrinkAppStartFailedEvent`。调用方不需要轮询 `Host.IsRunning`。 ## 声明式组合 默认资源名为 `Assets/Resources/ShrinkAppComposition.asset`。组合根先用代码注册安装器或原生组件工厂,Bootstrapper 再应用 Profile;配置文件不能通过类型名反射实例化任意组件。 Profile 的 JSON 结构如下: ```json { "includeUnlistedEntries": false, "entries": [ { "id": "shrink.datasaver", "enabled": true, "isolate": [], "intercept": [ { "key": "shrink.service.datasaver", "metadata": [ { "name": "access", "value": "read-only" } ] } ] } ] } ``` - `includeUnlistedEntries = false` 时,没有列出的已注册模块不会进入 loader。 - `ShrinkAppSettings.disabledModuleIds` 与 Profile 的 `enabled = false` 取并集;Profile 不会偷偷启用 Settings 已禁用的模块。 - isolate 与 intercept 都在进入 loader 前校验空键和重复键。 - intercept metadata 当前是字符串键值,由领域访问策略解释,不是任意对象反序列化入口。 - Profile 可引用一个 JSON `TextAsset` 作为覆盖;诊断窗口也支持 JSON 导入、校验、写回和导出。 ## 行为差异(对照经典 ShrinkAppHost) | 场景 | ClassicHost | LoaderHost | |---|---|---| | 依赖缺失 | 排序期抛错 | 安装器保持 Waiting,依赖出现自动激活 | | 重复 ModuleId | 宿主级异常 | 构造期抛错(一致);运行期替换退化为供给冲突失败 | | 运行中禁用模块 | 不支持(需重启) | `SetModuleDisabledAsync` 增量协调,重启用会重新执行安装器初始化 | | `ShrinkApp.IsRunning` | Host 驱动 | LoaderHost 通过 `SetExternalHostRunning` 同步静态门面状态 | ## 已知边界 - `ShrinkAppServices.TryUnregister(instance)` 支持按实例撤回服务;原生 Context 组件已使用该路径。旧 installer 包装器仍取决于安装器自身是否提供完整逆操作。 - config/isolate 变化走条目重建;intercept metadata 可原位更新而不改变 fiber generation。 - 运行中不支持重新应用整份 Profile;资产修改在下一次宿主启动生效,运行中模块开关仍使用 `SetModuleDisabledAsync`。 - Editor 基准的毫秒数和 GC 管理堆差值只用于同机前后对比;自动测试只断言索引候选规模和事务恢复结果。 ## 测试 `Tests/` 覆盖安装器生命周期、LoaderHost 开关、原生 Starter 接线、Profile/JSON 校验、显式条目选择、设置禁用优先级,以及 notify/失败恢复结构性基准。