AssetBundle Features
1. The AB package can store most of the Unity resources but cannot directly store C# scripts, so the hot update of the code needs to use Lua or store the compiled DLL file, as well as the HybridCLR hot update plug-in, and the code resources can be hot updated.
2. The AB package cannot be loaded repeatedly. When the AB package has been loaded into the memory, it must be unloaded before it can be reloaded.
3. Multiple resources are distributed in different AB packages. Some resources such as the texture of a prefab may not be in the same package. Some resources will be lost when directly loaded, that is, there are dependencies between AB packages. When loading the current AB package, you need to load the packages it depends on.
4. After the packaging is completed, a main package will be automatically generated (the name of the main package varies with the platform), and the version number, check code (CRC), and all other package related information (name, dependencies)
Plugin Overview
Download address: https://github.com/Unity-Technologies/AssetBundles-Browser
1. Configure panel: You can view the basic situation of the current AB package and its internal resources (size, resources, dependencies, etc.), and also configure those ab packages packaged during Build
2. Build panel: Responsible for the related settings of AssetBundle packaging, press Build to start packaging
2.1 Three compression methods
1. NoCompression: No compression, fast decompression, large package, not recommended.
2. LZMA: Minimal compression, slow decompression, use one resource to decompress all resources.
3. LZ4: The compression is slightly larger, and the decompression is fast. What to use to decompress, the memory usage is low, and it is recommended to use it.
Generally, the settings that need to be changed are the relevant option settings ticked in the figure.
3. Inspect panel: It is mainly used to view some details of the packaged AB package file (size, resource path, etc.)
Load related API
//AB package loading required related API //1. Load the AB package according to the path Note that the AB package cannot be loaded repeatedly AssetBundle ab = AssetBundle. LoadFromFile(path); //2. Load the resource with the specified name and type under the ab package T obj = ab.LoadAsset<T>(ResourceName); //generic loading Object obj = ab.LoadAsset(ResourceName); //Non-generic loading, the type needs to be forced for subsequent use Object obj = ab.LoadAsset(ResourceName,Type); //The parameter specifies the resource type to prevent duplicate names T obj = ab.LoadAssetAsync<T>(resName); //Asynchronous generic loading Object obj = ab.LoadAssetAsync(resName); //Asynchronous non-generic loading Object obj = ab.LoadAssetAsync(resName,Type); //The parameter specifies the resource type to prevent duplicate names //3. Uninstall the ab package The bool parameter represents whether to delete the resources that have been loaded into the scene from this AB package (usually false) ab.UnLoad(false); //Unload a single ab package AssetBundle.UnloadAllAssetBundles(false); //Unload all AB packages
Sample code:
using System; using System.Net.Mime; using System. Collections; using System.Collections.Generic; using UnityEngine; namespace Common { /// <summary> /// AB package manager is globally unique and uses singleton mode /// </summary> public class ABManager : MonoSingleton<ABManager> { //AB package cache --- solve the problem that the AB package cannot be loaded repeatedly, and it is also conducive to improving efficiency. private Dictionary<string, AssetBundle> abCache; private AssetBundle mainAB = null; //main package private AssetBundleManifest mainManifest = null; //Configuration file in the main package --- used to obtain dependent packages //Basic paths under each platform --- Use macros to determine the streamingAssets path under the current platform private string basePath { get { //Use the StreamingAssets path and pay attention to check copy to streamingAssets when packaging the AB package #if UNITY_EDITOR || UNITY_STANDALONE return Application.dataPath + "/StreamingAssets/"; #elif UNITY_IPHONE return Application.dataPath + "/Raw/"; #elif UNITY_ANDROID return Application.dataPath + "!/assets/"; #endif } } //The name of the main package under each platform --- used to load the main package to obtain dependency information private string mainABName { get { #if UNITY_EDITOR || UNITY_STANDALONE return "Standalone Windows"; #elif UNITY_IPHONE return "IOS"; #elif UNITY_ANDROID return "Android"; #endif } } //Inherit the initialization function provided by the singleton mode protected override void Init() { base.Init(); //Initialize the dictionary abCache = new Dictionary<string, AssetBundle>(); } //Load the AB package private AssetBundle LoadABPackage(string abName) { AssetBundle ab; //Load the ab package, and its dependent packages need to be loaded together. if (mainAB == null) { //Load the main package according to the basic path and main package name under each platform mainAB = AssetBundle.LoadFromFile(basePath + mainABName); //Get the AssetBundleManifest resource file under the main package (with dependency information) mainManifest = mainAB. LoadAsset<AssetBundleManifest>("AssetBundleManifest"); } // Get the names of all dependent packages according to the manifest Fixed API string[] dependencies = mainManifest. GetAllDependencies(abName); //Cycle load all dependent packages for (int i = 0; i < dependencies. Length; i ++ ) { // join if not in cache if (!abCache. ContainsKey(dependencies[i])) { //Load according to the dependent package name ab = AssetBundle.LoadFromFile(basePath + dependencies[i]); //Pay attention to adding it to the cache to prevent repeated loading of AB packages abCache. Add(dependencies[i], ab); } } //Load the target package -- also pay attention to the cache problem if (abCache.ContainsKey(abName)) return abCache[abName]; else { ab = AssetBundle.LoadFromFile(basePath + abName); abCache. Add(abName, ab); return ab; } } //==================== Three resource synchronous loading methods =================== //Provide a variety of calling methods to facilitate calling in other languages (Lua does not support generics well) Three overloads for synchronous loading of #region /// <summary> /// Synchronously load resources---generic loading is simple and intuitive, no display conversion required /// </summary> /// <param name="abName">The name of the ab package</param> /// <param name="resName">Resource name</param> public T LoadResource<T>(string abName, string resName) where T:Object { //load the target package AssetBundle ab = LoadABPackage(abName); //return resource return ab.LoadAsset<T>(resName); } //Do not specify the type. It is not recommended to use it if there are duplicate names. When using it, the conversion type needs to be displayed public Object LoadResource(string abName, string resName) { //load the target package AssetBundle ab = LoadABPackage(abName); //return resource return ab.LoadAsset(resName); } //Using parameters to pass types, suitable for language calls that do not support generics, need to force the type when using public Object LoadResource(string abName, string resName, System.Type type) { //load the target package AssetBundle ab = LoadABPackage(abName); //return resource return ab.LoadAsset(resName,type); } #endregion //================== Three resource asynchronous loading methods ======================== /// <summary> /// Provide asynchronous loading ---- Note that the loading of the AB package here is synchronous loading, but the loading of resources is asynchronous /// </summary> /// <param name="abName">ab package name</param> /// <param name="resName">Resource name</param> public void LoadResourceAsync(string abName, string resName, System.Action<Object> finishLoadObjectHandler) { AssetBundle ab = LoadABPackage(abName); //Enable the coroutine to provide a delegate after the resource is loaded successfully StartCoroutine(LoadRes(ab, resName, finishLoadObjectHandler)); } private IEnumerator LoadRes(AssetBundle ab, string resName, System.Action<Object> finishLoadObjectHandler) { if (ab == null) yield break; //Asynchronous loading resource API AssetBundleRequest abr = ab.LoadAssetAsync(resName); yield return abr; // delegate call processing logic finishLoadObjectHandler(abr.asset); } //Asynchronously load resources according to Type public void LoadResourceAsync(string abName, string resName, System.Type type, System.Action<Object> finishLoadObjectHandler) { AssetBundle ab = LoadABPackage(abName); StartCoroutine(LoadRes(ab, resName,type, finishLoadObjectHandler)); } \t private IEnumerator LoadRes(AssetBundle ab, string resName, System.Type type, System.Action<Object> finishLoadObjectHandler) { if (ab == null) yield break; AssetBundleRequest abr = ab.LoadAssetAsync(resName,type); yield return abr; // delegate call processing logic finishLoadObjectHandler(abr.asset); } // Generic loading public void LoadResourceAsync<T>(string abName, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object { AssetBundle ab = LoadABPackage(abName); StartCoroutine(LoadRes<T>(ab, resName, finishLoadObjectHandler)); } private IEnumerator LoadRes<T>(AssetBundle ab, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object { if (ab == null) yield break; AssetBundleRequest abr = ab.LoadAssetAsync<T>(resName); yield return abr; // delegate call processing logic finishLoadObjectHandler(abr.asset as T); } //======================= Two ways to uninstall the AB package ================== //Single package uninstall public void UnLoad(string abName) { if(abCache. ContainsKey(abName)) { abCache[abName].Unload(false); //Note that the cache needs to be removed together abCache. Remove(abName); } } // uninstall all packages public void UnLoadAll() { AssetBundle. UnloadAllAssetBundles(false); //Note to clear the cache abCache. Clear(); mainAB = null; mainManifest = null; } } }