Unity构建详解(12)——自动构建

【前言】

自动构建是指整个构建流程不需要人工操作,只需要输入启动构建指令即可获取构建结果。实现这样的自动构建需要满足以下条件:

  • 支持命令行参数启动
    • 我们不可能每次构建时都打开Unity去手动点击构建,必须支持通过命令行启动Unity自动执行构建
    • 我们每次构建的需求不同,可能构建Debug、Release或者其他特殊需求的应用,因此Unity需要支持识别命令行输入的不同参数
  • 支持工程自动检查
    • 我们构建时需要保证不会出现错误,否则中途就构建失败了。错误主要来自于代码和资源,需要在其被提交到主干时就进行自动检查,而不是留在构建时出现构建失败才发现某处代码或资源不对,这是提高构建效率的措施
    • 自动检查可以提前发现潜在并帮助解决潜在的问题,减少问题影响域,使得进入游戏包体的问题减少,进而降低人力成本
  • 支持应用程序自动构建
    • 在Unity中主要是支持iOS自动构建,有两步,一是自动修改xcode工程,二是xcode工程自动执行构建
  • 支持构建结果自动上传

【命令行参数启动程序】

我们通常通过点击程序的快捷方式启动程序,而所有程序都可能通过命令行来启动,两者都是调用更底层提供的接口,就好像我们写代码提供一个接口供上层在不同地方调用一样。

以win平台为例,输入exe文件的路径,即可启动程序,例如启动QQ:"C:\Program Files\Tencent\QQ\bin\QQ.exe"。

我们知道main函数是程序的入口,会接受参数输入,我们可以在命令行中输入参数,输入的参数被传递给main函数的args,程序应该读取这些参数并做相应的处理。参数具体是什么由应用程序来定。

命令行输入参数的语法为: -参数名 参数值

不同参数之前没有先后顺序。

Unity提供了命令行参数说明,常用的如下:

  • 启动工程
    • Unity程序路径 -projectPath Unity工程路径
  • 启动工程后执行某个函数
    • Unity程序路径 -projectPath Unity工程路径 -executeMethod <NamespaceName.ClassName.MethodName>
    • 该函数必须是静态函数且位于Editor文件夹中
  • 输出log
    • Unity程序路径 -projectPath Unity工程路径 -logfile 输出文件路径
  • 执行完命令自动退出
    • Unity程序路径 -projectPath Unity工程路径 -quit
  • 不打开Unity界面执行
    • Unity程序路径 -projectPath Unity工程路径 -batchmode
  • 执行时不使用GPU
    • Unity程序路径 -projectPath Unity工程路径 -nographics
  • 设置构建的目标平台
    • -buildTarget ios
    • -buildTarget android
  • 使用CacheServer
    • -EnableCacheServer
  • 设置CacheServer端口
    • -cacheServerEndpoint 127.0.0.1:10080
  • 设置使用的图形API
    • -force-gles
    • -force-vulkan
    • -force-d3d12

更进一步的,我们不可能每次都手动在命令行输入一堆东西,我们需要像点击快捷方式一样,直接运行这些指令,这时就用到bat脚本。bat脚本可以直接问ChatGPT。

@echo off
cd "Unity安装目录路径"
Unity.exe -projectPath "项目路径" -executeMethod MyScript.MyMethod -batchmode -quit

我们可以在启动Unity时调用我们自己的构建函数,即可开始构建。

如果有自定义的参数,可以通过System.Environment.GetCommandLineArgs()获取输入的参数,并做解析。

【工程自动检查】

检查主要分为代码检查和资源检查,可以在每次提交时做一次检查,也可以定时做一次全量检查。

代码检查
 可以分为编译检查、规范检查和缺陷检查

编译检查做起来做容易,可以针对每个人的每次提交做检查,主要针对漏提、错提、宏定义等导致的编译不通过情况

规范检查主要是看代码写的符不符合项目规范,虽然理论上有这一条,但实际上基本不会去做,因为每个项目组的规范不一样,要做自定义检查,而且这个检查也不好做,每个人编程习惯有细微差别,强制统一很难实施

缺陷检查很困难,一般会用第三方库做全量检查

通过检查的代码会被合并到主干,进行构建测试,这种频繁的将代码变更合并到主干中,然后自动构建和测试代码的过程叫做持续集成(CI,Continuous Integration)

通过检查后合并到主干一般在互联网开发中的做法,但在游戏中由于资产较重,构建时间很长,一般会直接将程序提交的代码合并到主干,然后再检查,且不会做构建测试

资源检查

凡是游戏内存在的资源,例如策划表、UI Prefab、场景Prefab、Timeline、动作资源、Mesh、各种精度模型、音频、各类配置等,都需要做检查。

