#nullable enable using Cysharp.Threading.Tasks; using ShrinkApp; using UnityEngine; namespace ShrinkContext.AppAdapter { /// /// ShrinkApp 加载器宿主的自动引导: /// hostingMode == ContextLoader 时在 BeforeSceneLoad 创建常驻 GameObject 并启动 ShrinkAppLoaderHost, /// 同时把服务容器接回 ShrinkApp 静态入口(InitializeForExternalHost),保证场景脚本照常访问 ShrinkApp.Services。 /// ClassicHost 模式下完全不动——经典路径零行为变化。 /// public sealed class ShrinkAppLoaderBootstrapper : MonoBehaviour { private static ShrinkAppLoaderBootstrapper? _instance; /// /// Starter/组合包在 SubsystemRegistration 阶段设置的默认装配表。 /// AppAdapter 保持不依赖具体业务模块,组合根负责把原生组件挂到已发现的模块 id。 /// public static System.Action? DefaultComposition { get; set; } public static ShrinkAppLoaderBootstrapper? Instance => _instance; public ShrinkAppLoaderHost Host { get; private set; } = null!; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void AutoBootstrap() { if (ShrinkAppSettings.Instance.hostingMode != ShrinkAppHostingMode.ContextLoader) return; var gameObject = new GameObject("ShrinkAppLoaderHost"); DontDestroyOnLoad(gameObject); gameObject.AddComponent(); } private void Awake() { if (_instance != null && _instance != this) { Destroy(gameObject); return; } _instance = this; Host = new ShrinkAppLoaderHost(); DefaultComposition?.Invoke(Host); var profile = ShrinkAppCompositionProfile.LoadDefault(); if (profile != null) Host.ApplyComposition(profile.ResolveDocument()); global::ShrinkApp.ShrinkApp.InitializeForExternalHost(Host.Services); Host.StartAsync().Forget(ex => { Debug.LogException(ex); Debug.LogError("[ShrinkApp.LoaderHost] 启动失败: " + ex.Message); }); } private void OnDestroy() { if (_instance == this) _instance = null; } } }