使用 命令行/WinForm 来打包Unity可执行程序( 二 )


点击可以成功打包EXE 。但此时有一个影响用户体验的地方,在点击之后窗口会卡死,无法对窗口拖动和缩放,只有在打包运行完后才恢复正常 。经过查询发现是线程卡死问题,所以可以新建一个线程来异步执行这一段代码,从而不影响主窗口的正常使用 。修改完代码如下:
private void button1_Click(object sender, EventArgs e){Task.Run(async () =>{MessageBox.Show("EXE正在打包中");string EditorPath = textBox1.Text;//编辑器地址string GamePath = textBox2.Text;//要打包的程序地址string cmd = @"cd " + EditorPath + "&&" + "Unity.exe -batchmode -nographics -quit -projectPath \"" + GamePath + "\" -executeMethod BuildScript.BuildEXE";GamePath = textBox1.Text;string output = "";CmdHelper.RunCmd(cmd, out output);MessageBox.Show("EXE打包完成");});}
主窗口在打包时可以正常拖动缩放,但需要注意的是上文所提到的
“一个Unity工程只能打开一个实例,所以如果我们已经手动用Unity打开了工程,此时执行该命令是会报错的 。请确保已关闭相应的工程 ”
在我们使用命令行打包的时候本质上其实也是手动打开了Unity,所以我们需要禁止用户在打包的过程中重复对按钮进行点击 。
这里我想到了修改的属性,但直接在这段异步线程代码中修改属性是行不通的,程序虽然不会报错,但异步操作中的代码不会运行 。因为C#只有主线程才能访问控件 。从 .NET2.0 类库开始,.NET框架就对于中采用多线程调用窗体控件进行了安全性检测,就是说我从另外一个不是主线程的线程去调用窗体控件的话,就会出现异常 。
以下有两个解决办法:
一是直接设置 ..Forms.. = false; 这种方法简单粗暴,但十分不推荐使用,因为可能会导致不安全 。
二是使用委托,使用方法来访问UI线程,以此对属性进行操作 。这种方法安全可靠,值得推荐 。修改完后代码如下:
private void button1_Click(object sender, EventArgs e){Task.Run(async () =>{// 访问UI线程button1.Invoke((MethodInvoker)delegate{// 更改Enabled属性button1.Enabled = false;});button2.Invoke((MethodInvoker)delegate{// 更改Enabled属性button2.Enabled = false;});MessageBox.Show("EXE正在打包中");string EditorPath = textBox1.Text;//编辑器地址string GamePath = textBox2.Text;//要打包的程序地址string cmd = @"cd " + EditorPath + "&&" + "Unity.exe -batchmode -nographics -quit -projectPath \"" + GamePath + "\" -executeMethod BuildScript.BuildEXE";GamePath = textBox1.Text;string output = "";CmdHelper.RunCmd(cmd, out output);MessageBox.Show("EXE打包完成");button1.Invoke((MethodInvoker)delegate{// 更改Enabled属性button1.Enabled = true;});button2.Invoke((MethodInvoker)delegate{// 更改Enabled属性button2.Enabled = true;});});}
③完整代码:
using System;using System.Diagnostics;using System.Threading.Tasks;using System.Windows.Forms;namespace AutoBuild{public partial class Form1 : Form{//stringcmd = "cd C:\Program Files\Unity\Hub\Editor\2021.3.20f1c1\Editor && Unity.exe -batchmode -nographics -quit -projectPath ""C:\Unity Project\PureMVC_study2"" -executeMethod BuildScript.BuildEXE"public string GamePath = "";delegate void MyDele();public Form1(){InitializeComponent();//Control.CheckForIllegalCrossThreadCalls = false; // 这句代码就是关闭了安全检查}private void button1_Click(object sender, EventArgs e){Task.Run(async () =>{// 访问UI线程button1.Invoke((MethodInvoker)delegate{// 更改Enabled属性button1.Enabled = false;});button2.Invoke((MethodInvoker)delegate{// 更改Enabled属性button2.Enabled = false;});//button1.Enabled = false;//一个Unity工程只能打开一个实例,所以不能同时打包多种可运行程序,这里禁止按键的点击防止用户多次点击打包//button2.Enabled = false;MessageBox.Show("EXE正在打包中");string EditorPath = textBox1.Text;//编辑器地址string GamePath = textBox2.Text;//要打包的程序地址string cmd = @"cd " + EditorPath + "&&" + "Unity.exe -batchmode -nographics -quit -projectPath \"" + GamePath + "\" -executeMethod BuildScript.BuildEXE";GamePath = textBox1.Text;string output = "";CmdHelper.RunCmd(cmd, out output);MessageBox.Show("EXE打包完成");button1.Invoke((MethodInvoker)delegate{// 更改Enabled属性button1.Enabled = true;});button2.Invoke((MethodInvoker)delegate{// 更改Enabled属性button2.Enabled = true;});//button1.Enabled = true;//button2.Enabled = true;});}private void button2_Click(object sender, EventArgs e){Task.Run(async () =>{// 访问UI线程button1.Invoke((MethodInvoker)delegate{// 更改Enabled属性button1.Enabled = false;});button2.Invoke((MethodInvoker)delegate{// 更改Enabled属性button2.Enabled = false;});//button1.Enabled = false;//一个Unity工程只能打开一个实例,所以不能同时打包多种可运行程序,这里禁止按键的点击防止用户多次点击打包//button2.Enabled = false;MessageBox.Show("APK正在打包中");string EditorPath = textBox1.Text;string GamePath = textBox2.Text;string cmd = @"cd " + EditorPath + "&&" + "Unity.exe -batchmode -nographics -quit -projectPath \"" + GamePath + "\" -executeMethod BuildScript.BuildAPK";GamePath = textBox1.Text;string output = "";CmdHelper.RunCmd(cmd, out output);MessageBox.Show("APK打包完成");button1.Invoke((MethodInvoker)delegate{// 更改Enabled属性button1.Enabled = true;});button2.Invoke((MethodInvoker)delegate{// 更改Enabled属性button2.Enabled = true;});//button1.Enabled = true;//button2.Enabled = true;});}public class CmdHelper{private static string CmdPath = @"C:\Windows\System32\cmd.exe";/// /// 执行cmd命令/// 多命令请使用批处理命令连接符:///