unity tolua 生产unity assetbundlee 点击哪个

Unity官方公布热更新方案性能对比浅析
Unity应用的iOS热更新
作者:丁治宇
Unity TechnologiesChina
? 什么是热更新
? 为何要热更新
? 如何在iOS 上对Unity 应用进行热更新
? 支持Unity iOS 热更新的各种Lua 插件的对比
什么是热更新
? 广义定义
? 无需关闭服务器,不停机状态下修复,更新资源等,重点是更新逻辑代码。
? 狭义定义( iOS热更新)
? 无需将代码重新打包提交至AppStore,即可更新客户端的执行代码,即不用下载app而自动更新程序。
? 苹果禁止了C#的部分反射操作,禁止JIT(即时编译,程序运行时创建并运行新代码),不允许逻辑热更新,只允许使用AssetBundle进行资源热更新。
为何要热更新
? 缩短用户获取新版应用的客户端的流程,改善用户体验。
? 具体到iOS平台的应用上,有以下几个原因
? App Store的审核周期难控制。
? 手机应用更新频繁。
? 对于大型应用,更新成本太大。
? 终极状态
? 不重新下载、不停机状态下完全变换一个应用的内容。
如何在iOS 上对Unity 应用进行热更新
应用的热更新
? 将执行代码预编译为assemblydll。
? 将代码作为TextAsset打包进Assetbundle。
? 运行时,使用Reflection机制实现代码的功能。
? 更新相应的Assetbundle即可实现热更新。
? Android 与iOS 热更新的 异同
? 苹果官方禁止iOS下的程序热更新;JIT在iOS下无效。
? 热更新方案:Unity+Lua插件。
? 使用Lua 插件进行iOS 热更新的 原理
? Unity 热更新的注意点
? 需要更新的代码、资源,都必须打包成AssetBundle(建议使用未压缩的格式打包)
? 熟悉Unity的几个重要的路径
? Resources(只读)
? StreamingAssets(只读)
? Application.dataPath(只读)
? Application.persistentDataPath(可读写)
? 重要路径之 之Resources
? Resources文件夹下的资源无论使用与否都会被打包
? 资源会被压缩,转化成二进制
? 打包后文件夹下的资源只读
? 无法动态更改,无法做热更新
? 使用Resources.Load加载
? 重要路径之StreamingAssets
? 流数据的缓存目录
? 文件夹下的资源无论使用与否都会被打包
? 资源不会被压缩和
? 打包后文件夹下的资源只读,主要存放二进制文件
? 无法做热更新
? WWW类加载(一般用CreateFromFile ,若资源是AssetBundle,依据其打包方式看是否是压缩的来决定)
? 相对路径,具体路径依赖于实际平台
?Application.streamingAssetsPath
? : Application.dataPath + &/Raw& 或Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw
? 重要路径之Application.dataPath
? 游戏的数据文件夹的路径(例如在Editor中的Assets)
? 很少用到
? 无法做热更新
? IOS路径: Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data
? 重要路径之Application.persistentDataPath
? 持久化数据存储目录的路径( 沙盒目录,打包之前不存在 )
? 文件夹下的资源无论使用与否都会被打包
? 运行时有效,可读写
? 无内容限制,从StreamingAsset中读取二进制文件或从AssetBundle读取文件来写入PersistentDataPath中
? 适合热更新
? IOS路径: Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents
? 使用Lua 插件进行iOS 热更新的总体流程
支持Unity iOS 热更新的各种Lua 插件的对比
? uLua(asset store)
? uLua插件原生版本,开山鼻祖
? 不会产生静态代码
? 反射机制,效率低下,速度慢,gcalloc频繁
? 已停止更新维护,不支持Unity5.x,淡出主流
? uLua & cstoLua
? 开发平台成熟稳定,Bug修复迅速
? 开发者众多,资源丰富
? 静态方法,性能优
?有成功商业产品案例(啪啪三国、超神战队、酷鱼吧捕鱼、绝地战警、这不是刀塔等) 鱼、绝地战警、这不是刀塔等)
? 都是基于原生版本的改进;未来,两者会合并成一个插件
? 静态方法,性能优
? 核心代码简洁
? 资源较少,开发平台不够成熟稳定
? 无 无成功商业产品案例 成功商业产品案例
? 基于原生版本的改进
支持Unity iOS 热更新的各种Lua 插件的对比
? C#Light(L#)
? 淡出主流
? 实现的Lua,非完整方案
? 淡出主流
支持Unity iOS 热更新的各种Lua 插件的对比
然后就是 uLua 和 sLua的测试代码。
综合来看 肯定是 uLua 会更好一些。>> ToLua_System_String.cs
ToLua_System_String.cs ( 文件浏览 )
using UnityE
using System.C
public class ToLua_System_String
[NoToLuaAttribute]
public static string ToLua_System_StringDefined =
LuaTypes luatype = LuaDLL.lua_type(L, 1);
if (luatype == LuaTypes.LUA_TSTRING)
string arg0 = LuaDLL.lua_tostring(L, 1);
LuaScriptMgr.PushObject(L, arg0);
LuaDLL.luaL_error(L, &&invalid arguments to method: String.New&&);
return 0;&;
public static string EqualsDefined =
int count = LuaDLL.lua_gettop(L);
if (count == 2 && LuaScriptMgr.CheckTypes(L, 2, typeof(string)))
string obj = LuaScriptMgr.GetVarObject(L, 1)
string arg0 = LuaScriptMgr.GetString(L, 2);
bool o = obj != null ? obj.Equals(arg0) : arg0 ==
LuaScriptMgr.Push(L, o);
else if (count == 2 && LuaScriptMgr.CheckTypes(L, 2, typeof(object)))
string obj = LuaScriptMgr.GetVarObject(L, 1)
object arg0 = LuaScriptMgr.GetVarObject(L,[Unity热更新]tolua# & LuaFramework(二):打包工具
1.资源的创建
注意一下命名规则,一个面板及其相关的东西都放在同一个文件夹中,如果文件夹命名为xxx,则面板预制要命名为xxxPanel
以文件夹为单位进行打包,打包类为Packager.cs。这里要打包的东西分两种,一种为图片等资源,另一种为代码资源(即lua脚本)。对lua脚本的打包已经被框架搞好了,不需要我们考虑,我们要考虑的是对前者的打包,详细的见Packager.cs的HandleExampleBundle方法,这里我做了个小工具:
using UnityE
using System.Collections.G
using UnityE
using System.IO;
using System.T
public enum SuffixEnum
public class AddBuildMapUtility : EditorWindow {
int count = 0;
List&string& bundleNameList = new List&string&();
List&SuffixEnum& suffixList = new List&SuffixEnum&();
List&string& pathList = new List&string&();
Vector2 scrollValue = Vector2.
[MenuItem(&LuaFramework/AddBuildMapUtility&)]
static void SetAssetBundleNameExtension()
EditorWindow.GetWindow&AddBuildMapUtility&();
void OnGUI()
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button(&添加一项&))
AddItem();
if (GUILayout.Button(&清除所有项&))
if (GUILayout.Button(&读取文件(.csv)&))
string path = EditorUtility.OpenFilePanel(&&, Application.dataPath, &csv&);
string content = File.ReadAllText(path);
string[] contents = content.Split(new string[] { &\r\n& }, System.StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i & contents.L i++)
string[] a = contents[i].Split(',');
AddItem(a[0], StringToEnum(a[1]), a[2]);
if (GUILayout.Button(&保存&))
string path = EditorUtility.SaveFilePanel(&&, Application.dataPath, &AssetBundleInfo&, &csv&);
StringBuilder sb = new StringBuilder();
for (int i = 0; i & i++)
if (string.IsNullOrEmpty(bundleNameList[i]))
sb.Append(bundleNameList[i] + &,&);
sb.Append(EnumToString(suffixList[i]) + &,&);
sb.Append(pathList[i] + &\r\n&);
File.WriteAllText(path, sb.ToString());
AssetDatabase.Refresh();
if (GUILayout.Button(&自动填写(所有选中的)&))
int startIndex =
for (int i = 0; i & Selection.objects.L i++)
AddItem();
AutoFill(startIndex, Selection.objects[i]);
startIndex++;
EditorGUILayout.EndHorizontal();
EditorGUILayout.LabelField(&注意:请以文件夹为单位进行选择!!!文件夹名即为包名!!!&);
scrollValue = EditorGUILayout.BeginScrollView(scrollValue);
for (int i = 0; i & i++)
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(i.ToString() + &AB包名&);
bundleNameList[i] = EditorGUILayout.TextField(&&, bundleNameList[i]);
suffixList[i] = (SuffixEnum)EditorGUILayout.EnumPopup(&类型&, suffixList[i]);
pathList[i] = EditorGUILayout.TextField(&路径&, pathList[i]);
if (GUILayout.Button(&自动填写(单个)&))
AutoFill(i, Selection.objects[0]);
if (GUILayout.Button(&输出路径&))
Debug.Log(pathList[i]);
if (GUILayout.Button(&删除该项&))
RemoveItem(i);
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
EditorGUILayout.EndScrollView();
void Clear()
count = 0;
bundleNameList = new List&string&();
suffixList = new List&SuffixEnum&();
pathList = new List&string&();
void AddItem(string bundleName = &&, SuffixEnum suffix = SuffixEnum.Prefab, string path = &&)
bundleNameList.Add(bundleName);
suffixList.Add(suffix);
pathList.Add(path);
void RemoveItem(int index)
bundleNameList.Remove(bundleNameList[index]);
suffixList.Remove(suffixList[index]);
pathList.Remove(pathList[index]);
void AutoFill(int index, Object selectedObject)
string path = AssetDatabase.GetAssetPath(selectedObject);
bundleNameList[index] = path.Remove(0, path.LastIndexOf(&/&) + 1).ToLower() + LuaFramework.AppConst.ExtN
string[] files = Directory.GetFiles(path);
string[] temp = files[0].Split('.');
suffixList[index] = StringToEnum(&*.& + temp[1]);
pathList[index] =
public static string EnumToString(SuffixEnum se)
switch (se)
case SuffixEnum.Prefab:
return &*.prefab&;
case SuffixEnum.Png:
return &*.png&;
case SuffixEnum.Csv:
return &*.csv&;
case SuffixEnum.Txt:
return &*.txt&;
return &null&;
public static SuffixEnum StringToEnum(string s)
switch (s)
case &*.prefab&:
return SuffixEnum.P
case &*.png&:
return SuffixEnum.P
case &*.csv&:
return SuffixEnum.C
case &*.txt&:
return SuffixEnum.T
return SuffixEnum.P
然后对HandleExampleBundle这个方法进行修改:
UGUI版本:
static void HandleExampleBundle()
string resPath = AppDataPath + &/& + AppConst.AssetDir + &/&;
if (!Directory.Exists(resPath)) Directory.CreateDirectory(resPath);
//AddBuildMap(&prompt& + AppConst.ExtName, &*.prefab&, &Assets/LuaFramework/Examples/Builds/Prompt&);
//AddBuildMap(&message& + AppConst.ExtName, &*.prefab&, &Assets/LuaFramework/Examples/Builds/Message&);
//AddBuildMap(&prompt_asset& + AppConst.ExtName, &*.png&, &Assets/LuaFramework/Examples/Textures/Prompt&);
//AddBuildMap(&shared_asset& + AppConst.ExtName, &*.png&, &Assets/LuaFramework/Examples/Textures/Shared&);
string content = File.ReadAllText(Application.dataPath + &/AssetBundleInfo.csv&);
string[] contents = content.Split(new string[] { &\r\n& }, System.StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i & contents.L i++)
string[] a = contents[i].Split(',');
//UnityEngine.Debug.Log(a[0]); UnityEngine.Debug.Log(a[1]); UnityEngine.Debug.Log(a[2]);
AddBuildMap(a[0], a[1], a[2]);
NGUI版本:
NGUI版本有些不同,它使用的是4.x的打包方式,为了配合5.x的打包,需要修改一下:
static void HandleExampleBundle(BuildTarget target) {
Object mainAsset =
//主素材名,单个
Object[] addis =
//附加素材名,多个
string assetfile = string.E
//素材文件名
BuildAssetBundleOptions options = BuildAssetBundleOptions.UncompressedAssetBundle |
BuildAssetBundleOptions.CollectDependencies |
BuildAssetBundleOptions.DeterministicAssetB
string dataPath = Util.DataP
if (Directory.Exists(dataPath)) {
Directory.Delete(dataPath, true);
string assetPath = AppDataPath + &/StreamingAssets/&;
if (Directory.Exists(dataPath)) {
Directory.Delete(assetPath, true);
if (!Directory.Exists(assetPath)) Directory.CreateDirectory(assetPath);
/////-----------------------------生成共享的关联性素材绑定-------------------------------------
//BuildPipeline.PushAssetDependencies();
//assetfile = assetPath + &shared& + AppConst.ExtN
//mainAsset = LoadAsset(&Shared/Atlas/Dialog.prefab&);
//BuildPipeline.BuildAssetBundle(mainAsset, null, assetfile, options, target);
/////------------------------------生成PromptPanel素材绑定-----------------------------------
//BuildPipeline.PushAssetDependencies();
//mainAsset = LoadAsset(&Prompt/Prefabs/PromptPanel.prefab&);
//addis = new Object[1];
//addis[0] = LoadAsset(&Prompt/Prefabs/PromptItem.prefab&);
//assetfile = assetPath + &prompt& + AppConst.ExtN
//BuildPipeline.BuildAssetBundle(mainAsset, addis, assetfile, options, target);
//BuildPipeline.PopAssetDependencies();
/////------------------------------生成MessagePanel素材绑定-----------------------------------
//BuildPipeline.PushAssetDependencies();
//mainAsset = LoadAsset(&Message/Prefabs/MessagePanel.prefab&);
//assetfile = assetPath + &message& + AppConst.ExtN
//BuildPipeline.BuildAssetBundle(mainAsset, null, assetfile, options, target);
//BuildPipeline.PopAssetDependencies();
/////-------------------------------刷新---------------------------------------
//BuildPipeline.PopAssetDependencies();
//////////////////////////////////////////////////////////////////////////////
string content = File.ReadAllText(Application.dataPath + &/AssetBundleInfo.csv&);
string[] contents = content.Split(new string[] { &\r\n& }, System.StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i & contents.L i++)
string[] a = contents[i].Split(',');
//UnityEngine.Debug.Log(a[0]); UnityEngine.Debug.Log(a[1]); UnityEngine.Debug.Log(a[2]);
AddBuildMap(a[0], a[1], a[2]);
string resPath = &Assets/& + &StreamingAssets&;
BuildAssetBundleOptions option = BuildAssetBundleOptions.DeterministicAssetBundle |
BuildAssetBundleOptions.UncompressedAssetB
BuildPipeline.BuildAssetBundles(resPath, maps.ToArray(), option, target);
maps.Clear();
static List&AssetBundleBuild& maps = new List&AssetBundleBuild&();
static void AddBuildMap(string bundleName, string pattern, string path)
string[] files = Directory.GetFiles(path, pattern);
if (files.Length == 0)
for (int i = 0; i & files.L i++)
files[i] = files[i].Replace('\\', '/');
AssetBundleBuild build = new AssetBundleBuild();
build.assetBundleName = bundleN
build.assetNames =
maps.Add(build);
那么,每一次打包,先点击LuaFramework/AddBuildMapUtility,准备好AB包的信息,然后点击LuaFramework/Build xxx Resource来进行打包,在window平台下,检查Assets\StreamingAssets中的资源是否正确。还有最重要的一点,每次对lua文件或者其他资源更改后,都要点击菜单栏LuaFramework/Build xxx Resource来重新打包!
a.在Assets\LuaFramework\Lua下的Controller和View下,模仿编写lua
b.在CtrlManager、Game、define这三个lua文件中模仿添加修改东西
建立一个空物体,挂上Main脚本,在Canvas(UGUI版本的框架)下建一个空物体,赋予GuiCamera这个tag,将位置和宽高置0,然后拉伸宽高,然后运行,这样就可以了!
NGUI版本注意点:
1.打包运行后可能会提示FileNotFoundException: Could not find file &c:\luaframework\shared.unity3d&.这个错误,追踪错误到ResourceManager.cs中的initialize方法,如果AppConst.ExampleMode为true,则需要shared.unity3d这个AB包。因此,打包的时候需要把shared文件夹也选上哦。。
2.生成的面板会在GUI这个物体下,那么如何修改这个物体呢?找到GameManager.cs中的InitGui方法,修改一下即可。GUI这个预制体,可以在Project视图搜索即可。
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?

我要回帖

更多关于 unity asset bundle 的文章

 

随机推荐