unity 打包原理学习

原文链接:https://zhuanlan.zhihu.com/p/38122862

一:AssetBundle介绍

AssetBundle是将资源使用unity提供的一种用于存储的压缩格式打包后的集合,它可以存储任何一种untiy可以识别的资源,
一般情况下AssetBundle的具体开发流程如下:

  • 创建AssetBundle,开发者在unity编辑器中通过脚本所需要的资源打包成AssetBundle文件
  • 上传服务器。开发者将打包好的AssetBundle文件上传至服务器中。使得游戏客户端能够获取当前的资源,进行游戏的更新
  • 下载AssetBundle,首先将其下载到本地设备中,然后通过AssetBundle的加载模块将资源加到游戏中
  • 加载,通过untiy提供的API可以加载资源里面包含的资源来更新客户端
  • 卸载AssetBundle,卸载之后可以节省内存资源,并且要保证资源的正常更新

二:AssetBundle多平台打包

2.1创建AssetBundle
(1)只有在Asset窗口中的资源才可以打包,我们单击GameObject->Cube,然后在Asset窗口创建一个预设体,命名为cubeasset,讲Cube拖到该预设体上。

(2)单击刚创建的预制件cubeasset,在编辑器界面右下角的属性窗口底部有一个名为”AssetBundle”的创建工具。接下来创建即可,空的可以通过单击菜单选项”New…”来创建,将其命名为”cubebundle”,名称固定为小写,如果使用了大写字母之后,系统会自动转换为小写格式。

2.2打包AssetBundle
AssetBundle创建之后需要导出,这一个过程就需要编写相应的代码实现,从unity5.x之后,提供了一套全新简单的API来实现打包功能。大大简化了开发者手抖遍历资源自行打包的过程,更加方便快捷。需要在Asset目录下创建Editor目录,表示该脚本是对于编辑器的一个扩展。脚本写完之后,也不需要进行挂载,会自动在unity的菜单栏中生成。点击子菜单,既可以进行打包AssetBundle。具体代码如下

using UnityEditor;
public class ExportAssets : MonoBehaviour {

	[@MenuItem("Test/Build Asset Bundles")]
	static void BuildAssetBundles(){

		BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath,
												 	 BuildAssetBundleOptions.UncompressedAssetBundle,
													 BuildTarget.StandaloneOSXUniversal);
	}
}

所有的AssetBundle已经被导出,此时每一个AssetBundle资源会有一个和文件相关的Mainfest的文本类型的文件,该文件提供了所打包的资源的CRC和资源依赖信息
除此之外,还有一个AssetBundle文件会在生成的时候被创建,记录整个资源列表以及列表之间的关系
2.3AssetBundle的压缩类型
untiy引擎为我们提供了三种压缩策略来处理AssetBundle的压缩

  • LZMA
  • LZ4
  • 不压缩

**LZMA格式:**默认情况下,打包生成的AssetBundle都会被压缩。在u3d中,AssetBundle的标准压缩格式便是LZMA(一种序列化流文件)。因此默认情况下,打出的AssetBundle包处于LZMA格式的压缩状态,在使用AssetBundle前需要解压缩。
使用LZMA格式压缩的AssetBundle的包体积最小,但是相应的会增加压缩时的时间
**LZ4:**unity5.3之后的版本增加了LZ4格式压缩, 由于LZ4压缩比一般,因此经过压缩后的AssetBundle包体的体积比较大,但是LZ4格式的好处在于解压时间相对短
若要使用LZ4格式压缩,只需要在打包的时候开启

BuildAssetBundleOptions.ChunkBasedCompression即可。
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath,
BuildAssetBundleOptions.ChunkBasedCompression);

**不压缩:**当然,我们也可以不对AssetBundle进行压缩,没有经过压缩的包体积最大,但是访问速度最快。若要使用不压缩策略,只要在打包的时候开启

BuildAssetBundleOptions.UncompressedAssetBundle即可。
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath,
BuildAssetBundleOptions.UncompressedAssetBundle);

static void BuildAssetBundlesAndroid(){
		Object obj = AssetDatabase.LoadMainAssetAtPath("Assets/Test.png");
		BuildPipeline.BuildAssetBundle(obj, null,
		                               Application.streamingAssetsPath + "/Test.assetbundle",
		         BuildAssetBundleOptions.CollectDependencies |        BuildAssetBundleOptions.CompleteAssets
		        | BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.StandaloneWindows);
	}

