unity提供了assetbunlde机制,下面介绍一种方法将指定目录下的所有文件打包成AssetBundle

先说明步骤,再上代码。

步骤一、选择要打包成assetbundle的目录,本案例使用assetbundle_raw

步骤二、把要打包的资源或者目录都放到assetbundle_raw目录,资源可以是

prefab,png,fbx,font,audio,txt等。

步骤三、给assetbundle_raw目录下所有的资源文件设置assetbundle名称,如果是目录,会递归。

名称格式:资源名称.资源后缀.unity3d,

如果有子目录,则资源名称为:子目录/子目录/.../子目录/资源名称.资源后缀.unity3d

在给这些资源设置assetbundle名称的时候会把该资源所依赖的所有资源都设置上

assetbundle名称。编辑器脚本已经写好,稍后附上,这一步你只需要点击

Tools->AssetBundle->Set Asset Bundle Names就可以。

步骤四、选择assetbundle输出目录,本案例使用StreamingAssets目录。只所以要使用这个目录,主要

是考虑到本地测试会比较方便,打包好的assetbundle肯定需要进行一下测试,没问题后再放到

资源服务器上,另外就是可以把StreamingAssets目录作为本地资源测试服务器,还可以打包到

手机设备上进行测试。操作:Tools->AssetBundle->Build Bundles。

步骤五、生成资源版本文件。步骤四执行完毕后,assetbundle已经生成,另外还会生成Manifest文件,

因为assetbundle和平台相关,以android平台为例,会生成android和android.manifest文件,

我们需要根据android文件获取每个bundle的hash值,生成版本文件,用于热更新。废话不多

说,操作:Tools->AssetBundle->Generate Resource Version File。

至此,assetbundle打包完成。

特别需要注意:

放到assetbundle_raw目录下的资源,互相之间不要有任何依赖关系,否则,在步骤三设置名称的阶段,被依赖的资源就会被设置两次或者多次assetbundle名称,这样它只能使用最后设置的名称。如果是这样的话,在加载assetbundle的时候,就可能出现已经加载的assetbundle被再次加载而报错。因为被加载的assetbundle在被释放前不能再次加载。所以,放到assetbundle_raw目录下的资源,互相之间不要有任何依赖关系;放到assetbundle_raw目录下的资源,互相之间不要有任何依赖关系;放到assetbundle_raw目录下的资源,互相之间不要有任何依赖关系。重要的话说三遍。

另外需要注意的地方,在前面的文章中也提到了。

  1. 要打包的资源名称不要有空格,空格在pc上支持,在android上不支持

  2. 名称用小写,下划线,数字,尽量不要用大写,因为unity打包成assetbundle后的资源名称都是小写

  3. 建议unity所有的资源命名的时候用小写,下划线,数字,尽量不要用大写

  4. 如果用到一些插件,例如NGUI等,里面的资源,如,shader文件名称中间是有空格的,它会作为依赖资源打包成assetbundle,这样的手机上加载就可能出错。

编辑器代码:

using UnityEngine;

using System.Collections;

using UnityEditor;

using System.IO;

using System;

using System.Collections.Generic;

using System.Text;

using LitJson;

public class Builder : Editor

