技术分享连载(九十九)

技术分享连载(九十九)

我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。

UWA QQ群:465082844
UWA 问答社区:answer.uwa4d.com


资源管理

Q1:目前我们项目打出来的APK大小在120MB 左右,打一次包平均耗时在20~25分钟。Build过程中绝大部分的耗时在“Building Scene0”和“Building additional assets”这两个阶段。请问这两个阶段Unity具体是在做哪些操作?有没有什么方式可以减少这阶段的耗时?另外如果从硬件层面考虑,如何更有效地提高打包速度?提高硬盘的读写速度和CPU的性能又分别能带来怎样的耗时收益?

我们使用的是AssetBundle的方式,目前600MB的包,没有太多资源修改的情况下,安卓包出包大约10分钟左右,之前是7-8分钟,不修改C#代码单独出Patch的话大致在5-7分钟。

我们在用的安卓打包机价格大约是1万左右,多CPU并且保证单核CPU的性能也是尽量高一些,SDD肯定必备,其他的没什么关系。

我们的CPU使用的是:
Intel(R)Xeon(R)CPU E5-2683 v3 @ 2.00GHz 2.00 GHz

提醒一下关于贴图压缩,之前我们一直被贴图压缩折磨,高品质实在是太慢,后来我们是区分了Dev和Pub版本,Dev版本本地贴图压缩使用Fast,发布用的Pub版本才用Best的品质,速度快了非常多~即使美术大量修改贴图,Dev版本出包也很快。

感谢贾伟昊提供了上述回答。

我很久之前在Github上发现了这个东西:
pvrtextool_wrapper:https://github.com/fxgames/pvrtextool_wrapper

Unity打包会调用pvrtextool,通过这个wrapper替换掉原始程序,这样可以在打开发版本时,强制把压缩质量设置到fast模式,这样就可以节约大量的时间,而不需要修改任何贴图的压缩质量参数。如果觉得Mac Pro太贵了,可以试一下这个方法。

感谢lujian提供了上述回答。

Building Scene 是Unity在打包场景资源中,Building additional assets 是Unity在打包Resources中的资源,我们项目接近600MB了,每次出包都要50分钟以上,苦不堪言。你可以尝试这样:

1)把资源全部使用AssetBundle的形式。除了第一次,在下次出包的时候,只会打包有变化和增量的资源。因为Resources的每次出版本都会重新打资源。这样可以将没修改的资源打包耗时省下来。
2)配置个好的电脑,把CPU换个好点的,硬盘换成SSD的。

以上两点能节省你出包的时间,目前也是我们使用的方法

感谢 hejianchun提供了上述回答。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a7abe4d847802258a06503d


资源管理

Q2:两次打包,文件均未有改动,但是AssetBundle的内容会有变化,我们感觉是里面包含的脚本内容有差异。Manifest文件显示CRC和AssetFileHash有变化。文件已经上传到UWA问答官网。第一次打包为彻底打包,第二次为增量打包。

彻底打包流程如下:
1、Revert资源
2、Clear所有资源的BundleName
3、按照规则全部设置一遍BundleName
4、使用指令BuildPipeline.BuildAssetBundles(outputPath, abBuilds, BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);进行打包
5、生成文件对应BundleName的映射表

增量打包流程如下:
1、Revert资源
2、Clear所有资源的BundleName
3、按照映射表设置资源BundleName
4、按照规则将其余资源设置BundleName
5、使用指令BuildPipeline.BuildAssetBundles(outputPath, abBuilds, BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);进行打包
6、生成文件对应BundleName的映射表

我们发现,问题主要是我们打包之前,还对UI的Prefab做了一次预处理,会为某些控件增加脚本组件,由于这个修改后的Prefab是不上传的,每次这个操作都会去做,并且每次增加的脚本组件分配的FileId不同,导致每次文件都会有差异。这块检查时疏忽了。

另外,已经和Unity官方确认,Unity 5.x以后,BuildAssetBundleOptions.DeterministicAssetBundle是默认选项,不需要特意再去加了。

该问题题主反馈已经得到了解决,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a7a8b23847802258a065038


其他

Q3:我们输出的AppStore.ipa比Development.ipa大很多,想了解下为什么会这样,具体情况如下:
输出环境:

xcode:9.2
unity:5.6.3p2

数据截图:
请输入图片描述
请输入图片描述
首先,代码使用了swift+obj-c的方式,导出的时候设置了ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES为Yes。从截图能看出,主要是AppStore相比Development多了SwiftSupport目录的内容。我打出来的AppStore.ipa比Development.ipa大了接近50MB。请问各位是如何避免掉这个问题呢?

AppStore的包默认带了symbols,用于崩溃日志的符号化,上传后会被剥离,最终用户下载的不是这个IPA的大小。

该问题来自UWA问答社区,感谢黄晓文提供了回答,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a7435b5e3b569146eeaeb4f


其他

Q4:如果C#中一个函数内容使用宏定义括起,编译时成为一个空函数,但是还是有外部调用,编译时会将这种调用优化掉吗?比如传入参数是做一些函数调用然后传入返回值之类的操作,这种操作的开销应该还在,但是传入常量的话,会不会被编译优化掉?

编译器只会优化掉你用宏包起来,且对应的宏没有被定义的代码。
如:
if UNITY_EDITOR
Debug.Log(“hello uwa”);

else if UNITY_iOS
Debug.Log("good uwa");
endif
那 if UNITY_EDITOR内的只会在Editor下生效,打包后就会被优化了。

感谢 hejianchun提供了解答(UWA整理)

[Conditional]

感谢钱康来提供了解答(UWA整理)

根据以上各位的回复,我在IL2CPP下实测了一下宏定义和条件编译的区别,代码如下图
而编译后生成的C++代码如下:
请输入图片描述
请输入图片描述
可见,两者都会生成函数的定义,但区别在于:
(1)宏定义会把函数定义中的代码移除掉,但是调用处的参数传递不会被优化,所以无法完全消除相关的调用开销;
(2)条件编译会直接移除掉函数调用语句,不再产生相关的调用开销了,但是函数定义中的代码还是在的。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a7a74ac2174bd258ff90f66


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站(answer.uwa4d.com)上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:465082844(仅限技术交流)