文章目錄
- InjectFix介紹
- InjectFix使用說明
- [IFix.Patch]
- [IFix.Interpret]
- [IFix.CustomBridge]
- [IFix.Filter]
- 專案中使用
- 接入遇到的問題記錄
- 贊賞與支持
InjectFix介紹
插件地址:https://github.com/Tencent/InjectFix
作用: 用于修復線上C# bug
流程: InjectFix包括Inject和Fix兩個部分,發包的時候對需要修復的類進行插樁(Inject)處理,線上版本要寫好加載熱更補丁包的邏輯,通過生成Patch補丁進行資源熱更的形式進行修復線上bug,
原理: InjectFix實作bug修復主要靠兩部分:虛擬機負責新邏輯的決議執行;注入代碼負責把呼叫重定向到虛擬機,
作者對Inject的介紹:https://segmentfault.com/a/1190000020375313
優勢: 代碼都以原生的方式執行,只有需要修復的代碼會重定向到虛擬機執行,內部使用反射,不如xlua的靜態warp,但考慮到只有少量函式需要修復,不會有大量性能損耗,
InjectFix使用說明
- InjectFix通過標簽標注的形式,進行對代碼插樁和生成補丁包生成處理,
- 標簽分為注入和補丁,注入標簽在發包前做,補丁標簽在發包后修復階段使用,
| 標簽 | 使用階段 | 用途 | 用法 |
|---|---|---|---|
| [Patch] | 補丁 | 修復函式 | 只能放在函式上 |
| [Interpret] | 補丁 | 新增屬性,函式,型別 | 放在屬性,函式,型別上 |
| [CustomBridge] | 注入 | interface和delegate橋接 | 只能放在單獨寫一個靜態類上,存盤虛擬機的類適配到原生interface或者虛擬機的函式適配到原生delegate,該類不能放Editor目錄 |
| [Configure] | 注入 | 配置類 | 只能放在單獨寫一個存放在Editor目錄下的類上 |
| [IFix] | 注入 | 可能需要修復函式的類的集合 | 只能放在[Configure]類的一個靜態屬性上 |
| [Filter] | 注入 | 不想發生注入的函式 | 只能放在[Configure]類的一個靜態函式上 |
[IFix.Patch]
修復某個函式,該標簽只能用在方法上,直接在方法上面標注一下[IFix.Patch]即可
[IFix.Patch]
private int Add(int a,int b)
{
return a * b;
}
[IFix.Interpret]
新增個函式或者類,在屬性,方法,型別上,直接在要新增的代碼上面標注一下這個標簽即可,
[IFix.Patch]和[IFix.Interpret]屬于比較常用的修復Bug
[IFix.CustomBridge]
在注入階段使用; 把一個虛擬機的類適配到原生interface或者把一個虛擬機的函式適配到原生delegate,
- 修復代碼賦值一個閉包到一個delegate變數;
- 修復代碼的Unity協程用了yield return;
- 新增一個函式,賦值到一個delegate變數;
- 新增一個類,賦值到一個原生interface變數;
- 新增函式,用了yield return;
該標簽只能用在類上,寫上一個靜態類,里面有一個靜態欄位,值就是interface和delegate的型別集合,該配置類不能放到Editor目錄,且不能內嵌到另外一個類里頭,
[IFix.CustomBridge]
public static class AdditionalBridge
{
static List<Type> bridge = new List<Type>()
{
typeof(ISubSystem),
typeof(IEnumerator), //如果之前使用過協程,可不做處理
typeof(Test.MyDelegate)
};
}
[IFix.Filter]
在注入階段使用,過濾某些方法,在注入階段,凡是在[IFix]標簽下的屬性里面的值,都會被注入適配代碼,但如果不想對某個函式進行注入,可以用該標簽進行過濾,該標簽只能用在方法上,Configure類中的一個靜態方法,
[Filter]
static bool Filter(System.Reflection.MethodInfo methodInfo)
{
return methodInfo.DeclaringType.FullName == "Test"
&& (methodInfo.Name == "Test2" || methodInfo.Name == "Test1");
}
專案中使用
【注入(發包前)】
- 可以單獨對一個型別或者一個dll進行插樁配置,打包的時候會自動注入到程式集中去,
- 要修復Assets下dll的類,需要在InjectFixAssemblys中配置對應dll的路徑資訊
使用PatchManager.Load(stream)加載補丁:
string[] fixFileNames = Directory.GetFiles(fullFixFilePath, "*.bytes");
foreach (var fileName in fixFileNames)
{
FileStream stream = new FileStream(fileName, FileMode.Open);
if (stream != null)
{
try
{
PatchManager.Load(stream);
}
catch (Exception e)
{
Debug.LogError(e.ToString());
}
Debug.LogFormat("InjectFix load fix file {0} success and start pathch", fileName);
stream.Dispose();
}
}
【Fix補丁包(發包后需要修復)】
在需要修復的代碼上面加上Patch標簽,生成對應平臺補丁包,走熱更流程,完成修復,
PS:一個程式集生成一個補丁包,多個補丁包會自動卸載上一個,即時多次Load,只有最后一個會生效,
【接入】
具體接入參考官方檔案
接入遇到的問題記錄
1. 注入失敗,提示下面報錯
System.Exception: assembly may be not injected yet, cat find IFix.ILFixInterfaceBridge, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
解決:
- 確保出包之前注入成功,官方監聽場景打包之后進行自動注入 ([UnityEditor.Callbacks.PostProcessScene]),確保注入注入之后不會觸發編譯,若觸發編譯(比如改變dll或者路徑),則注入失效,需要手動呼叫IFixEditor.InjectAllAssemblys重新注入
- 如果需要注入自定義程式集,需要改官方原始碼,官方會限定注入project\Library\ScriptAssemblies 路徑下的程式集,若要注入Assets/Plugins下的程式集,需要去改對應路徑和ScriptAssemblies限制,另外注入第三方dll會觸發編譯,需要重新注入ScriptAssemblies下的Assembly-CSharp.dll
2. 泛型Patch報錯
Unhandled Exception:System.Exception: Utils/d__0 is CompilerGenerated
Unhandled Exception:System.InvalidProgramException: try to use a generic type definition: !0
InjectFix對于泛型支持有限制,不支持一個不確定的泛型方法,支持確定的泛型方法
更多錯誤匯集
官方Issues
后期有坑持續記錄
贊賞與支持
【收藏與點贊】
覺得寫的不錯的可以收藏點贊轉發噢~
【請作者喝杯咖啡】
覺得寫的不錯的可以請作者喝杯咖啡噢~
您的支持是我創作和分享的動力!

(完)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/398518.html
標籤:其他