{

public static string sourcePath = Application.dataPath + "/assetbundle_raw";

const string AssetBundlesOutputPath = "Assets/StreamingAssets";

static string m_assetPath = Application.streamingAssetsPath;

static string assetTail = ".unity3d";

static bool canFinish = false;

//生成的bundle的相对路径列表

static List<string> bundleRelativePaths = new List<string>();

[MenuItem("Tools/AssetBundle/Set Asset Bundle Names")]

public static void SetBundleNames()

{

ClearAssetBundlesName();

bundleRelativePaths.Clear();

Pack(sourcePath);

Debug.Log("Bundles 名称设置完成");

}

[MenuItem("Tools/AssetBundle/Build Bundles")]

public static void BuildAssetBundle()

{

string outputPath = Path.Combine(AssetBundlesOutputPath, Platform.GetPlatformFolder(EditorUserBuildSettings.activeBuildTarget));

if (!Directory.Exists(outputPath))

{

Directory.CreateDirectory(outputPath);

}

//根据BuildSetting里面所激活的平台进行打包

BuildPipeline.BuildAssetBundles(outputPath, 0, EditorUserBuildSettings.activeBuildTarget);

Debug.Log("打包完成");

AssetDatabase.Refresh();

}

[MenuItem("Tools/AssetBundle/Generate Resource Version File")]

public static void GenerateVersionFile()

{

//生成配置文件

GenerateCfgFile();

EditorCoroutineRunner.StartEditorCoroutine(wait());

Debug.Log("成功生成资源版本文件");

AssetDatabase.Refresh();

}

static IEnumerator wait()

{

Debug.Log("wait");

while (!canFinish)

yield return null;

}

/// <summary>

/// 生成资源配置文件resource_version

/// </summary>

static void GenerateCfgFile()

{

Debug.Log("GenerateCfgFile");

getManifest();

}

/// <summary>

/// 清除之前设置过的AssetBundleName,避免产生不必要的资源也打包

/// 之前说过,只要设置了AssetBundleName的,都会进行打包,不论在什么目录下

/// </summary>

static void ClearAssetBundlesName()

{

string[] bundleNames = AssetDatabase.GetAllAssetBundleNames();

int length = bundleNames.Length;

Debug.Log(length);

string[] oldAssetBundleNames = new string[length];

for (int j = 0; j < bundleNames.Length; j++)

{

AssetDatabase.RemoveAssetBundleName(bundleNames[j], true);

}

length = AssetDatabase.GetAllAssetBundleNames().Length;

Debug.Log(length);

}

static void Pack(string source)

{

DirectoryInfo folder = new DirectoryInfo(source);

FileSystemInfo[] files = folder.GetFileSystemInfos();

int length = files.Length;

for (int i = 0; i < length; i++)

{

if (files[i] is DirectoryInfo)

{

Pack(files[i].FullName);

}

else

{

if (!files[i].Name.EndsWith(".meta"))

{

file(files[i].FullName);

Debug.Log("files[i].FullName is " + files[i].FullName);

}

}

}

}

static void file(string source)

{

string _source = Replace(source);

string _assetPath = "Assets" + _source.Substring(Application.dataPath.Length);

string _assetPath2 = _source.Substring(Application.dataPath.Length + 1);

Debug.Log("_assetPath is " + _assetPath);

Debug.Log("_assetPath2 is " + _assetPath2);

//在代码中给资源设置AssetBundleName

AssetImporter assetImporter = AssetImporter.GetAtPath(_assetPath);

string assetName = _assetPath2.Substring(_assetPath2.IndexOf("/") + 1);

//assetName = assetName.Replace(Path.GetExtension(assetName), ".unity3d");

assetName = assetName + ".unity3d";

assetImporter.assetBundleName = assetName;

fileDependences(_assetPath);

Debug.Log("assetName is " + assetName);

//保存bundle的相对路径

if (!bundleRelativePaths.Contains(assetName))

bundleRelativePaths.Add(assetName);

}

static string Replace(string s)

{

return s.Replace("\\", "/");

}

static void fileDependences(string path)

{

try

{

//string path = AssetDatabase.GetAssetPath(0);

Debug.Log("path is " + path);

string[] deps = AssetDatabase.GetDependencies(path);

int counter = 0;

for (int i = 0; i < deps.Length; i++)

{

if (deps[i].Equals(path) || deps[i].EndsWith(".cs"))

continue;

++counter;

}

if (counter == 0)

return;

for (int i = 0; i < deps.Length; i++)

{

Debug.Log("deps " + i + " is " + deps[i]);

if (deps[i].Equals(path) || deps[i].EndsWith(".cs"))

continue;

AssetImporter ai = AssetImporter.GetAtPath(deps[i]);

string assetName = deps[i] + ".unity3d";

assetName = assetName.Substring(assetName.IndexOf("/") + 1);

Debug.Log("assetName is " + assetName);

ai.assetBundleName = assetName;

//保存bundle的相对路径

if (!bundleRelativePaths.Contains(assetName))

bundleRelativePaths.Add(assetName);

fileDependences(deps[i]);

}

}

catch (Exception error)

{

Debug.Log("error is " + error);

}

}

#region LoadAssetBundle

/// <summary>

/// 加载目标资源

/// </summary>

/// <param name="name"></param>

/// <param name="callback"></param>

public static void LoadAssetBundle(string name, Action<UnityEngine.Object> callback)

{

name = name + assetTail;//eg:ui/panel.unity3d

Action<List<AssetBundle>> action = (depenceAssetBundles) =>

{

string realName = GetRuntimePlatform() + "/" + name;//eg:Windows/ui/panel.unity3d

Debug.Log("realName is " + realName);

LoadResReturnWWW(realName, (www) =>

{

int index = realName.LastIndexOf("/");

string assetName = realName.Substring(index + 1);

assetName = assetName.Replace(assetTail, "");

AssetBundle assetBundle = www.assetBundle;

UnityEngine.Object obj = assetBundle.LoadAsset(assetName);//LoadAsset(name),这个name没有后缀,eg:panel

//卸载资源内存

assetBundle.Unload(false);

for (int i = 0; i < depenceAssetBundles.Count; i++)

{

depenceAssetBundles[i].Unload(false);

}

//加载目标资源完成的回调

callback(obj);

});

};

LoadDependenceAssets(name, action);

}

static void writeCfgFile(AssetBundleManifest manifest)

{

if (null == manifest)

return;

StringBuilder sb = new StringBuilder();

JsonWriter js = new JsonWriter(sb);

try

{

js.WriteObjectStart();

js.WritePropertyName("id");

js.Write(0);

js.WritePropertyName("version");

js.Write("1.0");

string platform = Platform.GetPlatformFolder(EditorUserBuildSettings.activeBuildTarget);

js.WritePropertyName("manifest");

js.Write(platform);

js.WritePropertyName("resource");

string[] bundleNames = AssetDatabase.GetAllAssetBundleNames();

js.WriteObjectStart();

foreach (string path in bundleNames)

{

Hash128 hash = manifest.GetAssetBundleHash(path);

//if (hash.isValid)

{

js.WritePropertyName(path);

js.Write(hash.ToString());

}

}

js.WriteObjectEnd();

js.WriteObjectEnd();

}

catch (Exception error)

{

Debug.Log("Write json error : " + error.Message);

}

string strVersion = sb.ToString().ToLower();

try

{

string platform = GetRuntimePlatform();

File.WriteAllText(AssetBundlesOutputPath + "/" + platform + "/resource_version", strVersion);

}

catch (Exception error)

{

Debug.Log("Write Cfg file error : " + error.Message);

}

canFinish = true;

}

/// <summary>

/// 获取总manifest

/// </summary>

static void getManifest()

{

Action<AssetBundleManifest> dependenceAction = (manifest) =>

{

writeCfgFile(manifest);

};

LoadAssetBundleManifest(dependenceAction);

}

/// <summary>

/// 加载目标资源的依赖资源

/// </summary>

/// <param name="targetAssetName"></param>

/// <param name="action"></param>

private static void LoadDependenceAssets(string targetAssetName, Action<List<AssetBundle>> action)

{

Debug.Log("要加载的目标资源:" + targetAssetName);//ui/panel.unity3d

Action<AssetBundleManifest> dependenceAction = (manifest) =>

{

List<AssetBundle> depenceAssetBundles = new List<AssetBundle>();//用来存放加载出来的依赖资源的AssetBundle

string[] dependences = manifest.GetAllDependencies(targetAssetName);

//获取hash值

Hash128 hash = manifest.GetAssetBundleHash(targetAssetName);

Debug.Log(targetAssetName + " hash is " + hash);

Debug.Log("依赖文件个数:" + dependences.Length);

int length = dependences.Length;

int finishedCount = 0;

if (length == 0)

{

//没有依赖

action(depenceAssetBundles);

}

else

{

//有依赖,加载所有依赖资源

for (int i = 0; i < length; i++)

{

string dependenceAssetName = dependences[i];

dependenceAssetName = GetRuntimePlatform() + "/" + dependenceAssetName;//eg:Windows/altas/heroiconatlas.unity3d

//加载,加到assetpool

LoadResReturnWWW(dependenceAssetName, (www) =>

{

int index = dependenceAssetName.LastIndexOf("/");

string assetName = dependenceAssetName.Substring(index + 1);

assetName = assetName.Replace(assetTail, "");

AssetBundle assetBundle = www.assetBundle;

UnityEngine.Object obj = assetBundle.LoadAsset(assetName);

//assetBundle.Unload(false);

depenceAssetBundles.Add(assetBundle);

finishedCount++;

if (finishedCount == length)

{

//依赖都加载完了

action(depenceAssetBundles);

}

});

}

}

};

LoadAssetBundleManifest(dependenceAction);

}

/// <summary>

/// 加载AssetBundleManifest

/// </summary>

/// <param name="action"></param>

private static void LoadAssetBundleManifest(Action<AssetBundleManifest> action)

{

string manifestName = GetRuntimePlatform();

Debug.Log("Application.platform is " + Application.platform);

manifestName = manifestName + "/" + manifestName;//eg:Windows/Windows

Debug.Log("manifestName is " + manifestName);

LoadResReturnWWW(manifestName, (www) =>

{

AssetBundle assetBundle = www.assetBundle;

UnityEngine.Object obj = assetBundle.LoadAsset("AssetBundleManifest");

assetBundle.Unload(false);

AssetBundleManifest manif = obj as AssetBundleManifest;

Debug.Log("(www) " + manif.name);

action(manif);

});

}

#endregion

#region ExcuteLoader

public static void LoadResReturnWWW(string name, Action<WWW> callback)

{

string path = "file://" + m_assetPath + "/" + name;

Debug.Log("m_assetPath is " + m_assetPath);

Debug.Log("name is " + name);

Debug.Log("加载:" + path);

EditorCoroutineRunner.StartEditorCoroutine(LoaderRes(path, callback));

}

static IEnumerator LoaderRes(string path, Action<WWW> callback)

{

WWW www = new WWW(path);

yield return www;

callback(www);

}

#endregion

#region Util

/// <summary>

/// 平台对应文件夹

/// </summary>

/// <returns></returns>

private static string GetRuntimePlatform()

{

string platform = "";

if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor)

{

//platform = "Windows";

platform = "android";

}

else if (Application.platform == RuntimePlatform.Android)

{

platform = "android";

}

else if (Application.platform == RuntimePlatform.IPhonePlayer)

{

platform = "ios";

}

else if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor)

