乐于分享
好东西不私藏

MyFramework 用法说明(二):工程目录和启动流程

MyFramework 用法说明(二):工程目录和启动流程

上一篇完成安装和初始化以后,工程中会生成一套默认模板。 这一篇主要说明:这些目录分别放什么代码,以及框架启动时从哪里开始执行。


一、初始化后的主要目录

初始化完成后,重点关注 Assets/Scripts 下的几个目录:

Assets/Scripts ├── AutoGenerated │   ├── HybridCLRGenerate │   └── Obfuz ├── Game │   ├── Common │   ├── Game │   ├── GameScene │   └── UI └── HotFix     ├── Common     ├── Game     ├── GameScene     └── UI

其中:

AutoGenerated    自动生成代码目录,不建议手动改Game             非热更业务层HotFix           热更业务层

Game 和 HotFix 是最重要的两个目录。

Game 里的代码会直接参与主工程编译,一般放启动流程、热更前资源更新、平台初始化等不能随便热更的逻辑。

HotFix 里的代码属于热更业务层,项目主要玩法逻辑、主场景流程、热更 UI 注册等,后续都应该优先放这里。


二、几个程序集的关系

模板里默认会生成:

Assets/Scripts/Game/Game.asmdefAssets/Scripts/HotFix/HotFix.asmdefAssets/Scripts/AutoGenerated/AutoGenerated.asmdef

框架包内部还有:

Frame_BaseFrame_GameFrame_HotFix

可以简单理解成:

Frame_Base      框架最底层,非热更Frame_Game      框架非热更层Game            项目非热更层Frame_HotFix    框架热更层HotFix          项目热更层AutoGenerated   自动生成代码

实际项目里,建议遵守一个原则:

能放 HotFix 的业务逻辑,就不要放 Game。

Game 层只保留启动、热更前资源更新、平台接入、热更入口等必要代码。


三、启动入口:GameEntry

初始化时,框架会把 GameEntry 脚本挂到启动场景的 GameEntry 节点上。

默认代码很简单:

public class GameEntry : GameEntryBase{	publicoverridevoidAwake()	{		base.Awake();		Game framework = new();		framework.init();		setFrameworkAOT(framework);	}}

这里做了三件事:

1. 调用 GameEntryBase.Awake()2. 创建非热更框架 Game3. 初始化 Game,并设置为 AOT 框架实例

GameEntryBase 负责 Unity 生命周期转发,比如:

UpdateFixedUpdateLateUpdateOnApplicationQuit

也就是说,真正每帧驱动框架的入口在 GameEntryBase 中。


四、非热更入口:Game

Game 是非热更部分的项目框架入口。

默认代码核心是:

public class Game : GameFramework{	publicoverridevoidinit()	{		mOnInitFrameSystem += gameInitFrameSystem;		mOnRegisteStuff += gameRegiste;		mOnPackageName += () => { return ANDROID_PLUGIN_BUNDLE_NAME; };		base.init();		if (!isEnableHotFix() || isEditor())		{			mAssetVersionSystem.setAssetReadPath(ASSET_READ_PATH.STREAMING_ASSETS_ONLY);		}		else		{			mAssetVersionSystem.setAssetReadPath(ASSET_READ_PATH.SAME_TO_REMOTE);		}		mGameSceneManager.enterScene<LaunchScene>();	}	protectedvoidgameInitFrameSystem(){}	protectedvoidgameRegiste()	{		LayoutRegister.registeAllLayout();	}}

这里重点看几个位置。

gameInitFrameSystem 用来注册非热更层自己的框架系统。

比如以后需要在热更前使用某些管理器,可以放这里:

