(一)导入热补丁资源和工具
xlua源代码中assets文件夹中的plugins文件夹和xlua文件夹,放到unity工程中的asset目录下,xlua中的tools文件夹,放在项目的asset目录的同级目录下。
然后配置playersetting,最后编辑器会出现热补丁注入的选项,如图所示
(二)资源热更,代码热补丁的原理和流程,步骤
步骤:
1.做一个客户端demo
2.服务器放上要更换的资源
3.客户端下载服务器要更新的资源
4.客户端使用服务端的更新资源
5.代码热补丁,实现demo中不同的功能
(三)具体实现
(1)客户端demo
功能:点击鼠标左键,生成一个cube
c#代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
[Hotfix]//这个类能打热补丁的意思
public class Game : MonoBehaviour
{
private int num1=100;
public int num3=300;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//这块加载的资源,还有代码具体操作可能更改
GameObject prefab =(GameObject) Resources.Load("Cube");
GameObject go=Instantiate(prefab);
}
}
}
(2)准备热更的资源包
更改需求:把生成的cube改成球体,sphere
步骤:
1.准备好球体,准备好lua脚本,都打包成同一个ab包,如图所示
2.编写脚本生成ab包
具体步骤参考本人这篇:
超详细的ab打包过程
c#代码
using UnityEditor;
using System.IO;
public class HotFixABTools : Editor
{
[MenuItem("Tools/HotFixABCreate")]
static void CreateHotFixAB()
{
//把打包资源放到这个文件夹中,没有就创建
string path = "HotFixAssetBundles";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);
Debug.Log("打包成功");
}
}
编译后,生成的包如图所示
(3)编写下载ab包的代码,把资源和lua脚本下载下来
具体步骤参考本人这篇:
超详细的ab打包过程
将c#代码绑到空物体上
科普路径
这个路径Application.persistentDataPath,热更的重要路径,该文件夹可读可写,在移动端唯一一个可读写操作的文件夹。
移动端可以将本地的资源(资源MD5值配置表)等一些文件放到StreamingAssets文件夹下,通过Copy到persistentDataPath下与服务器的版本文件配置表作比对,完成资源的热更。
为什么不在StreamingAsset文件夹下直接操作?因为该文件夹只读,不可写,资源无法更新进去。
为什么不在persistentDataPath文件夹操作,因为该文件夹是apk安装以后,才会形成的一个文件夹,无法提前创建。
本来以为,persistentDataPath文件夹,是每次打开游戏,形成的,里面的数据是只在打开游戏期间临时保存,关闭游戏就会消除,今天做个小测试,原来该文件夹是安装完apk以后形成,里面的数据持久存在。
c#代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class LoadHotFixAB : MonoBehaviour
{
//这里的文件的路径名要注意
string path = @"file:///Users/Magician/Desktop/LittleSomethingsTest/HotFixAssetBundles/hotfixab.u3d";
public AssetBundle hotab;//把这个下载的ab包变成公共变量,别处好用
private void Awake()
{
StartCoroutine(LoadHotFixABS());
}
IEnumerator LoadHotFixABS()
{
//可以先清除下缓存,一面加载了之前的
Caching.ClearCache();
//用有缓存机制的加载,设置版本号为1
WWW w1 = WWW.LoadFromCacheOrDownload(path, 1);
//拿到加载好的资源包
hotab = w1.assetBundle;
//资源包里的lua脚本可以用textasset读出来
TextAsset hotlua = hotab.LoadAsset<TextAsset>("HotFixLua.lua");
//移动端热更路径,文章中有科普
string newPath = Application.persistentDataPath + @"/HotFixLua.lua.txt";
//如果不存在这个路径就创建,然后讲文件写入该路径
if (!File.Exists(newPath))
{
File.Create(newPath);
}
File.WriteAllText(newPath, hotlua.text);
yield return null;
}
}
(4)执行下载的lua代码,设置执行顺序
空物体挂的脚本如图所示
有加载ab包的,有执行lua脚本的,所以要有个执行顺序,需要设置。
设置成先下载包,再执行lua脚本
c#代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System.IO;
public class Excutelua : MonoBehaviour
{
private void Awake()
{
LuaEnv luaEnv = new LuaEnv();
luaEnv.AddLoader(myLoader);
luaEnv.DoString("require 'HotFixLua'");
//这两句的关系是,根据这个dostring中的hotfixlua,传给了myloader里的filepath
//所以加载器加载这个文件。
}
//自定以加载器
public byte[] myLoader(ref string filepath)
{
//去这个路径下,把文本内容读出来,以字节数组的方式返回
string newpath = Application.persistentDataPath + @"/" + filepath + ".lua.txt";
string txtstring = File.ReadAllText(newpath);
return System.Text.Encoding.UTF8.GetBytes(txtstring);
}
}
ps:也就是说走完这一步,从打包资源和代码,到下载使用lua代码,都实现了,下面就是具体操作lua脚本进行热补丁了。
(5)热补丁代码的实现
总的目标是用lua中的update替换掉,c#的这个update,使原来点击生成cube,现在点击生成球体,并赋值坐标5,5,5
注意:修改了lua脚本,要重新打包到原来的那个目录
lua脚本
--打印版本号
print("version:0.1")
--这句表示这个类里的私有内容是可用的,前提是这个类打了热补丁标签
xlua.private_accessible(CS.Game)
--这句的意思是把这个类的update方法,用这个匿名方法替换掉
xlua.hotfix(CS.Game,"Update",
function(self)
--打印下Game类的私有变量和公共变量
print(self.num1,self.num3)
--最终把cube替换ab资源包里的球体
local cc=CS.UnityEngine --把命名空间变成变量
if cc.Input.GetMouseButtonDown(0) then
--找到挂着加载ab包脚本的游戏物体
local dGo=cc.GameObject.Find("ScriptsManager")
--获得ab包
local t=dGo:GetComponent("LoadHotFixAB").hotab
--找到ab包里的资源
local obj=t:LoadAsset("Sphere")
--实例化这个球体
local go=cc.GameObject.Instantiate(obj)
--更改其位置
go.transform.position=cc.Vector3(5,5,5)
end
end
)
重新打包,运行会报这个错,这个错表示lua热补丁没注入进去
这个错的解决方案:
先点击这个
再点击这个
就能热补丁注入成功了,记住,只要是更改了脚本或者资源,重新打包后,都要重新生成lua代码,然后再注入
科普一下,this,self,指的是脚本依附的这个游戏对象