以下内容均来自Tencent/InjectFix项目分享,可在Github上查到 链接在下面
人类身份验证 - SegmentFaultsegmentfault.com Tencent/InjectFixgithub.com首先是创建工程
然后根据指导
右键编辑
打开后是这样
将UNITY_HOME变量的值修改为指向本机unity安装目录
接下来两个框对应的是工程名
类似这样,这一步涉及了一些文件的注入必不可少,修改完保存,
然后运行build_for_unity.bat,
类似这样 注意看有没有错误 例如上图中IFix.Core.dll注入是有误的,不会弄的话可以直接Copy进对应路径
最后正确的运行环境需要包括
一个与Assets平级的文件IFixToolKit
IFixToolKit里面包括
Assets文件里
首先是IFix下
其次是Plugins下要有IFix.Core.dll是编译时导入的,如果没有可以Copy进来
最后是Editor文件
热补丁的实现依赖于提前做些静态代码插入,需要做配置类
并且配置必须放在Editor目录下,创个脚本在Editor下
作者提供了两种方式
[Configure]
public class InterpertConfig {
[IFix]
static IEnumerable<Type> ToProcess
{
get
{
return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
where type.Namespace == "XLua" && !type.Name.Contains("<")
select type);
//对XLua命名空间下进行插入
}
}
}
和
[Configure]
public class HelloworldCfg
{
[IFix]
static IEnumerable<Type> hotfix
{
get
{
return new List<Type>()
{
typeof(IFix.Test.Calculator)//单个类
};
}
}
}
有两点要求:
*配置类打上Configure标签
* 配置的属性打上IFix标签,而且必须是 __static__ 类型
我在做的时候尝试了
return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
select type);
这样写把Assembly-CSharp工程下类全都插入,不知是否有什么后遗症
--------------------------插入补充上面的后遗症-----------
在问答中有提到不支持泛型插入和不支持异步匿名函数
后续在更新
------------------------------------------------------------
将类插入后接下来是补丁的制作
要对类下的方法进行热修复
只需要在方法上打上[Patch]标签
说下操作步骤:
例如一开始
public int Add(int a, int b)
{
return a - b;
}
是错误的
那么要进行热修复就在方法上打上标签并修改里面内容
[Patch]
public int Add(int a, int b)
{
return a + b;
}
然后保存在Unity执行"InjectFix/Fix"菜单。
补丁制作成功后会放到工程目录下,文件名为“{Dll Name}.patch.bytes”(比如:“Assembly-CSharp.patch.bytes”)
如果要在Unity上体验需要执行"InjectFix/Inject"菜单,否则编辑器不会走新的逻辑
接下来就是上传补丁到手机
挂个空物体在Start中调用下面的方法
IEnumerator enumerator()
{
string path = "";
#if UNITY_IOS
#elif UNITY_ANDROID
path = @"http://192.168.0.0:80/Assembly-CSharp.patch.bytes";
#elif UNITY_EDITOR
path = @"http://localhost/Assembly-CSharp.patch.bytes";
#endif
var request = UnityWebRequest.Get(path);
yield return request.SendWebRequest();
if (request.isHttpError || request.isNetworkError)
{
Debug.Log("载入热更新文件失败"+ "request.isHttpError:" + request.isHttpError + "request.isNetworkError:" + request.isNetworkError);
}
else
{
Debug.Log("载入热更新文件成功");
byte[] bytes = request.downloadHandler.data;
PatchManager.Load(new MemoryStream(bytes));//加载
}
}
加载完后就可看到热修复
至于原理作者在知乎上有回答,作为Xlua的升级版IFix运行时非常小巧,仅100K左右,比各lua方案,ILRuntime都要小很多,而且不依赖第三方库,纯C#实现。
支持每个游戏生成一份自己私有的补丁格式,私有的指令定义。这样相比通用的lua原代码,lua字节码,clr程序集都更安全些。
支持Assembly-CSharp.dll之外的dll的修复。
附上作者对于Xlua的回答
https://www.zhihu.com/question/54344452/answer/139413144
另外我在热修复的代码里用到了更新前Image.color = Color.blue更新后Image.color = Color.red,由于Color.red并未加载过,Unity进行了裁剪
导致报错 can not load method [get_red] of UnityEngine.Color
以至于热修复无法实现,此处是个小坑,有测试的可以避免可以使用new Color(0,0,0)
后续下载判断时
我的想法是存在PlayerPres存起来然后MD5判断
- string str = System.Text.Encoding.UTF8.GetString(bytes);
- byte[] decBytes = System.Text.Encoding.UTF8.GetBytes(str);
首先尝试了这种转换以PlayerPres.SetString的方法存起来
发现这种转换方式貌似转换会影响PatchManager.Load正常使用 具体没有深入研究
使用
- string str = Convert.ToBase64String(bytes);
- byte[] decBytes = Convert.FromBase64String(str);
这种方式转换和使用正常
--------------------------------------------------------------
[iFix.Interpret]//切换到解析执行 例如新增的方法就需要打上这个标签
[iFix.Patch]//直接在要做成补丁的方法上打标签
[iFix.CustomBridge]//可以手动指定要生成delegate(主要用于闭包)、interface(比如迭代器语法糖)的桥接(这个还未具体使用,有大佬知道可以说下谢谢)
-----------------------------------------------------------------
文章如果有不对的地方欢迎指出修改,谢谢!!
关于热修复其他问题可以查看FAQ和Tencent/InjectFix
最后谢谢大佬的开源和分享跟回答 非常感谢!!!!