一段时间没写了,今天把最重要的一节补上;前面说的内容,开发过程都够用了,但是,如果直接用.lua文件去实现热更,未免太不安全了,所有的代码都裸露在大家眼中了;所有我们需要一个东西去对.lua进行加密打包,框架就给我们提供了一个现成的Bundle工具。
具体使用
1.我们依旧打开工程的.\tolua-master\Assets\ToLua\Examples\18_Bundle文件夹,打开TesetAssetBundle场景;直接运行,我们会发现有报错,原因是因为我们都没有打包lua文件,Bundle都没有。
2.打包lua文件,依次点击导航条上lua -> Build bundle files not jit 按钮;进度条走完后,我们会发现StreamingAssets文件夹下出现了Win文件夹,下面有一堆的lua,lua.unity3d文件等;这时候我们再运行,发现不报错,并且有打印了。
3.只是有打印了,这自动打包怎么用嘛,大家肯定在想,此刻大家肯定是懵B的;大家可以看下Assets下有一个Lua文件夹,我们Bundle的话,框架会帮我们吧Lua下的Lua文件都自动打包;我们可以试一下,双击打开Lua文件夹下的Main.lua文件。
我们此刻改一下打印的信息,将print(“logic start”)改为print(“Test logic start !!!”);删除StreamingAssets下的Win文件夹,继续点击导航条上lua -> Build bundle files not jit 按钮,进度条重新跑了一遍,Win文件夹和下面的打包文件重新又生成了,我们再运行跑一便,发现我们修改的lua内容被打包出去并且运行了。
我们发现修改的lua脚本被重新打包出去了。
代码解析
我们接下来打开TestABLoader类,对此类进行分析下。
public class TestABLoader : MonoBehaviour
{
int bundleCount = int.MaxValue;
string tips = null;
IEnumerator CoLoadBundle(string name, string path)
{
using (WWW www = new WWW(path))
{
if (www == null)
{
Debugger.LogError(name + " bundle not exists");
yield break;
}
yield return www;
if (www.error != null)
{
Debugger.LogError(string.Format("Read {0} failed: {1}", path, www.error));
yield break;
}
--bundleCount;
LuaFileUtils.Instance.AddSearchBundle(name, www.assetBundle);
www.Dispose();
}
}
IEnumerator LoadFinished()
{
while (bundleCount > 0)
{
yield return null;
}
OnBundleLoad();
}
public IEnumerator LoadBundles()
{
string streamingPath = Application.streamingAssetsPath.Replace('\\', '/');
#if UNITY_5 || UNITY_2017 || UNITY_2018
#if UNITY_ANDROID && !UNITY_EDITOR
string main = streamingPath + "/" + LuaConst.osDir + "/" + LuaConst.osDir;
#else
string main = "file:///" + streamingPath + "/" + LuaConst.osDir + "/" + LuaConst.osDir;
#endif
WWW www = new WWW(main);
yield return www;
AssetBundleManifest manifest = (AssetBundleManifest)www.assetBundle.LoadAsset("AssetBundleManifest");
List list = new List(manifest.GetAllAssetBundles());
#else
//此处应该配表获取
List list = new List() { "lua.unity3d", "lua_cjson.unity3d", "lua_system.unity3d", "lua_unityengine.unity3d", "lua_protobuf.unity3d", "lua_misc.unity3d", "lua_socket.unity3d", "lua_system_reflection.unity3d" };
#endif
bundleCount = list.Count;
for (int i = 0; i < list.Count; i++)
{
string str = list[i];
#if UNITY_ANDROID && !UNITY_EDITOR
string path = streamingPath + "/" + LuaConst.osDir + "/" + str;
#else
string path = "file:///" + streamingPath + "/" + LuaConst.osDir + "/" + str;
#endif
string name = Path.GetFileNameWithoutExtension(str);
StartCoroutine(CoLoadBundle(name, path));
}
yield return StartCoroutine(LoadFinished());
}
void Awake()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += ShowTips;
#else
Application.RegisterLogCallback(ShowTips);
#endif
LuaFileUtils file = new LuaFileUtils();
file.beZip = true;
#if UNITY_ANDROID && UNITY_EDITOR
if (IntPtr.Size == 8)
{
throw new Exception("can't run this in unity5.x process for 64 bits, switch to pc platform, or run it in android mobile");
}
#endif
StartCoroutine(LoadBundles());
}
void ShowTips(string msg, string stackTrace, LogType type)
{
tips += msg;
tips += "\r\n";
}
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 200, Screen.height / 2 - 150, 400, 300), tips);
}
void OnApplicationQuit()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
}
void OnBundleLoad()
{
LuaState state = new LuaState();
state.Start();
state.DoString("print('hello tolua#:'..tostring(Vector3.zero))");
state.DoFile("Main.lua");
LuaFunction func = state.GetFunction("Main");
func.Call();
func.Dispose();
state.Dispose();
state = null;
}
}
LoadBundles方法为加载Bundle的方法,机制和AB包加载一样的,首先加载Win文件夹下的Win信息索引文件,通过索引文件得到所有相关的Lua打包文件,通过CoLoadBundle方法将得到的所有文件进行初始化;LoadFinished方法等待所有的打包文件初始化完毕,完毕后执行OnBundleLoad方法;OnBundleLoad方法中 ,使用 state.DoFile(“Main.lua”);方法去加载打包后的Main.lua文件,最后使用 LuaFunction func = state.GetFunction(“Main”);func.Call();对Main.lua方法进行实例和调用。
其实很简单,框架所有lua AB打包和解析代码都抛了出来,要是不适应大家完全可以修改为合适自己项目。有了Bundle和之前的知识,已经足够使用开发进行热更开发。