三:AssetBundle资源加载和卸载

3.1AssetBundle加载
在5.3版本中的新AssetBundle系统中,旧有的一些动态加载API已经被新的API所取代,具体内容如下
4.x-5.2版本中的AssetBundle.CreateFromFile方法,变成了AssetBundle.LoadFromFile
4.x-5.2版本中的AssetBundle.CreateFromMemory,变成AssetBundle.LoadFromMemoryAsync方法
4.x-5.2版本中AssetBundle.CreateFromMemoryImmediate,变成AssetBundle.LoadFromMemory
因此我们学习的内容都是以新的为准
使用AssetBundle动态加载资源首先要获取AssetBundle对象,第二步才是从AssetBundle中加载目标资源。
因此我们要关注如何在运行的时候获取AssetBundle的对象
要在运行时加载AssetBundle对象主要可以分为俩个途径

  • 先获取www对象,再通过www.assetBundle获取AssetBundle对象
  • 直接获取AssetBundle

到此没找特别好的材料 等后续找到好的资料,再补充这块

3.2AssetBundle内部资源加载
新版的AssetBundle中,加载资源的API已经变成了一下的几个:
- LoadAsset:从资源包中加载指定的资源
- LoadAllAsset:加载当前资源包中所有的资源
- LoadAssetAsync:从资源包中异步加载资源

	Texture mat = (Texture)data.assetBundle.LoadAsset ("1");
	GetComponent<MeshRenderer> ().material.mainTexture = mat;
	data.assetBundle.Unload (false);
	//2同步加载所有的GameObject类型
	GameObject[] obj = data.assetBundle.LoadAllAssets<GameObject> ();
	//3Async加载,根据名称进行加载
	AssetBundleRequest req= data.assetBundle.LoadAssetAsync("1");
	yield return req;
	if (req.isDone) {
		Texture tex = (Texture)req.asset;
	}
	//4 LoadAllAssets的yibu版本
	AssetBundleRequest req1=data.assetBundle.LoadAllAssetsAsync
		<GameObject>();

从AssetBundle加载资源的常用API

  • public Object LoadAsset(string name,Type type);
    通过给定的名字和资源类型,加载资源。加载是会自动加载其依赖的资源,即Load一个Prefab时,会自动Load其引用的Texture资源
  • public Object[] LoadAllAsset(Type type);
    一次性加载Bundle中给定资源的所有资源
  • public AssetBundleRequest LoadAssetAsync(string name,Type type);
    该接口时Load的异步版本
    资源卸载
    资源卸载部分的变化不大,使用的仍然是Unload方法。
    该方法会卸载运行时内存中包含的bundle中的所有资源
    当传入参数为true,则不仅仅内存中的AssetBundle对象包含的资源会被销毁,根据这些资源实例化而来的游戏内对象也会销毁
    当传入false,则仅仅销毁内存中的AssetBundle对象包含的资源

四:AssetBundle服务器下载

我们采用下面的案例,场景进入的时候,依次从服务器给三个已经创建的对象加载纹理,材质,以及根据预设创建一个新的对象。
服务器我们简单的使用python进行搭建,进入到存放asset资源目录下,输入以下命令就可以搭建一个简单的文件服务器:
python -m SimpleHTTPServer 8080
浏览器输入 http://127.0.0.1:8080/ 可以查看搭建的情况。
具体过程如下:

(1)新建一个场景,创建立方体,球体和一个空对象,分别用来测试下载纹理,材质和预设体。

(2)分别将材质和纹理图片,预设体创建成为AssetBundle资源,具体的命名自己把握,后来需要根据名称进行获取。

(3)打包成功之后,将内容添加到对应的服务器之中,下面开始脚本的编写。

(4)新建脚本如下,分别测试三个内容的下载。