可以做一个Unity全资源自动检查的系统,这些可以定时检查,本质上都是命令行启动Unity调用我们的检查方式,在不同的检查方法内实现不同的检查

自动通知

在构建或者检查过程中如果出现报错,我们会将报错信息输出到Log文件中。但是构建和检查一般是在单独的机器中执行的,每次去该机器上找Log文件既繁琐、效率又低,因此需要实现自动通知的功能。

将Log文件发送到某个服务器上进行存储,同时如果检查出错,可以直接将报错信息发送到工作群中的相关人员。

如果办公用的是飞书、钉钉或企业微信,其会提供API让我们去实现自动发消息。

【自动修改xcode工程】

使用Unity提供的PBXProject类,可以在代码中修改xcode工程的配置,示例如下:


public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
{string projPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj";PBXProject proj = new PBXProject();//创建PBXProject对象proj.ReadFromFile(projPath);//获取Targetstring target = proj.TargetGuidByName("Unity-iPhone");//设置自动签名proj.SetBuildProperty(target, "CODE_SIGN_IDENTITY", "Apple Development");proj.SetBuildProperty(target, "CODE_SIGN_STYLE", "Automatic");proj.SetTeamId(target, teamId); //teamId 是对应开发者正好的团队id (在苹果后台可以看到)//添加系统的FrameWorkproj.AddFrameworkToProject(target, "AdSupport.framework", true);proj.AddFrameworkToProject(target, "CoreTelephony.framework", true);proj.AddFrameworkToProject(target, "StoreKit.framework", true); //内购需要 否则 PBXCapabilityType.InAppPurchase会加不上// 设置 BitCodeproj.SetBuildProperty(target, "ENABLE_BITCODE", "false");// 设置 other link flags -ObjCproj.AddBuildProperty (target, "OTHER_LDFLAGS", "-ObjC");// 添加系统的tbd库string filePath = proj.AddFile("usr/lib/" + lib, "Frameworks/" + libPath, PBXSourceTree.Sdk);proj.AddFileToBuild(target, filePath);//添加自定义动态库string defaultLocationInProj = Application.dataPath+"/Editor/Plugins/iOS";                 //framework 存放的路径const string coreFrameworkName = "boxjing.framework";  // framework 的文件名string framework = Path.Combine(defaultLocationInProj, coreFrameworkName);string fileGuid = proj.AddFile(framework, "Frameworks/" + coreFrameworkName,         PBXSourceTree.Sdk);PBXProjectExtensions.AddFileToEmbedFrameworks(proj, target, fileGuid);proj.SetBuildProperty(target, "LD_RUNPATH_SEARCH_PATHS", "$(inherited)     @executable_path/Frameworks");//获取Plist文件string plistPath = path + "/Info.plist";PlistDocument plist = new PlistDocument();plist.ReadFromString(File.ReadAllText(plistPath));PlistElementDict infoDict = plist.root;infoDict.SetString("CFBundleShortVersionString",version);   //versioninfoDict.SetString("CFBundleVersion",build);                 //build//添加权限描述// 权限  根据自己的项目 修改后面的提示文案infoDict.SetString("NSLocationWhenInUseUsageDescription", "为了发现周围的好友,请允许App访问您的地里位置"); //地理位置infoDict.SetString("NSPhotoLibraryUsageDescription", "为了能选择照片进行上传,请允许App访问您的相册");      //相册infoDict.SetString("NSMicrophoneUsageDescription", "为了能够录制声音,请允许App访问您的麦克风权限");     //麦克风//添加URL Schemes白名单,LSApplicationQueriesSchemes是iOS中的一项权限设置,用于确定是否允许应用程序通过特定的URL Scheme与其他应用程序进行交互。URL Scheme是一种用于在应用程序之间传递数据和进行通信的方式PlistElementArray list = plist.root.CreateArray("LSApplicationQueriesSchemes");lsit.AddString("weixin");//同时添加Key和ValuePlistElementDict dic = list.AddDict();dic.SetString("key","value")//获取unityframeworkstring unityFramework = proj.GetUnityFrameworkTargetGuid();
}

xcode自动构建使用官方提供的xcodebuild,这方面的资源很多,就不多说了

【构建结果自动上传】

构建的结果不光是应用程序,还有Log文件,符号表等,这些文件都需要自动上传,而且上传的地方不一样。日常开发是一个环境,发布是另一个环境。

同时,还要将构建结果自动在群里通知。

这里只说了应该做哪些事情,实现起来都不难,就是流程繁琐些。

【定时任务】

python加强

上述用bat脚本实现了自动构建,但是后面还有构建结果自动上传、自动通知,其他各种繁琐细节的操作等,这时候用bat实现就很繁琐,我们可以用Phyton脚本实现,这些都是简单而固定的逻辑,如果不会写可以直接问GPT,下面是示例:

