AssetBundle

思考并回答以下问题:

简介

AssetBundle是Unity引擎提供的一种资源打包方式,可以对Unity内的任何资源类型进行打包处理(除了C#脚本)。

AssetBundle的作用类似于电脑上的压缩软件,可以将一个或者多个资源进行打包管理,顺带还可以对资源的体积进行压缩。

Unity实现热更新的时候,更新下载下来的资源都是需要事先进行AssetBundle打包处理的。

打包

资源标签的设置

在Unity环境内,除去C#脚本文件以外,选中任何文件后,在Inspector面板的下方都会出现一个Asset Lables功能区域,通过这个功能可以给资源设置AssetBundle的文件名和文件后缀。

文件名:资源打包成AssetBundle后的文件名,类似于压缩包的名字;
后缀:企业开发中常用的后缀有unity3d,assetbundle,ab,其他自定义;

注意:文件名和后缀名都是小写格式。

打包的实现

方法:BuildPipeline.BuildAssetBundles(路径, 选项, 平台);

BuildAssetBundles:打包所有设置了AssetLabels的资源;

参数分析:

  • 1.路径:打包出来的AssetBundle文件存放的位置;
  • 2.选项:设置AssetBundle打包过程中的选项,None表示忽略该选项;
  • 3.平台:AssetBundle是平台之间不兼容的,IOS,Android是两套资源;

AssetBundle打包选项(一般都是使用第一种)

1、BuildAssetBundleOptions.None:
使用 LZMA 压缩算法进行压缩,打包后的资源体积最小。

2、BuildAssetBundleOptions.UncompressedAssetBundle:
不使用压缩方式,打包后的AssetBundle体积最大,但是加载速度最快。

3、BuildAssetBundleOptions.ChunkBasedCompression:
使用LZ4 压缩算法进行压缩,打包后的AssetBundle体积和加载速度介于二者之间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

// 该脚本放在Editor文件夹下面
public class Packer
{
[MenuItem("Packer/DoPacker")]
public static void DoPacker()
{
// 打包好的资源一般要放在StreamingAssets文件夹下面,发布后才能正常加载
// StreamingAssets文件夹是一个特殊的文件夹,发布项目后会被复制到项目中
// 自己创建的文件夹不会被发布到项目中
string path = Application.streamingAssetsPath;
BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}

资源分类打包

在Asset Labels区域填写AssetBundle名称的时候,名称是可以分目录嵌套的,比如:文件夹名/文件名。这样就可以在指定的路径下面,创建文件夹,把资源放在里面。

mainfest文件

AssetBundle打包完毕后的资源包,由两部分组成。

  • 1.资源打包出来的AssetBundle文件;
  • 2.AssetBundle文件配套的manifest文本文件。

备注说明:

.meta文件不属于AssetBundle打包后的产物。

在Unity3D环境内,每个资源都会自动生成一个同名同后缀的.meta 文件。这个文件用于存储该资源的一些基本信息。比如:“创建时间,版本ID,AssetBundle名称,后缀”等信息。

manifest文件和.meta文件作用类似。

manifest文件是用于专门存储打包后的AssetBundle文件的基本信息的。主要包含以下信息:

  • CRC校验码:类似于MD5,用于计算出该资源的一个特殊信息标示;
  • ClassTypes列表:当前资源关联使用到了Unity中的哪些类,这些类是以编号索引的形式存在的,每个编号都对应一个类文件。

StreamingAssets.mainfest

在我们打包出来的AssetBundle文件中,有一个特殊的manifest文件StreamingAssets.mainfest。这个manifest文件是和用于存储AssetBundle的文件夹同名的文件,且只在根文件夹下有唯一的一个。

这个manifest文件可以称之为“AssetBundle目录文件”,因为这个文件中内存储了打包出来的所有的AssetBundle的文件的索引信息。
通过这个目录文件,可以找到所有的AssetBundle文件。

AssetBundle资源加载

留在项目工程中当成普通的资源使用

StreamingAssets文件夹

StreamingAssets文件夹是Unity引擎内部规定的一个特殊功能文件夹,和Resources文件夹类似。

在Windows平台通过下方的路径代码就可以访问到该文件夹下的资源(两种方式):
1、Application.dataPath + “/StreamingAssets/fileName”

2、Application.streamingAssetsPath + “fileName”

放到该文件夹内的资源,在项目打包过程中会直接把该文件夹以及文件夹内部所有的资源一起原封不动的打包到最终的项目成品中。

Windows平台:会直接打包到“xxxx_Data”文件夹下的StreamingAssets文件夹;

Android平台:会直接打包到APK文件中。

注意:在Android平台的调用路径和Windows平台稍有不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InitGame : MonoBehaviour
{

// Use this for initialization
void Start () {
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/prefab/bear.ab");
GameObject bear = ab.LoadAsset<GameObject>("bear");
Instantiate(bear);
}

}

文件上传服务器更新时使用

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System.IO;

public class DownLoadAssetBundle : MonoBehaviour
{
// 以下两个是网页资源服务器的路径

// mainAssetBundleURL这个路径下面只需要存放一个文件就可以了(打包好的名为StreamingAssets的文件,没有后缀的,这个文件其实也是一个ab包)
private string mainAssetBundleURL = @"http://www.mynet.com/Assets/AssetBundles/Main";

//
private string allAssetBundelURL = @"http://www.mynet.com/Assets/AssetBundles/";

void Start ()
{
// 开始下载主目录文件(StreamingAssets文件)
StartCoroutine("DownLoadMainAssetBundel");
}

// 下载主[目录]AssetBundle文件(StreamingAsset文件和StreamingAsset.manifest文件)
IEnumerator DownLoadMainAssetBundel()
{
// 通过UnityWebRequest.GetAssetBundle()把函数对应路径的AB资源下载下来
UnityWebRequest request = UnityWebRequest.GetAssetBundle(mainAssetBundleURL);
yield return request.Send();
// 获取这个AB包
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
// StreamingAsset文件包含了StreamingAsset.manifest
// 加载StreamingAsset文件,不加载StreamingAsset.manifest也可以得到StreamingAsset.manifest
// 从这个AB包里面去获取StreamingAsset.manifest文件
AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

// 获取StreamingAsset.manifest文件里面记录的所有被打包资源
string[] names = manifest.GetAllAssetBundles();

for (int i = 0; i < names.Length; i++)
{
Debug.Log(allAssetBundelURL + names[i]);
// StartCoroutine(DownLoadSingleAssetBundel(allAssetBundelURL + names[i]));
StartCoroutine(DownLoadAssetBundleAndSave(allAssetBundelURL + names[i]));
}
}

/// 下载单个AssetBundle文件
IEnumerator DownLoadSingleAssetBundel(string url)
{
UnityWebRequest request = UnityWebRequest.GetAssetBundle(url);
yield return request.Send();
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
string[] names = ab.GetAllAssetNames();

for (int i = 0; i < names.Length; i++)
{
string tempName = Path.GetFileNameWithoutExtension(names[i]);
//Debug.Log(tempName);
GameObject obj = ab.LoadAsset<GameObject>(tempName);
GameObject.Instantiate<GameObject>(obj);
}
}

// 下载AssetBundle并且保存到本地
IEnumerator DownLoadAssetBundleAndSave(string url)
{
WWW www = new WWW(url);
yield return www;

if (www.isDone)
{
// 使用IO技术将www对象存储到本地
SaveAssetBundle(Path.GetFileName(url), www.bytes, www.bytes.Length);
}
}

// 存储AssetBundle为本地文件
private void SaveAssetBundle(string fileName, byte[] bytes, int count)
{
FileInfo fileInfo = new FileInfo(Application.streamingAssetsPath + "//" + fileName);
FileStream fs = fileInfo.Create();
fs.Write(bytes, 0, count);
fs.Flush();
fs.Close();
fs.Dispose();
Debug.Log(fileName + "下载完毕~~~");
}
}

IO存储资源

WWW下载资源

1
WWW www = new WWW(url);

通过WWW类创建一个web请求,参数填写AssetBundle的url下载地址。

1
yield return www;

将对象作为数据返回,这个www对象就是请求(下载)来的数据。

1
www.isDone

一个属性,表示下载状态是否完毕。
使用if语句块判断,当这个属性为真时,就可以使用IO技术把这个 www对象作为AssetBundle存储到本地。

IO存储资源

1
FileInfo fileInfo = new FileInfo(文件完整路径+名称);

创建一个文件信息对象。

1
FileStream fs = fileInfo.Create();

通过文件信息对象的“创建”方法,得到一个文件流对象。

1
fs.Write(字节数组, 开始位置, 数据长度);

通过文件流对象,往这个文件内写入信息。

1
2
3
fs.Flush();
fs.Close();
fs.Dispose();

文件写入存储到硬盘,关闭文件流对象,销毁文件对象。

几个常用API

1
AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

从这个“目录AssetBundle”中获取manifest数据。

1
string[] assets = manifest.GetAllAssetBundles();

获取这个manifest文件中所有的AssetBundle的名称信息。

1
string[] names = ab.GetAllAssetNames();

通过获取到的AssetBundle对象获取内部所有的资源的名称,返回一个数组。

1
Path.GetFileNameWithoutExtension(path)

截取路径地址中的文件名,且无后缀名。需要引入System.IO命名空间。

0%