public class DownloadAsset : MonoBehaviour {
public GameObject goCube; //演示修改纹理
public GameObject goSphere;//演示修改材质
public Transform newPosition;//演示根据预设体创建对象
//url=IP+文件名
private string url1=“http://127.0.0.1:8080/image”;
private string url2=“http://127.0.0.1:8080/mater”;
private string url3=“http://127.0.0.1:8080/cubebundle”;
// Use this for initialization
void Start () {
//downTexture ();
downMat ();
//downPrefab ();
}
void downTexture()
{
StartCoroutine (download_Texture(url1));
}
IEnumerator download_Texture(string url){
WWW downAsset = new WWW (url);
yield return downAsset;
goCube.GetComponent ().material.mainTexture
= (Texture)downAsset.assetBundle.LoadAsset (“01”);
downAsset.assetBundle.Unload (false);
}

void downMat(){
	StartCoroutine (download_Mat(url2));
}
IEnumerator download_Mat(string url){
	WWW downAsset = new WWW (url);
	yield return downAsset;
	goCube.GetComponent<Renderer> ().material
		= (Material)downAsset.assetBundle.LoadAsset 
		("Red");
	downAsset.assetBundle.Unload (false);
}
void downPrefab(){
	StartCoroutine (download_Prefab(url3));
}
IEnumerator download_Prefab(string path){
	WWW downloadAsset = new WWW (path);
	yield return downloadAsset;

	GameObject gpPrefabs = (GameObject)Instantiate
		(downloadAsset.assetBundle.LoadAsset("Cube"));
	gpPrefabs.GetComponent<Renderer> ().material.color = 
		Color.yellow;
	gpPrefabs.transform.position =
		newPosition.transform.position;
	downloadAsset.assetBundle.Unload (false);
	downloadAsset.Dispose ();

当然,我们这里也可以使用异步加载的方式加载AssetBundle的资源,如下所示:

	AssetBundle bundle = downloadAsset.assetBundle;
	AssetBundleRequest request = bundle.LoadAssetAsync 
		("Cube",typeof(GameObject));
	yield return request;

	GameObject gpPrefabs = (GameObject)Instantiate
		(request.asset);
	gpPrefabs.GetComponent<Renderer> ().material.color = Color.yellow;
	gpPrefabs.transform.position =newPosition.transform.position;
	downloadAsset.assetBundle.Unload (false);
	downloadAsset.Dispose ();

五:AssetBundle原理分析

在AssetBundle的下载和加载过程中,以及Assets加载和实例化过程中,AssetBundle以及加载的Assets都会占用内存。
(1)AssetBundle的卸载采用Assetbundle.Unload(bool)接口。

(2)Assets的卸载有两种方式:
①.Assetbundle.Unload(true)。这会强制卸载掉所有从AssetBundle加载的Assets。

②.Resource.UnloadUnusedAssets()和 Resources.UnloadAsset。这会卸载掉所有没有用到的Assets。需要注意的是,该接口作用于整个系统,而不仅仅是当前的AssetBundle,而且不会卸载从当前AssetBundle文件中加载并仍在使用的Assets。
(3)对于实例化出来的对象,可以使用GameObject.Destroy或GameObject.DestroyImmediate。注意的是:官方说法是这样的,如果使用GameObject.Destroy接口,unity会将真正的删除操作延后到一个合适的时机统一进行处理,但会在渲染之前。
WW对象和WWW.asssetbundle加载的AssetBundle对象都会对Web Stream数据持有引用。AssetBundle对象同时也会引用到从它加载的所有Assets。按照官方说法,真正的数据都是存放在Web Stream数据中(如纹理、模型),而WWW和AssetBundle对象只是一个结构指向了Web Stream数据。

对于WWW对象,可以使用www=null或www.dispose来卸载。这两者是有区别的,www=null不会立即释放内存,而是系统的自动回收机制启动时回收。www.dispose则会立即调用系统的回收机制来释放内存。当WWW对象被释放后,其对于Web Stream数据的引用计数也会相应减1。

对于Web Stream数据,它所占用的内存会在其引用计数为0时,被系统自动回收。例如:当上图中的AssetBundle对象和WWW对象被释放后,Web Stream数据所占内存也会被系统自动回收。

六:AssetBundle依赖加载

如果一个或者多个 UnityEngine.Objects 引用了其他 AssetBundle 中的 UnityEngine.Object,那么 AssetBundle 之间就产生的依赖关系。相反,如果 UnityEngine.ObjectA 所引用的UnityEngine.ObjectB 不是其他 AssetBundle 中的,那么依赖就不会产生。

假若这样(指的是前面两个例子的后者,既不产生依赖的情况),被依赖对象(UnityEngine.ObjectB)将被拷贝进你创建的 AssetBundle(指包含 UnityEngine.ObjectA 的 AssetBundle)。

更进一步,如果有多个对象(UnityEngine.ObjectA1、UnityEngine.ObjectA2、UnityEngine.ObjectA3…)引用了同一个被依赖对象(UnityEngine.ObjectB),那么被依赖对象将被拷贝多份,打包进各个对象各自的 AssetBundle。

如果一个 AssetBundle 存在依赖性,那么要注意的是,那些包含了被依赖对象的 AssetBundles,需要在你想要实例化的对象的加载之前加载。Unity 不会自动帮你加载这些依赖。

想想看下面的例子, Bundle1 中的一个材质(Material)引用了 Bundle2 中的一个纹理(Texture):

在这个例子中,在从 Bundle1 中加载材质前,你需要先将 Bundle2 加载到内存中。你按照什么顺序加载 Bundle1 和 Bundle2 并不重要,重要的是,想从 Bundle1 中加载材质前,你需要先加载 Bundle2。

(1)AssetBundle.LoadFromMemoryAsync

这个方法的参数是一个包含了 AssetBundle 数据的字节数组。如果需要的话,你还可以传入一个 CRC(循环冗余校验码) 参数。如果 AssetBundle 使用 LZMA 算法压缩,那么 AssetBundle 在加载的时候会被解压。如果 AssetBundle 使用 LZ4 算法压缩,它将直接以压缩形式被加载。

IEnumerator LoadFromMemoryAsync(string path)
{
AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
yield return createRequest;
AssetBundle bundle = createRequest.assetBundle;
var prefab = bundle.LoadAsset.(“MyObject”);
Instantiate(prefab);
}
AssetBundle.LoadFromFile

这个 API 在加载本地存储的未压缩 AssetBundle 时具有很高效率。如果 AssetBundle 是未压缩,或者是数据块形式(LZ4 算法压缩)的,LoadFromFile 将从磁盘中直接加载它。如果 AssetBundle 是高度压缩(LZMA 算法压缩)的,在将它加载进入内存前,会首先将它解压。

下面是一个如何使用这个方法的例子:

public class LoadFromFileExample extends MonoBehaviour
{
function Start() {
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, “myassetBundle”));
if (myLoadedAssetBundle == null) {
Debug.Log(“Failed to load AssetBundle!”);
return;
}
var prefab = myLoadedAssetBundle.LoadAsset.(“MyObject”);
Instantiate(prefab);
}
}
注意:在安卓设备上,如果 Unity 是5.3或者更老的版本,这个方法在读取资源流路径(Streaming Assets path)的时候会失败。这是因为那个路径是在一个 .jar 文件的内部。Unity5.4 以及更高的版本没有这个问题,可以正常的读取资源流。

