Unity Injection
Runtime method injection for Unity that enables dynamic function replacement at runtime. Supports both Mono and IL2CPP, works with engine and user code, and operates entirely within the Unity Editor without external tools. Includes decorators, data proxies, and dependency injection capabilities for implementing AOP patterns.
com.bbbirder.injection 
Install via UPM
Add to Unity Package Manager using this URL
https://www.pkglnk.dev/injection.git README Markdown
Copy this to your project's README.md
## Installation
Add **Unity Injection** to your Unity project via Package Manager:
1. Open **Window > Package Manager**
2. Click **+** > **Add package from git URL**
3. Enter:
```
https://www.pkglnk.dev/injection.git
```
[](https://www.pkglnk.dev/pkg/injection)Dependencies (2)
README
UnityInjection
Unity注入模块,可以运行时改变被注入函数实现。
Verified Verisons:
| Unity 2021.3.x | Unity 2022.3.x |
|---|---|
| :heavy_check_mark: | :heavy_check_mark: |
Purpose
开发此模块的最初动机是修改UnityEngine的源码。对这样一个具体问题一般化分析和设计后,最终实现顺便支持了用户自定义的装饰器和AOP。
是个轮子?
Unity的注入模块已经有一些其他大神的实现了,为什么还要造一个轮子呢?原因如下:
- 基于UnityEditor。一些注入模块,需要依赖外部工具;而此实现在完全在UnityEditor下注入。
- 支持IL2CPP。一些注入模块只支持Editor和Mono;而此实现支持所有平台和选项。
- 支持修改引擎源码。一些注入模块只能修改用户代码,无法注入引擎代码;而此实现可以注入引擎和用户代码。
直接修改DLL文件?
直接修改DLL文件是可行的,但是存在以下问题:
- 无法记录所做的修改
- 不方便团队共享和版本控制
- 不能改变Unity版本
- 修改步骤繁琐,容易误操作
Quick Start
Installation
install via git url
step 1. 安装依赖库:DirectRetrieveAttribute
step 2. 通过git url安装
install via openupm (recommend)
execute command line:
openupm add com.bbbirder.injection
Basic Usage
一个修改Debug.Log的例子
using com.bbbirder.injection;
using UnityEngine;
// this illustration shows how to hook `Debug.Log`
public class FirstPatch
{
// the field to be overwrited to original method
static Action<object> RawLog;
static void Log(object msg){
return RawLog.Invoke("[msg] "+msg);
}
internal class MethodReplacer : IInjection
{
// implement method: ProvideInjections
public IEnumerable<InjectionInfo> ProvideInjections()
{
yield return InjectionInfo.Create<Action<object>>(
Debug.Log, // replace Debug.Log
FirstPatch.Log, // with FirstPatch.Log
f => FirstPatch.RawLog = f // save origin method to FirstPatch.RawLog
);
}
}
}
自定类继承自IInjection,并实现接口
ProvideInjections中返回一个或多个InjectionInfo
初始化的时候调用:
FixHelper.InstallAll();// 查找所有注入标记,并使生效
测试成果:
Debug.Log("hello"); //output: [msg] hello
更多用法
更多使用方法参考附带的Sample工程
Possible Problems
| Problem | Reason | Solution |
|---|---|---|
| 文档示例中的异步方法无法打印完整 | WebGL平台不支持多线程 | 文档中使用的是Task,改成UniTask或其他方式即可 |
| 注入时未搜索到标记的方法 | Managed Stripping Level过高,Attribute被移除 |
降低Stripping Level或 保留代码 |
注入时报UnauthorizedAccessException或cannot access file |
文件访问权限不够 | 管理员运行 或 修改目标文件夹的安全设置(属性-安全-编辑,添加当前用户的完全控制) |
打包时报the same key has already been added. Key: mscorlib |
不支持的Unity版本,程序集依赖树包含多个不同版本的mscorlib | 暂不提供解决方案,可自行修改类型引入部分逻辑,如果这个问题影响的人多则解决之 |
How it works
UnityInjection在编译时织入,不用担心运行时兼容性
织入时机:
- 运行时:在打包的Link阶段修改DLL,如此使Runtime生效
- 编辑器时:Domain Reload
Todo List
- 更多Unity版本测试,有问题提ISSUE附Unity版本,或者PR。
- Editor加速注入
当前的方法在Editor下也会执行织入,这将导致domain reload一定程度变慢,这对于超大代码库来说是难以忍受的。 事实上Editor下的织入不是必要的。作者忙完本职工作后,会来完善此处。
- 支持泛型
泛型的支持有一些特殊性,这种特殊性需要额外的工作:
| Inject Phase | Fix Phase | |
|---|---|---|
| AOT approach | 与非泛型方法相同 | - |
| RT approach | 不同的GenericInstance有时共享同一个方法体,有时又独享之。如:Full Generic Sharing方法存在一个共享的方法体;普通Generic Sharing则按照泛型类型内存大小共享方法体 | 泛型实例是运行时创建的。UnityInjection需要实现一种GenericInstantiation(classInst&methodInst)遍历的技术。这种技术对于IL2CPP backend来说,可以轻易实现;但是对于Mono backend,则需要对cctor的额外注入。 |
No comments yet. Be the first!