# AssetBundle 创建与加载

  • AssetBundle 只能用代码创建和加载
  • 在创建前需要先为资源分配资源包,如图:img

# 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 包,如图:img

加载

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);
        }
    }
}