WWW.LoadFromCacheOrDownload

这个 API 已经被废弃(建议使用 UnityWebRequest)(三思:这句话不是我加的,官方文档中就是有这句话)

这个 API 对于从远程服务器加载 AssetBundles,或者加载本地 AssetBundles 都很有用。这个 API 是 UnityWebRequest 不尽如人意的老版本。

从远程服务器加载的 AssetBundle 将会被自动缓存。如果 AssetBundle 是压缩形式的,一个工作线程将加速解压这个 AssetBundle 并写入缓存。一旦一个 AssetBundle 已经被解压且被缓存,它将完全像使用 AssetBundle.LoadFromFile 方法一样被加载。

下面是一个如何使用这个方法的例子:

using UnityEngine;
using System.Collections;

public class LoadFromCacheOrDownloadExample : MonoBehaviour
{
IEnumerator Start ()
{
while (!Caching.ready)
yield return null;

    var www = WWW.LoadFromCacheOrDownload("http://myserver.com/myassetBundle", 5);
    yield return www;
    if(!string.IsNullOrEmpty(www.error))
    {
        Debug.Log(www.error);
        yield return;
    }
    var myLoadedAssetBundle = www.assetBundle;

    var asset = myLoadedAssetBundle.mainAsset;
}

}
由于缓存 AssetBundle 字节数据的开销较大,建议所有开发者在使用 WWW.LoadFromCacheOrDownload 方法时,确保 AssetBundles 都比较小——最多几兆字节。同样建议所有开发者在内存比较有限的平台(比如移动设备)上使用这个方法时,确保同时只下载一个 AssetBundle,防止内存泄漏。

