不要忽视Managed code stripping的副作用
0x00 前言
Unity 2018.3之后,新的“Managed Stripping Level”选项将替换 player settings 中原有的“Stripping Level”选项。 这个新的选项可用于所有平台以及Mono和IL2CPP脚本运行时。而这个功能的主要目的则是通过删除一些未使用的代码来减小应用程序的大小。 嗯,听起来不错,但这里存在一个潜在的副作用,即Unity如何知道哪些代码才是未使用的代码呢?

0x01 Load From Assetbundle 以及 “the script is missing”
但是,在继续讨论代码剔除流水线之前,让我们看一下由于代码剔除导致问题的一个情景。
现在,让我们在编辑器中创建一个Cube和一个Timeline资源。 使用Timeline,我们可以将Cube从A点移动到B点。
为了更好地管理和更新资源,我们将场景中的Cube制作为Prefab并将Cube本身从场景中删除。 然后,我们将这个prefab和Timeline资源制成AssetBundle,以便在运行时动态加载资源。

我们可以在编辑器中加载Assetbundle并实例化Prefab,然后我们可以看到Cube开始了从点A到点B的移动——Timeline的脚本生效了。
此时,这个工作流似乎工作正常: 从场景中删除资源,将它们放入Assetbundle中,并在运行时动态加载它们。
之后,我们将项目构建到iOS平台,运行相同的场景并加载相同的Assetbundle以在运行时创建Cube对象。 但是这次,Cube并没有开始按预期移动,并且我们从Unity收到了一条错误消息。

“The referenced script (UnityEngine.Timeline.AnimationTrack) on this Behaviour is missing!”
Timeline的脚本丢失了,并且导致了Cube无法在iOS平台上移动。
0x02 代码剔除流水线
丢失与Timeline相关的脚本的原因是,在构建iOS版本时Unity删除了相关代码。
首先要注意的是,iOS使用IL2CPP脚本运行时。 因为Apple的App Store不再接受Mono版本,并且iOS 11及更高版本也不支持Mono。 而选择IL2CPP脚本运行时的时候,“Managed code stripping”的“Disabled”选项将不可用。 这意味着当我们选择IL2CPP脚本运行时的结果就是无法关闭代码剔除。

要注意的第二件事是代码剔除流水线本身。 Unity的Build Pipeline会使用一个称为UnityLinker的工具来剔除托管代码。该过程的工作方式是定义root assemblies,然后使用静态代码分析来确定这些root assemblies还要使用哪些其他的托管代码。 之后删除所有无法访问的代码,即所谓的未使用代码。 其中Unity Engine的程序集也是有可能被剥离的。 root assemblies是Unity Editor根据用户脚本代码编译的程序集,例如Assembly-CSharp.dll。同时构建中包含的场景也会被视为root。
因此,在运行时从Assetbundle加载资产时,至少有3种方法可以避免类似脚本丢失的问题。
- 在构建的场景中引用所需的脚本,以防止在构建项目时剔除需要的代码。

如图,将PlayableDirector组件和一个空的Timeline对象添加到场景中。
2. 在脚本中引用所需的类,以防止在构建项目时剔除需要的代码。

3. 添加一个link.xml文件,以防止UnityLinker剔除所需的代码。

可以在下面的代码仓库中查看这三种方式的示例,4个分支分别代表了会被剔除代码(Master)以及3种防止代码被错误剔除的方式。
https://github.com/chenjd/CodeStripExamplegithub.com
0x03 结论
如果你开启了代码剔除功能以减小构建的包体大小,那么请留意Unity是否会剔除你在运行时所需的代码,例如反射相关的代码等等。 特别是对于那些使用IL2CPP脚本运行时的平台(例如iOS),默认情况下会启用代码剔除。 如果使用Assetbundle管理资源,则需要注意不要删除所需的代码。
不要忽视Managed code stripping的副作用的更多相关文章
- Optimize Managed Code For Multi-Core Machines
Parallel Performance Optimize Managed Code For Multi-Core Machines Daan Leijen and Judd Hall This ar ...
- Passing JavaScript Objects to Managed Code
Silverlight If the target managed property or input parameter is strongly typed (that is, not typed ...
- How to: Synchronize Files by Using Managed Code
The examples in this topic focus on the following Sync Framework types: FileSyncProvider FileSyncOpt ...
- [转]Passing Managed Structures With Strings To Unmanaged Code Part 3
1. Introduction. 1.1 In part 1 of this series of blogs we studied how to pass a managed structure (w ...
- [转]Passing Managed Structures With Strings To Unmanaged Code Part 2
1. Introduction. 1.1 In part 1 of this series of blogs we studied how to pass a managed structure (w ...
- [转]Passing Managed Structures With Strings To Unmanaged Code Part 1
1. Introduction. 1.1 Managed structures that contain strings are a common sight. The trouble is that ...
- Native code on Windows Phone 8(转)
Windows Phone 8 introduces the ability to use native code to implement Windows Phone. In this sectio ...
- Calling C++ code from C# z
http://blogs.msdn.com/b/borisj/archive/2006/09/28/769708.aspx I apologize for the long delay for thi ...
- code 代码分析 及其解决方案
官网地址:http://msdn.microsoft.com/zh-cn/library/ms182135.aspx [FxCop.设计规则]11. 不应该使用默认参数 参考地址:http://blo ...
随机推荐
- Sqlite教程(3) SQlite Query
Configuration是属於util工具包. 把所有环境设置都定义在Configuration工具包里,那麽这个Configuration就是独立的单一入囗. 在架构上,可以提高耦合度,而且出Bu ...
- PAT甲级——1027 Colors in Mars
1027 Colors in Mars People in Mars represent the colors in their computers in a similar way as the E ...
- 关于Apache Commons-Lang3的使用
在日常工作中,我们经常要使用到一些开源工具包,比如String,Date等等.有时候我们并不清楚有这些工具类的存在,造成在开发过程中重新实现导致时间浪费,且开发的代码质量不佳.而apache其实已经提 ...
- openssl 密钥注意
使用openssl生成的密钥,在对加密字符串进行数字签名的时候,程序一直报错,错误异常: algid parse error, not a sequence 其原因是因为,openssl生成的私钥没 ...
- 数论入门——斐蜀定理与拓展欧几里得算法
斐蜀定理 内容 斐蜀定理又叫贝祖定理,它的内容是这样的: 若$a,bin N$,那么对于任意x,y,方程$ax+by=gcd(a,b)*k(kin N)$一定有解,且一定有一组解使$ax+by=gcd ...
- vue项目中net::ERR_CONNECTION_TIMED_OUT错误
我出错的原因时network地址与我本机ip地址不一致 Network: http://192.168.13.30:8080/ 处理方法: 在vue项目中新建一个vue.config.js文件 配置上 ...
- 13.1 CentOS系统启动流程介绍
CentOS系统启动流程介绍 本章我们将学习 Linux 启动流程和内核模块管理相关的内容.通过本章我们将学习如下内容: Linux 系统的组成及特点 CentOS 系统的启动流程 开机启动成 gru ...
- MOOC(7)- case依赖、读取json配置文件进行多个接口请求-mock(8)
mock, 较7属于代码优化 # -*- coding: utf-8 -*- # @Time : 2020/2/12 8:40 # @File : learn_mock_8.py # @Author: ...
- 接口测试-chap6-获取页面动态token
1.在发起某些请求时,可能会要求必须是从某个页面进行请求,此时会验证页面的token 2.这个token是动态生成的,每次请求时值都是不同的, 不可以通过fiddler抓取的值作为固定值传入,通过fi ...
- StringUtil中isBlank(),idNUll,isEmpty的区别
StringUtils 方法的操作对象是 java.lang.String 类型的对象,是 JDK 提供的 String 类型操作方法的补充,并且是 null 安全的(即如果输入参数 String 为 ...