import subprocess
import timedef Init():print("初始化")def run_unity_method(method_name):unity_path = "/path/to/Unity"  # Unity的安装路径project_path = "/path/to/UnityProject"  # Unity项目的路径command = unity_path + " -batchmode -projectPath " + project_path + " -executeMethod " + method_namesubprocess.call(command, shell=True)def xcode_build():print("xcode构建ipa")def upload_build_result():upload_symbol_table()print("其他结果上传")print("上传构建结果")def upload_symbol_table():# 在这里添加上传符号表的代码print("上传符号表")def auto_notify():print("自动通知")def main():Init()run_unity_method("YourNamespace.YourClassName.YourMethod")time.sleep(1)  # 等待1秒#如果是ios平台再加上xcode自动构建的xcode_build()#结果上传upload_build_result()#自动通知auto_notify()if __name__ == "__main__":main()

随后我们只要在命令行中调用Phyton脚本即可

Jenkins加强

实际构建中要输入很多不同的参数,而我们的Phyton脚本中各种参数都固定,我们不可能在命令行中手动输入参数,同时还有一些定时任务等,这需要我们有一个可交互界面,可以用Jenkins

在Jenkins中输出参数,调用Phyton脚本,通过浏览器可以让不同的人都访问到Jenkins。当然Jenkins不止这些功能,但在游戏中其他功能用的不多。

到这一步,我们就完成了持续交付(CD,Continuous Delivery)

JenKins使用介绍

【应用自动安装】

应用自动安装启动是比较高级的功能,一般大型游戏安装下载耗时都在半小时以上,是很耗费时间的,可以在日常构建完成后自动安装启动以提高效率。

Android可以用adb指令通过usb或者wifi安装,同时做个apk监听新应用安装,并发出广播让新应用启动

ios可以使用阿里开源的tidevice

但这两种方式都比较繁琐,统一的解决方案是自己开发一个应用,模拟人工安装过程

【自助自动构建】

一般自动构建是在特定的机器上进行的,如果有人想自己构建验证东西,其会花费很长的时间在构建上。可以做一个自助构建的功能,让其他人借助已有的自动构建系统进行构建。

原理比较简单,先规定一些简单的指令映射自动构建时的参数,随后将这些指令转发给Jenkins即可,

【参考】

利用Unity提供的PBXObject来自动化iOS工程 - 简书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/835203.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java.lang.NoSuchMethodException: com.ruoyi.web.controller.test.bean.HeadTeacher

