Unity3D + luaframework如何做到一键打包
目录
阅前提示: 本文讲述内容为如何优化luaframework的打包流程,并不是讲如何使用luaframework配合unity3D进行热更新的基础内容,因此需要读者有unity3d + luaframework的使用经验,以及熟悉assetbundle的热更原理和流程,否则不建议阅读. 目录: 1.为什么要做一键打包公司项目近两年来一直在使用luaframework,热更功能和lua开发的效率让我们受益良多,不过其打包流程的缺陷也很明显,很多流程都需要等待,盯着右下角的小菊花,等待它转完,然后进行下一步操作,当项目开发到中后期,代码量和资源量都上来以后,等的时间也在随着变长,有时候我们会在等的过程中不自觉的做点其它事,开个网页,滑滑手机,并不是每次都可以在菊花刚好转完时注意到,中间间隔的时间就这么浪费掉了. 我们今天就来对luaframework框架进行一个小小的改造,减少一些人工干预,做到一键打包. 首先我们来看看整个打包的流程,整个流程很清晰都是线性执行的,在没有进行修改的情况下,每一步执行以后都需要等待,等待当前这一步执行完毕后再手动执行下一步,非常麻烦. 2.使用OnScriptsReloaded 来串接整个流程为了不用等待,我们需要使用unity editor自带的一个回调接口 OnScriptsReloaded 来完成功能 当每次editor编译完成后(右下角的菊花转完以后)系统都会回调一次这个函数,我们这次的重点就是通过这个回调函数把整个流程串起来. 首先我们新建一个自动打包的脚本AutoBuild.cs,把它放到工程中AssetsLuaFrameworkEditor目录下,我们的大部分功能都会在这个脚本中完成. 接下来我们添加一段代码让编译完成后给一个系统弹框,提示我们包已经打好了: public static void OnScriptsReloaded() { EditorUtility.DisplayDialog("Complete","Export package successful!","Open Folder") } 添加上述代码后我们会发现一个糟糕的问题,任何一次修改代码编译完成后都会弹一个打包完毕的包,这当然不是我们想要的,因此我们需要加一个标记变量和一个分支语句来进行判断当前是否处于打包的流程中. 3.如何在OnScriptsReloaded中使用条件分支判断我们尝试用一个静态变量来进行控制. Static int clearTag = false; public static void clearAndBuild() { clearTag = true; //do something like clean… } [UnityEditor.Callbacks.DidReloadScripts] public static void OnScriptsReloaded() { //这个分支判断永远都进不去,因为编译完毕后clearTag会被重置回false if (clearTag) { //show clean complete dialog. } } 结果发现这样做是不可行的,调试发现clearTag的值怎么都无法被修改,在查阅官方文档后找到原因:
没关系,即便静态变量不能在这里使用,我们还有其它的方法来完成逻辑的判断
File.Create("clear.ini"); 然后通过 if( File.Exists("clear.ini")) { //do something } 来做标记判断 显然,后者比前者繁琐了不少,因此我们这里选择采用__PlayerPrefs__来记录数据 public static void clearAndBuild() { PlayerPrefs.SetInt("clearTag",1); //do something like clean… } [UnityEditor.Callbacks.DidReloadScripts] public static void OnScriptsReloaded() { //这里就可以被正确判断了 if (PlayerPrefs.GetInt("clearTag") == 1) { //show clean complete dialog. } } 这样就能正常通过判断了. 4.在packager中新增BuildResource接口接下来在Packager.cs中增加一个新的函数接口 public static void BuildResource() { #if UNITY_ANDROID BuildAndroidResource(); #elif UNITY_IPHONE BuildiPhoneResource(); #else BuildWindowsResource(); #endif } 在这里对原本的接口做了一个封装,加入了平台的自动判断,这样做有两个好处 接下来我们回到AutoBuild.cs文件 [MenuItem("AutoBuild/Build",false,100)] public static void build() { PlayerPrefs.SetInt("autobuild",1); Packager.BuildResource(); } [MenuItem("AutoBuild/BuildAndRun",100)] public static void buildAndRun() { PlayerPrefs.SetInt("autobuild",2); Packager.BuildResource(); } [MenuItem("AutoBuild/clearAndBuild",100)] public static void clearAndBuild() { PlayerPrefs.SetInt("clearAndBuild",1); ToLuaMenu.ClearLuaWraps(); } 为什么要分成这三个功能呢?
接下来我们完善上面提到的重要接口OnScriptsReloaded [UnityEditor.Callbacks.DidReloadScripts] public static void OnScriptsReloaded() { if (PlayerPrefs.GetInt("clearAndBuild") == 1) { PlayerPrefs.SetInt("clearAndBuild",0); EditorApplication.delayCall = build; } else if (PlayerPrefs.GetInt("autobuild") == 1) { PlayerPrefs.SetInt("autobuild",0); PlayerPrefs.SetInt("exportPackage",1); EditorApplication.delayCall = justBuildPackage; } else if (PlayerPrefs.GetInt("autobuild") == 2) { PlayerPrefs.SetInt("autobuild",1); EditorApplication.delayCall = buildPackageAndRun; } else if (PlayerPrefs.GetInt("exportPackage") == 1) { PlayerPrefs.SetInt("exportPackage",0); if (EditorUtility.DisplayDialog("Complete","Open Folder")) { System.Diagnostics.Process.Start("D:/unity_package/luaframework"); }; } } 其实逻辑非常简单,每做一步操作时,就通过PlayerPrefs打一个标记,当编译完毕后,通过判断当前的标记值做下一步的操作,并重置当前标记,所有逻辑与上面的流程图中的流程一一对应.
接下来我们来完成打包函数 static void makePackage(bool isRun) { string[] levels = { "Assets/LuaFramework/Scenes/main.unity"}; BuildPlayerOptions option = new BuildPlayerOptions(); option.scenes = levels; //caculate current datetime string nowTime = System.DateTime.Now.ToString("MMdd-HH_mm"); string filePath = "D:/unity_package/luaframework/luaframework" + nowTime; #if UNITY_ANDROID filePath += ".apk"; option.target = BuildTarget.Android; #elif UNITY_IPHONE option.target = BuildTarget.iOS; #else filePath += ".exe"; option.target = BuildTarget.StandaloneWindows; #endif option.locationPathName = filePath; if (isRun) { option.options = BuildOptions.AutoRunPlayer; } else { option.options = BuildOptions.None; } BuildPipeline.BuildPlayer(option); } 这里做了5件事: 5.调整会阻碍自动打包的地方既然要一键打包,那在按下打包键后就不希望出现还要人工干预的地方了,所以我们需要对ToluaMenu.cs进行一点小小的修改 注释掉下面这段if提示语句和对应的括号,让分支内的代码自动执行 if (EditorUtility.DisplayDialog("自动生成","点击确定自动生成常用类型注册文件, 也可通过菜单逐步完成此功能","确定","取消")) 6.如何设置打包快捷键快捷键能极大的提升我们的工作效率,unity editor也贴心的提供了这一功能 快捷键的规则是在菜单的后面接上” _”开头的特殊表达式(注意‘_‘前面有个空格) `% = ctrl` `# = Shift` `& = Alt` 比如我们把build设置为 [MenuItem("AutoBuild/Build _%#_d",100)] (ctrl + shift + d) 把BuildAndRun设置为 [MenuItem("AutoBuild/BuildAndRun _%#_x",100)] (ctrl + shift + x) 连接好手机,键盘按下ctrl + shift + x,剩下的就等着看运行效果了,是不是很爽 7.制作提示对话框最后一步增加了一个主动弹出的系统对话框,这一步的主要目的是主动提醒开发者执行结束了,而不是让开发者不停的去关注右下角的小菊花转完没有 if (EditorUtility.DisplayDialog("Complete","Open Folder")) { System.Diagnostics.Process.Start("D:/unity_package/luaframework"); }; 在弹出对话框中点击Open Folder即可打开刚刚导出的可执行文件所在的目录,相当方便 8.android自动签名设置最后说一下android自动签名的设置,每次重启untiy后,android player的keystore签名设置都会清空,需要重新输入,不厌其烦,既然都一键打包了,肯定不希望每次还需要手动填写一次keystore的各种密码信息,要偷懒就要彻底一点,我们新建一个脚本AutoSignKeystore.cs [InitializeOnLoad] public class AutoSignKeystore { static AutoSignKeystore() { PlayerSettings.Android.keystoreName = "D:/keystore/luaframework.keystore"; PlayerSettings.Android.keystorePass = "luaframework"; PlayerSettings.Android.keyaliasName = "luafw"; PlayerSettings.Android.keyaliasPass = "luaframework"; } } 设置好keystore文件的路径,密码,别名,别名密码等相关信息,把此脚本放到assets/Editor文件夹下,每次打开unity时就会自动设置好预设的签名信息了. 通过上述设置,按下ctrl+shift+d就能导出可执行文件. 按下ctrl+shift+x就能导出并运行. 一键打包制作完毕! 整个调整几乎没有动到原来的框架,主要功能都在AutoBuild.cs中完成,对原框架只是做了非常少的一些修改,我把修改后的功能放到github上了,如果觉得有用请按Star,谢谢! https://github.com/CraneInForest/LuaFrameWork_UGUI_AutoBuild.git 一键打包搞定了,但这只方便了开发和调试过程,离真正的自动化打包还有差距,下一篇文章就来讲讲如何结合jenkins做到在网页上全自动打包吧(解放你的电脑和双手,别让打包占用我们宝贵的生命~) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |