使用 Mono.Cecil 辅助 Unity3D 手游进行性能测试(续)

之前的方法及其局限

问题背景和最初的尝试见这里。最开始的想法比较简单,只想着利用 PostprocessBuild 这个事件,来对已经准备好的本地工程文件(iOS 或 Android)中的 .NET 程序集进行注入。但是,这样做限制很多。

首先,无法对 IL2CPP 作为 Scripting Backend 的情况进行注入。因为触发这个事件时,本地工程文件中没有 .NET 程序集,只有 C++ 代码,无法用 Cecil 进行注入。

第二,Android 平台,用 Mono2x 作为 Scripting Backend 的情况下,也需要打包为 Android Studio Project 才能使用。对于直接打包成 apk 的情况,无法简单的进行注入(除非使用解包、注入、重新签名打包的方法,比较麻烦)。

第三,iOS 平台,即使用 Mono2x 作为 Scripting Backend,也无法成功。这是因为在 iOS 平台打包需要先进行一个叫 AOT Cross Compiling 的步骤,对所有的程序集生成对应的 .dll.s 文件。这些文件包含的信息会在运行时被校验,如果我篡改了程序集,而没有理会 .dll.s 文件,在运行时会报错。错误信息类似

A script behaviour (probably XXX?) has a different seralization layout when loading. (Read ** bytes but expected ** bytes)

Did you #ifdef UNITY_EDITOR a section of your serialized properties in any of your scripts?

其中 XXX 是 .NET 脚本名称,两组星号表示两个不同值。这错误最终导致脚本加载失败,无法运行游戏。与错误信息描述不同,我并没有在出问题的脚本上写任何条件编译的代码。要想解决这个问题,估计需要篡改 .dll.s 文件才可以,仍然是很不经济的。

篡改编译器的方法

接下来一个办法,就是对 Unity 的 C# 编译器 mcs.exe 进行篡改。我没有深入实验,因为几个简单的实验就耗费了一天多的时间。我主要尝试了两种方法,当然,都没成功。

方法一,将原 mcs.exe 重命名(如 mcs1.exe),而后自己写一个 .NET 控制台应用程序,占据原来 mcs.exe 的位置,在其中用 System.Diagnostic.Process 类来启动 mcs1.exe。这个过程中,我对 Process 对象的一些配置,如环境变量(EnvironmentVariables 属性)、输入输出重定向(RedirectStandardXXX 属性)进行了多种排列组合,仍无法正确调用 mcs1.exe,就更不要说调用之后的事情了。

方法二,直接在 mcs.exe 中注入代码。因为 mcs.exe 也是一个 .NET 应用程序,并且看上去未经混淆,所以直接注入是可行的。即,「把向游戏程序集中注入代码的代码,注入到编译器中。」这样做主要的问题,是 mcs.exe 的输出目录是临时文件夹,无法保证其中有我们依赖的(如注入后写入程序集时,需要用 Mono.Cecil 的 DefaultAssemblyResolver 进行解析的)程序集。

通过 OnPostprocessScene 回调事件来进行注入

Unity 虽然没有在执行 mcs.exe 和后续步骤(IL2CPP、Android 打包 apk、iOS 上的 AOT 交叉编译等)之间提供回调,但是回调事件 OnPostprocessScene 目前是确保在它们之间至少触发一次的。多亏 https://github.com/rayosu/UnityDllInjector 提醒了我。在这个事件回调中处理 DLL,理论上在任何平台、任何 Scripting Backend 上都可以有效注入。实现过程中有几个要点需要注意:

  • 事件 OnPostprocessScene 对应 Build Settings 中指定打包的场景个数,所以它可能执行多次,故而需要防止重复。除了上述 UnityDllInjector 中提供的方法,还可以直接把注入标记写入你的目标程序集。但值得注意的是,新增一个用于标记的空类在 iOS + Mono2x 下又是不好用的,猜测还和 AOT 交叉编译有关。保险的做法之一,是在游戏代码中保留几个 bool 常量,值为 false,注入前检查相应的值,如果为 true 则跳过,否则注入。注入完成后,将相应的 bool 常量篡改为 true 即可。

  • 游戏脚本对应的程序集,在注入时一定处于和 Assets 同级的 Library 下的 ScriptAssemblies 文件夹下,但要注意你依赖的 Unity 程序集。我使用 UnityDllInjector 提供的方法,依然不能保证获取到需要的程序集。最终我采用的方法是,使用 EditorApplication.applicationContentsPath 获取 Unity 安装目录,在其中 Data/Managed 目录里寻找必要的程序集。

目前我测试了 Android + Mono/IL2CPP 和 iOS + IL2CPP,都没有问题。iOS + Mono2x 可能由于我们项目本身的一些问题,在 Xcode 链接阶段有一些问题。


旧文搬运,2017-06-15 首发于博客园。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容