如果缓存文件夹没有足够的空间来缓存额外的文件,LoadFromCacheOrDownload 将会从缓存中迭代删除最近最少使用的 AssetBundles,直到有足够的空间来存储新的 AssetBundle。如果空间还是不够(比如硬盘满了,或者所有缓存的文件都正在被使用),LoadFromCacheOrDownload() 将绕开缓存,直接将文件以流的形式存进内存。

如果想要使用 LoadFromCacheOrDownload 的版本变量,方法参数(第二个参数)需要改变。如果参数与当前缓存的 AssetBundle 的版本变量一致,那么就可以从缓存中加载这个 AssetBundle。

UnityWebRequest

UnityWebRequest 有个专门的 API 来处理 AssetBundles。首先,你需要使用 UnityWebRequest.GetAssetBundle 方法来创建你的 web 请求。在请求返回后,将请求放入 DownloadHandlerAssetBundle.GetContent(UnityWebRequest) 作为参数。GetContent 方法将返回你的 AssetBundle 对象。

在下载完 AssetBundle 后,你同样可以使用 DownloadHandlerAssetBundle 类的 assetBundle 属性来加载 AssetBundle,这就和使用 AssetBundle.LoadFromFile 方法一样高效。

下面有个例子展示:如何加载一个包含两个 GameObjects 的 AssetBundle,并实例化它们。想要运行这段程序,我们只需要调用 StartCoroutine(InstantiateObject()) 方法:

IEnumerator InstantiateObject()
{
string uri = “file:///” + Application.dataPath + “/AssetBundles/” + assetBundleName;
UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
GameObject cube = bundle.LoadAsset(“Cube”);
GameObject sprite = bundle.LoadAsset(“Sprite”);
Instantiate(cube);
Instantiate(sprite);
}
使用 UnityWebRequest 的优点是,它允许开发者用更灵活的方式来处理下载的数据,并且潜在地排除了不必要的内存占用。和 UnityEngine.WWW 类相比,这是更现代,也更推荐的 API。

从 AssetBundles 中加载资源

现在,你已经成功下载了你的 AssetBundle,是时候从中加载一些资源。

通常的代码片段:

T objectFromBundle = bundleObject.LoadAsset(assetName);

T 是你想加载的资源类型。

当你决定如何加载资源的时候,有一对方法供使用。我们可以使用 LoadAsset、LoadAllAssets 方法,以及与它们对应的异步方法: LoadAssetAsync、LoadAllAssetsAsync。

下面是一个从一个 AssetBundle 中同步加载资源的例子:

加载一个 GameObject:

GameObject gameObject = loadedAssetBundle.LoadAsset(assetName);

加载所有资源:

Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();

现在,和上面展示的方法(要么返回你正在加载的对象,要么返回一组对象)不同的是,异步方法返回的是一个 AssetBundleRequest。

在可以使用资源前,你需要等待处理完成。如下:

AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync(assetName);
yield return request;
var loadedAsset = request.asset;
以及:
AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request;
var loadedAssets = request.allAssets;
一旦你已经加载好你的资源,是时候行动了!你可以像使用 Unity 中的其他对象一样使用加载的对象。
加载 AssetBundle Manifests(资源清单)

加载 AssetBundle manifests 非常的有用。尤其是当处理 AssetBundle 依赖关系的时候。为了获取可以使用的 AssetBundleManifest,你需要加载一个额外的 AssetBundle(即那个和文件夹名称相同的文件),并且从中加载出一个 AssetBundleManifest 类型的对象。从 AssetBundle 中加载 manifest 完全和从中加载其他资源一样,如下:

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset(“AssetBundleManifest”);
现在,你可以通过上面例子获取到的 manifest 对象来使用 AssetBundleManifest 类的 API。从现在开始,你可以使用这个 manifest 来获取关于 AssetBundle 的信息,包括:依赖数据、hash 数据,以及版本变量数据。

还记得前面章节我们讨论过的,如果一个 bundleA 对 bundleB 有依赖,那么在从 bundleA 中加载任何资源之前,我们需要先加载 bundleB 吗?Manifest 对象就使得动态查找正在加载的依赖关系成为可能。比如我们想要加载一个名叫“assetBundle”的 AssetBundle 的所有依赖:

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset(“AssetBundleManifest”);
string[] dependencies = manifest.GetAllDependencies(“assetBundle");
foreach(string dependency in dependencies)
{
AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}
现在,你已经加载了 AssetBundle、AssetBundle 依赖,以及其他资源,是时候讨论如何管理这些加载好的 AssetBundles 了。

在 Objects 被从场景中移除的时候,Unity 不会自动将它们卸载。资源的清理是在某个特定时机被触发,当然也可以手动触发。

知道什么时候加载和卸载一个 AssetBundle 很重要。不合时宜的卸载 AssetBundle 可能导致重复对象(duplicating objects)错误,或者其他未预料到的情况,比如纹理丢失

理解如何管理 AssetBundle 最重要的事是什么时候调用 AssetBundle.Unload(bool) 方法,以及该方法的参数应该传入 true 还是 false。该方法卸载 AssetBundle 的头信息;方法参数决定了是否同时卸载从 AssetBundle 中加载并实例化的所有 Objects。

如果你传入 true 参数,那么你从 AssetBundle 中加载的所有对象将被卸载,即便这些对象正在被使用。这就是我们前面提到的,导致纹理丢失的原因。

假设 Material M 是从 AssetBundle AB 中加载的,如下:

如果 AB.Unload(true) 被调用,那么任何使用 Material M 的实例都将被卸载并消除,即便它们正在场景中被使用。

如果 AB.Unload(false) 被调用,那么将切断所有使用 Material M 的实例与 AssetBundle AB 的联系。

如果 AssetBundle AB 在被卸载后不久再次被加载,Unity 并不会将已经存在的使用 Material M 的实例与 AssetBundle AB 重新联系。因此将存在两份被加载的 Material M。

通常情况下,使用 AssetBundle.Unload(false) 不会获得理想情况。大多数项目应该使用 AssetBundle.Unload(true) 方法,以避免内存中出现重复对象(duplicating objects)。

大多数项目应该使用 AssetBundle.Unload(true) 方法,并且要采取措施确保没有重复对象。两种通常采取的措施如下:

在应用的生命周期中找到合适的时机来卸载 AssetBundle,比如关卡之间,或者加载场景的时候。

为每个对象采取引用计数管理方法,只有当 AssetBundle 的所有对象都没有被使用的时候,再卸载 AssetBundle。这样就可以避免应用出现重复对象的问题。

如果应用必须使用 AssetBundle.Unload(false) 方法,对象将只能在以下两种情况下被卸载:

消除对象的所有引用,包括场景中的和代码中的。之后,调用

Resources.UnloadUnusedAssets。

没有额外附加特性地加载一个场景。这将消除当前场景的所有对象,并自动调用 Resources.UnloadUnusedAssets。

如果你不想自己管理加载的 AssetBundle、依赖关系,以及资源,你可能需要使用 AssetBundle 管理器。(AssetBundle Manager,下一章节将介绍。)

public class LoadAssetBundle : MonoBehaviour {
public string manifestFilePath;
// Use this for initialization
void Start () {
manifestFilePath = Application.streamingAssetsPath + “/StreamingAssets”;
}

void GetData(){
	AssetBundle assetBundle = AssetBundle.CreateFromFile(manifestFilePath);
	AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
	string[] dependencies = manifest.GetAllDependencies(“mater.assetbundle");
	foreach(string dependency in dependencies)
	{
		AssetBundle.CreateFromFile(Application.streamingAssetsPath+"/"+dependency);
	}
	
	AssetBundle bundle= AssetBundle.CreateFromFile 
		(Application.streamingAssetsPath+"/mater.assetbundle");
	Material mat = (Material)bundle.LoadAsset ("Red");
	GetComponent<MeshRenderer> ().material = mat;

}

上一篇:Unity5 多场景 打包Assetbundle 以及 Shader Stripping 导致 LightMap 全部丢失的解决方法


下一篇:unity打包AssetBundle包的几种压缩方式介绍