软件开发过程中使用Java反射机制时遇到了下面的问题 com.ruoyi.web.controller.test.bean.HeadTeacher4b9af9a9 com.ruoyi.web.controller.test.bean.HeadTeacher4b9af9a9java.lang.NoSuchMethodException: com.ruoyi.web.controller.test.bean.HeadTeacher.<init>(java…

【软考高项】三十八、风险管理7个过程

一、规划风险管理 1、定义、作用 定义&#xff1a;定义如何实施项目风险管理活动的过程作用&#xff1a;确保风险管理的水平、方法和可见度与项目风险程度相匹配&#xff0c;与对组织和其他干系人的重要程度相匹配 2、输入 项目管理计划 项目章程 项目文件 干系人登记册…

C语言从头学04——介绍占位符和输出格式

占位符、输出格式都是与 printf() 相关的&#xff0c;当然其它函数也有用到占位符的。这里先介绍它们在 printf() 的使用。 一、先介绍占位符&#xff0c;所谓“占位符”通俗讲就是先占个位置&#xff0c;后边再找具体值(参数)代入进行显示的一种方法。先用一个例子说明…

【一刷《剑指Offer》】面试题 17:合并两个排序的链表

力扣对应题目链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 核心考点&#xff1a;链表合并。 一、《剑指Offer》内容 二、分析题目 这道题的解题思路有很多&#xff1a; 可以一个一个节点的归并。可以采用递归完成。 三、代码 1、易于理解的…

Java 多线程补充

线程池 Java线程池是一种能够有效管理线程资源的机制&#xff0c;它可以显著提高应用性能并降低资源消耗。 线程池的主要优点包括&#xff1a; 资源利用高效&#xff1a;通过重用已存在的线程&#xff0c;减少了频繁创建和销毁线程带来的系统开销。响应速度提升&#xff1a;…

智慧公厕,小民生里的“大智慧”!

公共厕所是城市社会生活的基础设施&#xff0c;而智慧公厕则以其独特的管理模式为城市居民提供更优质的服务。通过智能化的监测和控制系统&#xff0c;智慧公厕实现了厕位智能引导、环境监测、资源消耗监测、安全防范管理、卫生消杀设备、多媒体信息交互、自动化控制、自动化清…

ThinkPHP+MySQL查询数据的时候计算两个经纬度之间的距离

需求&#xff0c;数据表中有lng&#xff08;经度&#xff09;lat&#xff08;维度&#xff09;两个字段&#xff0c;查询数据的时候要计算记录经纬度距离目标经纬度之间的距离。 方法中还有根据生日计算年龄(YEAR(CURDATE()) - YEAR(birthday)) AS age public function get_li…

抽象类基本概念

抽象类及抽象方法 概念&#xff1a;一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这种类被定义为抽象类&#xff0c;含有抽象方法的类也被称为抽象类。 用通俗的话来说就是当一个类的某个功能&#xff08;方法&#xff09;实现不确定时&#xff0c;我们就将该…

Java防挨骂--01

在遇到字符拼接需求时&#xff0c;习惯使用StringBuilder,而不要使用String. 因为String是不可变字符序列&#xff0c;在拼接时会产生新的String对象来进行拼接 StringBuider是可变字符序列&#xff0c;在拼接时效率和对资源的占用都表现更优。 StringBuffer也是可变字符序列…

一篇详解Git版本控制工具

华子目录 版本控制集中化版本控制分布式版本控制 Git简史Git工作机制Git和代码托管中心局域网互联网 Git安装基础配置git的--local&#xff0c;--global&#xff0c;--system的区别 创建仓库方式1git init方式2git clone git网址 工作区&#xff0c;暂存区&#xff0c;本地仓库…

React19学习-初体验

升级react19版本 安装 npm install reactbeta react-dombeta如果使用ts则需要在package.json中添加。等正式版发布直接可以使用types/react了 "overrides": {"types/react": "npm:types-reactbeta","types/react-dom": "npm:ty…

ethtool 调用流程

1. bcmgenet_ethtool_ops 分析 static const struct ethtool_ops bcmgenet_ethtool_ops {.begin bcmgenet_begin,.complete bcmgenet_complete,.get_strings bcmgenet_get_strings,.get_sset_count bcmgenet_get_sset_count,.get_ethtoo…

Spring添加注解读取和存储对象

5大注解 Controller 控制器 Service 服务 Repository 仓库 Componet 组件 Configuration 配置 五大类注解的使用 //他们都是放在同一个目录下&#xff0c;不同的类中 只不过这里粘贴到一起//控制器 Controller public class UserController {public void SayHello(){System.ou…

在51单片机里面学习C语言

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「&#xff23;语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 说出来你们可能都…

Oracle count的优化-避免全表扫描

Oracle count的优化-避免全表扫描 select count(*) from t1; 这句话比较简单&#xff0c;但很有玄机&#xff01;对这句话运行的理解&#xff0c;反映了你对数据库的理解深度&#xff01; 建立实验的大表他t1 SQL> conn scott/tiger 已连接。 SQL> drop table t1 purge…

C++ | Leetcode C++题解之第71题简化路径

题目&#xff1a; 题解&#xff1a; class Solution { public:string simplifyPath(string path) {auto split [](const string& s, char delim) -> vector<string> {vector<string> ans;string cur;for (char ch: s) {if (ch delim) {ans.push_back(mov…

QT+MYSQL数据库处理

1、打印Qt支持的数据库驱动&#xff0c;看是否有MYSQL数据库驱动 qDebug() << QSqlDatabase::drivers(); 有打印结果可知&#xff0c;没有MYSQL数据库的驱动 2、下载MYSQL数据库驱动&#xff0c;查看下面的文章配置&#xff0c;亲测&#xff0c;可以成功 Qt6 配置MySQL…

百面算法工程师 | 模型评价指标及优化策略

本文给大家带来的百面算法工程师是深度学习模型评价指标的面试总结&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们还将介绍一些常见的评价方案&#xff0c;并提供参考的回答及其理论基础&…

7 系列 FPGA 产品介绍及选型

目录 Spartan-7 FPGAsArtix-7 FPGAsKintex-7 FPGAsVirtex-7 FPGAsFPGA芯片命名规则DSP资源BRAM资源Transceivers 资源Transceivers 总带宽I/O 个数及带宽参考文档 Spartan-7 FPGAs Artix-7 FPGAs Kintex-7 FPGAs Virtex-7 FPGAs FPGA芯片命名规则 DSP资源 BRAM资源 Transceiver…

深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f525; 引言&#x1f9f1; 原型基础⛓️ 原型链的形成&#x1f504; 修改原型的影响&#x1f3c1; 原型链的尽头为什么null标志着结束&#xff1f;实际意义 &#x1f310; &#x1f504; 继承的实现方式1. 原型链继承…