# AssetBundle 创建与加载
- AssetBundle 只能用代码创建和加载
- 在创建前需要先为资源分配资源包,如图:
# AssetBundle 创建
- 区分平台(Windows、OSX、Linux 等)
- 区分创建方式(是否压缩、压缩方式等)
- lua 文件无法被打包,本文使用的方法是:生成 .lua 文件对应的 .txt 文件,将 .txt 文件打包,然后删除生成的 .txt 文件
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using UnityEditor; | |
using UnityEngine; | |
namespace Common | |
{ | |
/// <summary> | |
/// CreateAssetBundles | |
/// </summary> | |
public class CreateAssetBundles | |
{ | |
/// <summary> | |
/// BuildAllAssetBundles | |
/// </summary> | |
[MenuItem("Build/Build AssetBundles")] | |
private static void BuildAllAssetBundles() | |
{ | |
// 自定义路径 | |
//string assetBundleDirectory = EditorUtility.OpenFolderPanel ("选择导出路径", Application.dataPath, ""); | |
//if (string.IsNullOrEmpty(assetBundleDirectory)) | |
//{ | |
// return; | |
//} | |
string assetBundleDirectory = Application.streamingAssetsPath + "/AssetBundles"; | |
BuildAssetBundleOptions assetBundleOptions; | |
BuildTarget targetPlatform; | |
#if UNITY_STANDALONE_WIN //Windows 独立平台应用程序 | |
assetBundleOptions = BuildAssetBundleOptions.UncompressedAssetBundle; | |
targetPlatform = BuildTarget.StandaloneWindows64; | |
#elif UNITY_WSA //UWP | |
assetBundleOptions = BuildAssetBundleOptions.UncompressedAssetBundle; | |
targetPlatform = BuildTarget.WSAPlayer; | |
#elif UNITY_STANDALONE_OSX //Mac OS X(包括 Universal、PPC 和 Intel 架构) | |
assetBundleOptions = BuildAssetBundleOptions.UncompressedAssetBundle; | |
targetPlatform = BuildTarget.StandaloneOSX; | |
#elif UNITY_STANDALONE_LINUX //Linux | |
assetBundleOptions = BuildAssetBundleOptions.UncompressedAssetBundle; | |
targetPlatform = BuildTarget.StandaloneLinux; | |
#elif UNITY_ANDROID | |
assetBundleOptions = BuildAssetBundleOptions.ChunkBasedCompression; | |
targetPlatform = BuildTarget.Android; | |
#elif UNITY_IOS | |
assetBundleOptions = BuildAssetBundleOptions.ChunkBasedCompression; | |
targetPlatform = BuildTarget.iOS; | |
#elif UNITY_WEBGL | |
assetBundleOptions = BuildAssetBundleOptions.ChunkBasedCompression; | |
targetPlatform = BuildTarget.WebGL; | |
#endif | |
if (!Directory.Exists(assetBundleDirectory)) | |
{ | |
Directory.CreateDirectory(assetBundleDirectory); | |
} | |
else | |
{ | |
Directory.Delete(assetBundleDirectory, true); | |
Directory.CreateDirectory(assetBundleDirectory); | |
} | |
string[] allTxtPaths = CopyLuaToTxt(); | |
GetFilesInfo(); | |
BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleOptions, targetPlatform); | |
DeleteTxtFiles(allTxtPaths); | |
AssetDatabase.Refresh(); | |
} | |
/// <summary> | |
/// 获取文件信息,用于调试 | |
/// </summary> | |
private static void GetFilesInfo() | |
{ | |
string[] bundleNames = AssetDatabase.GetAllAssetBundleNames(); | |
List<string> allAssetPaths = new List<string>(); | |
foreach (string bundleName in bundleNames) | |
{ | |
string[] assetPaths = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName); | |
allAssetPaths.AddRange(assetPaths); | |
} | |
StringBuilder stringBuilder = new StringBuilder(); | |
stringBuilder.AppendLine("All AB paths:"); | |
foreach (string path in allAssetPaths) | |
{ | |
stringBuilder.AppendLine(path); | |
} | |
Debug.Log(stringBuilder.ToString()); | |
} | |
/// <summary> | |
/// 将 .lua 文件转换为 .txt 文件 | |
/// </summary> | |
/// <returns>.txt 文件路径 & lt;/returns> | |
private static string[] CopyLuaToTxt() | |
{ | |
string[] bundleNames = AssetDatabase.GetAllAssetBundleNames(); | |
List<string> allAssetPaths = new List<string>(); | |
List<string> allTxtPaths = new List<string>(); | |
foreach (string bundleName in bundleNames) | |
{ | |
string[] assetPaths = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName); | |
allAssetPaths.AddRange(assetPaths); | |
} | |
foreach (string path in allAssetPaths) | |
{ | |
if (path.EndsWith(".lua")) | |
{ | |
// 读取.lua 文件内容 | |
var utf8 = new System.Text.UTF8Encoding(false); | |
string content = File.ReadAllText(path, utf8); | |
// 构造对应的.txt 文件路径 | |
string txtPath = Path.ChangeExtension(path, "txt"); | |
File.WriteAllText(txtPath, content, utf8); | |
allTxtPaths.Add(txtPath); | |
} | |
} | |
AssetDatabase.Refresh(); | |
return allTxtPaths.ToArray(); | |
} | |
/// <summary> | |
/// 删除 .txt 文件 | |
/// </summary> | |
/// <param name="dir"></param> | |
private static void DeleteTxtFiles(string[] allTxtPaths) | |
{ | |
foreach (string path in allTxtPaths) | |
{ | |
AssetDatabase.DeleteAsset(path); | |
} | |
} | |
} | |
} |
# AssetBundle 加载
- 两种加载方式:通过网络请求加载(UnityWebRequest)、通过本地存储加载(AssetBundle.LoadFromFile ())
- 本工具类中使用网络请求加载方式,目的是为了适配更多的设备
- 同一个 ab 包中如果有多个同名文件,则只会加载第一个匹配的文件
- 加载目标 ab 包前,需要先加载它的依赖 ab 包(如果存在)
- 加载目标 ab 包后,调用委托处理其他逻辑
- 加载的 ab 包在使用完后需要卸载,防止占用内存
using System; | |
using System.Collections; | |
using UnityEngine; | |
using UnityEngine.Networking; | |
namespace Common | |
{ | |
/// <summary> | |
/// AB 包管理器 | |
/// </summary> | |
public static class AssetBundleManager | |
{ | |
/// <summary> | |
/// 加载资源包 | |
/// </summary> | |
/// <param name="body"> 执行对象 & lt;/param> | |
/// <param name="path"> 路径 & lt;/param> | |
/// <param name="action"> 委托 & lt;/param> | |
public static void LoadAssetBundle(this MonoBehaviour body, string path, Action<AssetBundle> action) | |
{ | |
body.StartCoroutine(LoadAssetBundle_(path, action)); | |
} | |
/// <summary> | |
/// 加载资源包 | |
/// </summary> | |
/// <param name="path"> 路径 & lt;/param> | |
/// <param name="action"> 委托 & lt;/param> | |
/// <returns></returns> | |
private static IEnumerator LoadAssetBundle_(string path, Action<AssetBundle> action) | |
{ | |
string assetBundleName = path.Split('/')[^1]; | |
string startPath = path.Substring(0, path.LastIndexOf('/')); | |
// 获取 AssetBundles 文件 | |
UnityWebRequest request_0 = UnityWebRequestAssetBundle.GetAssetBundle(startPath + "/AssetBundles", 0); | |
yield return request_0.SendWebRequest(); | |
if (request_0.result != UnityWebRequest.Result.Success) | |
{ | |
Debug.LogError("Failed to load AssetBundle:" + request_0.error); | |
} | |
else | |
{ | |
AssetBundle bundle_0 = DownloadHandlerAssetBundle.GetContent(request_0); | |
// 获取 manifest 文件 | |
AssetBundleManifest manifest_0 = bundle_0.LoadAsset("AssetBundleManifest") as AssetBundleManifest; | |
bundle_0.Unload(false); | |
// 查找并加载依赖文件 | |
string[] dependencies = manifest_0.GetAllDependencies(assetBundleName); | |
AssetBundle[] bundles = new AssetBundle[dependencies.Length]; | |
for (int i = 0; i < dependencies.Length; i++) | |
{ | |
string dependenciesPath = startPath + '/' + dependencies[i]; | |
UnityWebRequest requests = UnityWebRequestAssetBundle.GetAssetBundle(dependenciesPath, 0); | |
yield return requests.SendWebRequest(); | |
if (requests.result != UnityWebRequest.Result.Success) | |
{ | |
Debug.LogError("Failed to load AssetBundle:" + requests.error); | |
} | |
else | |
{ | |
bundles[i] = DownloadHandlerAssetBundle.GetContent(requests); | |
} | |
} | |
// 取出资源 | |
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(path, 0); | |
yield return request.SendWebRequest(); | |
if (request.result != UnityWebRequest.Result.Success) | |
{ | |
Debug.LogError("Failed to load AssetBundle:" + request.error); | |
} | |
else | |
{ | |
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request); | |
action(bundle); | |
bundle.Unload(false); | |
} | |
foreach (AssetBundle item in bundles) | |
{ | |
item.Unload(false); | |
} | |
} | |
} | |
} | |
} |
# 使用方法
创建
点击按钮创建 ab 包,如图:
加载
using Common; | |
using UnityEngine; | |
namespace Default | |
{ | |
/// <summary> | |
/// AB 包测试 | |
/// </summary> | |
public class ABTest : MonoBehaviour | |
{ | |
private void Start() | |
{ | |
this.LoadAssetBundle(Application.streamingAssetsPath + "/AssetBundles/lua_bundles", TestAction); | |
} | |
private void TestAction(AssetBundle bundle) | |
{ | |
TextAsset receive = bundle.LoadAsset<TextAsset>("main"); | |
Debug.Log(receive.text); | |
} | |
} | |
} |