protectedvoidgameInitFrameSystem(){	// registeFrameSystem<XXXManager>((com) => { mXXXManager = com; });}

gameRegiste 用来注册非热更层资源、布局等内容。

默认会调用:

LayoutRegister.registeAllLayout();

最后进入:

mGameSceneManager.enterScene<LaunchScene>();

也就是说,非热更启动后,第一个进入的是 LaunchScene


五、LaunchScene:热更前流程

LaunchScene 是非热更层的启动场景流程。

默认代码:

public class LaunchScene : GameScene{	publicoverridevoidassignStartExitProcedure()	{		mStartProcedure = typeof(LaunchSceneVersion);		mExitProcedure = typeof(LaunchSceneExit);	}	publicoverridevoidcreateSceneProcedure()	{		addProcedure<LaunchSceneVersion>();		addProcedure<LaunchSceneExit>();	}}

它有两个流程:

LaunchSceneVersion    启动热更流程LaunchSceneExit       退出启动场景流程

LaunchSceneVersion 里默认调用:

public class LaunchSceneVersion : SceneProcedure{	publicoverridevoidinit()	{		base.init();		HybridCLRSystem.launchHotFix(nullnullnull);	}}

这里就是热更启动入口。

编辑器下会直接从当前 AppDomain 中查找 HotFix 程序集。 真机热更版则会加载热更 DLL,然后启动 GameHotFix


六、热更入口:GameHotFix

热更启动后,框架会查找 GameHotFix 类型,并创建热更实例。

默认代码:

public class GameHotFix : GameHotFixBase<GameHotFix>{	protectedoverridevoidregisterAll()	{		LayoutRegisterHotFix.registeAll();	}	protectedoverridevoidinitFrameSystem()	{		//registeFrameSystem<NetManager>((com) => { mNetManager = com; });	}	protectedoverridestringgetAndroidPluginBundleName()	{		return ANDROID_PLUGIN_BUNDLE_NAME;	}	protectedoverride Type getStartGameSceneType()	{		return typeof(MainScene);	}}

这里有三个重点。

registerAll 用来注册热更层内容,比如热更 UI:

protectedoverridevoidregisterAll(){	LayoutRegisterHotFix.registeAll();}

initFrameSystem 用来注册热更层框架系统:

protectedoverridevoidinitFrameSystem(){	// registeFrameSystem<NetManager>((com) => { mNetManager = com; });}

getStartGameSceneType 决定热更启动完成后进入哪个场景:

protectedoverride Type getStartGameSceneType(){	return typeof(MainScene);}

所以真正的业务主场景默认从 MainScene 开始。


七、MainScene:热更业务主场景

模板中的 MainScene 结构如下:

public class MainScene : GameScene{	publicoverridevoidassignStartExitProcedure()	{		mStartProcedure = typeof(MainSceneLoading);		mExitProcedure = typeof(MainSceneExit);	}	publicoverridevoidcreateSceneProcedure()	{		addProcedure(typeof(MainSceneLoading));		addProcedure(typeof(MainSceneExit));	}}

默认有两个流程:

MainSceneLoading    主场景加载流程MainSceneExit       主场景退出流程

MainSceneLoading 目前是空实现:

public class MainSceneLoading : SceneProcedure{	protected override void onInit(SceneProcedure lastProcedure) { }	protected override void onExit(SceneProcedure nextProcedure) { }}

实际项目可以从这里开始写主业务初始化,比如:

public class MainSceneLoading : SceneProcedure{	protectedoverridevoidonInit(SceneProcedure lastProcedure)	{		base.onInit(lastProcedure);		// 加载主界面		// 初始化玩家数据		// 进入主城流程	}}

MainSceneExit 中默认调用:

genericExit(0);

一般用于卸载当前场景的布局和资源,避免离开场景后还有资源残留。


八、UI 注册入口

非热更 UI 注册在:

Assets/Scripts/Game/UI/LayoutRegister.cs

默认结构:

public class LayoutRegister{	publicstaticvoidregisteAllLayout()	{		//registeLayout<UIDemo>((script) => { mUIDemo = script; });	}}

热更 UI 注册在:

Assets/Scripts/HotFix/UI/LayoutRegisterHotFix.cs

默认结构:

public class LayoutRegisterHotFix{	publicstaticvoidregisteAll()	{		// auto generate start		// auto generate end	}}

后续使用 UI 代码生成器时,热更 UI 的注册代码通常会写入 auto generate 区域。


九、推荐修改位置

刚接入框架时,建议先只改这些文件:

Assets/Scripts/Game/Common/GameDefine.csAssets/Scripts/Game/Game/Game.csAssets/Scripts/HotFix/Game/GameHotFix.csAssets/Scripts/HotFix/GameScene/MainScene/MainSceneLoading.csAssets/Scripts/HotFix/UI/LayoutRegisterHotFix.cs

大致分工如下:

GameDefine.cs              项目常量,比如安卓插件包名Game.cs                    非热更层初始化GameHotFix.cs              热更层初始化MainSceneLoading.cs        主业务入口LayoutRegisterHotFix.cs    热更 UI 注册

不要一开始就去改框架包里的 Runtime/Frame_* 代码。 如果只是正常开发项目,优先在 Game 和 HotFix 目录中扩展。


十、启动流程总结

完整启动流程可以理解为:

start.unity  ↓GameEntry.Awake  ↓Game.init  ↓进入 LaunchScene  ↓LaunchSceneVersion  ↓HybridCLRSystem.launchHotFix  ↓创建 GameHotFix  ↓GameHotFix.start  ↓进入 MainScene  ↓MainSceneLoading  ↓项目主业务开始

如果不启用热更,编辑器下也会尽量走同一套入口,只是不会从外部加载 DLL,而是直接从当前工程中的程序集启动热更逻辑。

这样做的好处是:

编辑器开发和真机运行的业务入口基本一致,后续调试热更层代码会更方便。