Unity 代码裁剪(Strip Engine Code)
文章目录
- 0.IL2CPP 打包运行闪退问题
- 1.什么是代码裁剪
- 2.为什么要使用代码裁剪
- 3.代码裁剪设置与级别
- 4.强制保留代码
- 4.1 使用[Preserve]标签
- 4.2 使用Link.xml文件
- 5.Strip中遇到的问题及解决方法
- 6.注意事项
0.IL2CPP 打包运行闪退问题
Google Play要求从2019年8月1日起apk必须支持64位CPU, 否则就下架或不让上. 使apk支持ARM64就需要把Scripting Backend由Mono切换为IL2CPP

那么问题来了, 通过IL2CPP打出的包往往不能正常运行(闪退,报错).

其原因就是, BuildSetting里默认勾选了代码裁剪, 取消勾选打出的apk就能正常运行,但是包体也会变大
1.什么是代码裁剪
官方文档
简而言之:开启代码裁剪,能够在build时将项目中没有用到的代码裁减掉,以减少build出的代码量。
Strip的主要作用在于裁剪系统库、Unity引擎代码、插件代码,往往它们包含了大量对工程无用的代码。
勾选代码裁剪,构建时Unity代码裁剪工具会分析项目中的程序集,查找和删除未使用的代码. 裁剪掉没有使用到的代码.比如,一款2D游戏只用到了Sprite, 2D物理组件, 就可以把没有用到的3D物理代码部分裁剪掉. 使用裁剪功能可以显著减小包体大小, 也是目前Unity游戏包体优化的一个重要环节.
2.为什么要使用代码裁剪
显著减小包体大小:开启代码裁剪,在build时将项目中没有用到的代码裁减掉,以减少build出的代码量加快cpp生成的过程:如果使用了il2cpp,由于build过程中先生成CIL然后再生成cpp代码。所以开启代码裁减之后,能减少CIL的生成,从而加快cpp生成的过程。
3.代码裁剪设置与级别
File->Build Settings->Player Settings->Optimization->Managed Stripping Level
| 属性 | 功能 |
|---|---|
| Disabled | Unity 不会删除任何代码。此设置仅可见,并且是使用 Mono 脚本后端时的默认设置。 |
| Minimal | Unity 仅在 UnityEngine 和 .NET 类库中搜索未使用的代码。Unity 不会删除任何用户编写的代码。此设置最不可能导致任何意外的运行时行为。此设置对于可用性比构建大小更重要的项目很有用。如果您使用 IL2CPP 脚本后端,这是默认设置。 |
| Low | Unity 会搜索部分用户编写的程序集以及所有 UnityEngine 和 .NET 类库以查找未使用的代码。此设置会应用一组规则,删除部分未使用的代码,但会将出现意外后果的可能性降至最低,例如使用反射的运行时代码的行为发生变化。 |
| Medium | Unity 会部分搜索所有程序集以查找无法访问的代码。此设置应用一组规则,可删除更多类型的代码模式以减小构建大小。虽然 Unity 不会删除所有可能无法访问的代码,但此设置确实会增加不良或意外行为更改的风险。 |
| High | Unity 会对所有程序集进行广泛搜索,以查找无法访问的代码。在此设置下,Unity 优先考虑减小尺寸而不是代码稳定性,并删除尽可能多的代码。此搜索可能比较低的剥离级别花费更长的时间。仅对紧凑构建大小极其重要的项目使用此设置。彻底测试您的应用程序并谨慎使用[Preserve]属性和 link.xml 文件,以确保 Unity 链接器不会剥离重要代码。 |
Tips: 等级越高裁剪掉的代码越多, 包体也就越小, 但是对应的风险也就更大:
4.强制保留代码
4.1 使用[Preserve]标签
可以对Assembly、Type、Field、Properties、Method使用。
4.2 使用Link.xml文件
在项目的Assets目录下创建个link.xml
保留整个程序集dll:
<?xml version="1.0" encoding="UTF-8"?>
<linker><assembly fullname="DOTween" preserve="all" /> <!-- 保留 DOTween --><assembly fullname="Newtonsoft.Json" preserve="all" /> <!-- 保留 Newtonsoft.Json --><assembly fullname="Assembly-CSharp" preserve="all" /> <!-- 保留我们写的项目代码 -->
</linker>
保留某个程序集里的某个类:
<assembly fullname="UnityEngine"><type fullname="UnityEngine.SpriteRenderer" preserve="all"/><type fullname="UnityEngine.Rigidbody2D" preserve="all"/>
</assembly>
5.Strip中遇到的问题及解决方法
1. 类型转换错误
InvalidCastException: Unable to cast object of type ‘BehaviourTree’ to type ‘DialogueTree’.
对于该类型错误,无法有效的确定错误原因(以NodeCanvas为例,对错误的实例进行类型转换的逻辑流程无法准确定位,可能与NodeCanvas对行为树资源反序列化的实现有关),最直接的办法是将整个模块的Namespace包含到link中以避免此类问题。
(同时可以对官方示例进行同等级的strip,尝试更仔细的解决问题,通常官方示例因为体量小,能更快的进行build迭代和测试)。
2. 无法为抽象类创建对象
Exception: Cannot create an instance of an interface or abstract type for NodeCanvas.Framework.ActionTask。
通常原因在于其实现类没有被保留下来。报错定位依然不明确。解决办法同上。
3. 无法解析符号
Type with name ‘NodeCanvas.Tasks.Actions.PlayerActions.AnimationAction’ could not be resolved.
其中指出的符号,即类型、方法、属性等,因为没有被保留下来,导致进行反射调用时无法确定符号意义导致的问题。解决方法很明确,就是将符号写入link.xml以在strip过程中保留。
**4. 找不到Class ID对应的类型
ReportException: UnityLogError Could not produce class with ID 134.
通常是因为Unity引擎的代码被Strip掉了,导致在程序运行时找不到对应的类。对此类问题比较方便的一点在于,错误信息给出了具体的类(https://docs.unity3d.com/Manual/ClassIDReference.html),要解决问题只需要将查表找到的Class加入到link.xml即可。
6.注意事项
link.xml配置是根据程序集而不是根据名字空间,例如UnityEngine.Animator,在VisualStudio中跳转到Animator类会发现,它是属于UnityEngine.AnimationModule程序集,而不是UnityEngine程序集。如果配置到错误的程序集自然就不能正确保留该类防止被裁剪。
如保留Animator类,如下方式是无效的:
<assembly fullname="UnityEngine" preserve="all"/>
正确方式应该是:
<assembly fullname="UnityEngine.AnimationModule" preserve="all"/>
Unity项目Build后会在项目Library的子目录,如Library\Bee\artifacts\Android\ManagedStripped下生成项目依赖(没用上的会被裁剪)的全部程序集(不同版本Unity或不同平台生成程序集位置不同),这样就可以确定需要保留哪些程序集。
il2cpp代码裁剪(Strip Engine Code)配置工具:https://blog.csdn.net/final5788/article/details/126451377
相关文章:
Unity 代码裁剪(Strip Engine Code)
文章目录 0.IL2CPP 打包运行闪退问题1.什么是代码裁剪2.为什么要使用代码裁剪3.代码裁剪设置与级别4.强制保留代码4.1 使用[Preserve]标签4.2 使用Link.xml文件 5.Strip中遇到的问题及解决方法6.注意事项 0.IL2CPP 打包运行闪退问题 Google Play要求从2019年8月1日起apk必须支…...
单目3d重建DUSt3R 笔记
目录 DUSt3R 三维重建 报错RecursionError: maximum recursion depth exceeded in comparison 报错 numpy.core.multiarray failed to import 报错Numpy is not available 解决 升级版mast3r 速度变慢 修改了参数设置脚本: 测试效果 操作技巧 DUSt3R 三维重…...
AI驱动TDSQL-C Serverless 数据库技术实战营-与AI的碰撞
目录 一、简介 二、实验介绍 三、结果展示 四、实操指导 4.1 系统设计 4.2 环境搭建(手把手教程) 4.3 应用构建 4.4 效果展示 4.5 踩坑避雷总结 五、清理资源 5.1 删除TDSQL-C Serverless 5.2 删除 HAI 算力 六、实验总结归纳 一、简介 本…...
C++之String类(上)
片头 嗨!好久不见~ 今天我们来学习C的Sting类,不过,在学习它之前,我们先来对STL库有一个简单的了解。 STL(standard template library--标准模板库),是C标准库的重要组成部分,不仅是…...
kubernets基础-ingress详细介绍
文章目录 什么是IngressIngress详细说明Ingress示例 Ingress控制器Ingress控制器的工作原理Ingress控制器的特点常见的Ingress控制器 Ingress关联Ingress控制器一、Ingress资源对象二、Ingress控制器三、Ingress与Ingress控制器的关联方式四、注意事项 多实例部署一、Ingress多…...
jenkins部署Maven和NodeJS项目
在 Java 项目开发中,项目的编译、测试、打包等是比较繁琐的,属于重复劳动的工作,浪费人力和时间成本。以往开发项目时,程序员往往需要花较多的精力在引用 jar 包搭建项目环境上,跨部门甚至跨人员之间的项目结构都有可能…...
在unity资源中发现无效引用
本文主要解决在不打开unity的情况下搜索出无效引用的资源的方法 1. 概述 一般只要遍历一下目录里所有资源,判空一下就好了但有些情况下,不希望打开unity, 尤其希望是在资源整合时,想更快验证资源的合法性, 这对合并提交及出包验证时,都要较大的需求 2. 简单的验证方法 简单来…...
C#知识|基于反射和接口实现抽象工厂设计模式
哈喽,你好啊,我是雷工! 01 应用场景 在项目的多数据库支持上、业务的多算法封装、以及各种变化的业务中; 02 抽象工厂组成 抽象工厂包括抽象产品(即业务接口,可以通过抽象类或抽象接口设计)…...
【分布式微服务云原生】gRPC vs RPC:深入探索远程过程调用的现代与经典
摘要 在分布式系统的世界里,gRPC和RPC是两个耳熟能详的术语,但它们之间有何区别和联系?本文将深入探讨gRPC和RPC的概念、关键特性、以及它们在现代软件开发中的应用。你将了解到gRPC如何作为RPC的一种实现,提供高性能的跨语言远程…...
听说这是MATLAB基础?
MATLAB(矩阵实验室)是一个强大的高性能计算环境和编程语言,广泛应用于数学计算、算法开发、数据分析、可视化以及模拟等多个领域。以下是MATLAB的一些基础知识,涵盖其功能、语法、基本操作等方面。 1. MATLAB环境 工作区…...
【CSS/HTML】圣杯布局和双飞翼布局实现两侧宽度固定,中间宽度自适应及其他扩展实现
前沿简介 圣杯布局和双飞翼布局是前端重要的布局方式。两者的功能相同,都是为了实现一个两侧宽度固定,中间宽度自适应的三栏布局。 圣杯布局来源于文章In Search of the Holy Grail,双飞翼布局来源于淘宝UED。 两者的实现方式有差异,但是都…...
数据流和数据流处理技术
一数据流 首先明确数据流概念:数据流是连续不断生成的、快速变化的无界数据序列 数据流类型: 数据流大致可以分为四种类型 1.连续型数据流:不断地产生数据,数据稳定速度输入系统。 2.突发型数据流:在某特定时间或…...
(IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案
系列文章目录 文章目录 系列文章目录一、(IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案1.资料 一、(IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案 1.资料…...
解决TikTok无网络连接问题解析
随着社交媒体的快速发展,TikTok已成为全球用户最喜欢的短视频平台之一,吸引了数以亿计的用户。然而,在享受这个平台时,用户经常会遇到无网络连接的问题,这不仅影响观看体验,还可能导致无法上传内容或参与社…...
k8s中,ingress的实现原理,及其架构。
图片来源:自己画的 图片来源:k8s官网 首先,什么是ingress? 是服务还是控制器? 都不精确 ingress是一个api资源 service和deployment也是api资源。 这几个相互协作,组建成一个对外提供服务的架构。 ingress提供的…...
【数据结构强化】应用题打卡
应用题打卡 数组的应用 对称矩阵的压缩存储 注意: 1. 2.上三角的行优先存储及下三角的列优先存储与数组的下表对应 上/下三角矩阵的压缩存储 注意: 上/下三角压缩存储是将0元素统一压缩存储,而不是将对角线元素统一压缩存储 三对角矩阵的…...
解决 MySQL 服务无法启动:failed to restart mysql.service: unit not found
目录 前言1. 问题描述2. 问题分析3. 解决步骤3.1 检查 MySQL 服务文件3.2 备份旧的服务文件3.3 启动 MySQL 服务3.4 验证服务状态 4. 总结结语 前言 在日常使用 MySQL 数据库时,有时候可能会遇到服务无法正常启动的问题。这类问题通常出现在系统更新或者服务配置文…...
Dubbo和Http的调用有什么区别
背景 我们在项目开发中,需要进行调用外部接口时,往往使用Dubbo和Http方式都能实现远程调用。那么他们在使用上,有什么区别呢? 定位不同 一个是分布式环境下的框架,一个是通信协议。 Dubbo:是一种高性能的…...
ARM 架构、cpu
一、ARM的架构 ARM是一种基于精简指令集(RISC)的处理器架构. 1、ARM芯片特点 ARM芯片的主要特点有以下几点: 精简指令集:ARM芯片使用精简指令集,即每条指令只完成一项简单的操作,从而提高指令的执行效率…...
【React】入门Day03 —— Redux 与 React Router 核心概念及应用实例详解
1. Redux 介绍 // 创建一个简单的Redux store const { createStore } Redux;// reducer函数 function counterReducer(state { count: 0 }, action) {switch (action.type) {case INCREMENT:return { count: state.count 1 };case DECREMENT:return { count: state.count -…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