{

platform = "osx";

}

return platform;

}

#endregion

}

public class Platform

{

public static string GetPlatformFolder(BuildTarget target)

{

switch (target)

{

case BuildTarget.Android:

return "android";

case BuildTarget.iOS:

return "ios";

case BuildTarget.WebPlayer:

return "webplayer";

case BuildTarget.StandaloneWindows:

case BuildTarget.StandaloneWindows64:

return "windows";

case BuildTarget.StandaloneOSXIntel:

case BuildTarget.StandaloneOSXIntel64:

case BuildTarget.StandaloneOSXUniversal:

return "osx";

default:

return null;

}

}

}

用到了一个工具类,这是一个在编辑器下可运行的协程类,我也是从网上找的

using UnityEngine;

using UnityEditor;

using System.Collections;

using System.Collections.Generic;

using System.Runtime.CompilerServices;

public static class EditorCoroutineRunner

{

private class EditorCoroutine : IEnumerator

{

private Stack<IEnumerator> executionStack;

public EditorCoroutine(IEnumerator iterator)

{

this.executionStack = new Stack<IEnumerator>();

this.executionStack.Push(iterator);

}

public bool MoveNext()

{

IEnumerator i = this.executionStack.Peek();

if (i.MoveNext())

{

object result = i.Current;

if (result != null && result is IEnumerator)

{

this.executionStack.Push((IEnumerator)result);

}

return true;

}

else

{

if (this.executionStack.Count > 1)

{

this.executionStack.Pop();

return true;

}

}

return false;

}

public void Reset()

{

throw new System.NotSupportedException("This Operation Is Not Supported.");

}

public object Current

{

get { return this.executionStack.Peek().Current; }

}

public bool Find(IEnumerator iterator)

{

return this.executionStack.Contains(iterator);

}

}

private static List<EditorCoroutine> editorCoroutineList;

private static List<IEnumerator> buffer;

public static IEnumerator StartEditorCoroutine(IEnumerator iterator)

{

if (editorCoroutineList == null)

{

// test

editorCoroutineList = new List<EditorCoroutine>();

}

if (buffer == null)

{

buffer = new List<IEnumerator>();

}

if (editorCoroutineList.Count == 0)

{

EditorApplication.update += Update;

}

// add iterator to buffer first

buffer.Add(iterator);

return iterator;

}

private static bool Find(IEnumerator iterator)

{

// If this iterator is already added

// Then ignore it this time

foreach (EditorCoroutine editorCoroutine in editorCoroutineList)

{

if (editorCoroutine.Find(iterator))

{

return true;

}

}

return false;

}

private static void Update()

{

// EditorCoroutine execution may append new iterators to buffer

// Therefore we should run EditorCoroutine first

editorCoroutineList.RemoveAll

(

coroutine => { return coroutine.MoveNext() == false; }

);

// If we have iterators in buffer

if (buffer.Count > 0)

{

foreach (IEnumerator iterator in buffer)

{

// If this iterators not exists

if (!Find(iterator))

{

// Added this as new EditorCoroutine

editorCoroutineList.Add(new EditorCoroutine(iterator));

}

}

// Clear buffer

buffer.Clear();

}

// If we have no running EditorCoroutine

// Stop calling update anymore

if (editorCoroutineList.Count == 0)

{

EditorApplication.update -= Update;

}

}

}

后面我会分享热更新策略,用到了上面生成的资源版本文件。

以上是我用assetbundle打包的使用案例,本人能力有限,有错误和不足的地方,还请不吝赐教,万分感激!

转载于:https://blog.51cto.com/chenshuhb/1836562

unity 打包AssetBundle相关推荐

  1. 实力封装:Unity打包AssetBundle(大结局)

    →→前情提要:让用户选择要打包的文件←← 大结局:更多选择 Unity打包AssetBundle从入门到放弃系列终于要迎来大结局了[小哥哥表示实在写不动了o(╥﹏╥)o]... 经过上一次的教程,其实 ...

  2. Unity打包AssetBundle自动分析资源依赖关系(包括UGUI图集打包)

    https://blog.csdn.net/u012740992/article/details/79371986 怎么分析资源的依赖关系呢,并设置AssetBundleName呢? 我们检测资源之间 ...

  3. 使用Unity打包Assetbundle填坑记录(随时更新)

    Unity版本=2017.4.13f1 问题1: Cannot mark assets and scenes in one AssetBundle 出现原因:使用Unity 打包场景文件为AssetB ...

  4. 实力封装:Unity打包AssetBundle(二)

    →前情提要:Unity最基本的AssetBundle打包方式. 第二种打包方式 Unity提供的BuildAssetBundles API还有一个重载形式,看下面↓↓ public static As ...

  5. Unity5.x 依赖关系打包 AssetBundle 研究

    Unity5.x新依赖打包及加载 https://blog.csdn.net/strugglebydreamlin/article/details/78031086 demo:https://pan. ...

  6. Unity PIC 打包assetBundle报错

    Unity PIC 打包assetBundle报错 修改平台设置,讲LitJson 从android 目录移出来,重启unity.就可以读取到引用关系了.

  7. [FairyGUI][Unity]FGUI资源打包AssetBundle

    参考资料3 将发布后的文件打包为两个AssetBundle,即定义文件和资源各打包为一个bundle(desc_bundle+res_bundle).这样做的好处是一般UI的更新都是修改元件位置什么的 ...

  8. Unity资源管理——AssetBundle构建/打包

    1.为资源设置 assetBundleName 和 assetBundleVariant. 可以在资源的 Inspector 上手动设置,也可以通过 AssetImporter 进行设置. Asset ...

  9. 【小松教你手游开发】【unity系统模块开发】Unity5.5.2UI打包AssetBundle

    之前已经有几篇文章写打包AssetBundle,但毕竟没有实际在项目中写过都写的比较浅. 刚好最近项目更新Unity5.5.2就顺便由我来更新ui打包流程 这里就把这次的经验写一下 这里还是稍微解释一 ...

最新文章

  1. SAP 企业管理软件与解决方案 产品简介
  2. whereis, which, locate的区别
  3. 第九届蓝桥杯省赛JavaC组真题——详细答案对照(完整版)
  4. java学习(21):移位运算符
  5. STM32之ADC单通道连续例程
  6. [Go] 通过 17 个简短代码片段,切底弄懂 channel 基础
  7. python之路 -- 并发编程之进程
  8. python气象绘图速成_气象数据可视化——利用Python绘制温度平流
  9. g40-45支持虚拟化技术_虚拟化技术与原理简介
  10. linux grub.cnf grub64.efi 文件
  11. python给图片加边框,照片加边框,照片加描边,图片加描边,批量给图片加描边
  12. 吐血推荐:无解的完成图
  13. kirin710f是什么处理器_华为kirin710f处理器相当于骁龙几
  14. javascript中获取非行间样式的方法
  15. flash崩溃未保存!
  16. 从 LoG 到 DoG 再到 XDoG, FDoG
  17. 麻将牌技法--收藏慢慢学
  18. 路由声明式传参和编程式传参
  19. 如何在Arch Linux搭建高效便捷的平铺式桌面
  20. 机器学习算法 03 —— 逻辑回归算法(精确率和召回率、ROC曲线和AUC指标、过采样和欠采样)

热门文章

  1. Tips--Multisim中压电传感器与电荷源的替代方案
  2. VMware关闭虚拟机系统后不见了
  3. java求最后一位不为0的数字_【Java】 剑指offer(62) 圆圈中最后剩下的数字
  4. linux网卡IP同一网段,Linux下多网卡不同IP在同一网段的情况
  5. 安卓新发布机制----app bundle
  6. 开源MSSQL Express Profile 文件
  7. tensorflow学习笔记一:安装调试
  8. Ubuntu ./configure 半途终止 导致没有生成makefile文件 解决方法
  9. leveldb - 并发写入处理
  10. JS 防止表单重复提交