unity-doc-Addressables

介绍

文件

  • catalog.hash:存储每个版本的hash文件。
  • catalog.json:存储所有bundle的信息,以及每个bundle里面拥有的asset,以及每个asset的hash信息。
  • catalog日期表示首次打包的时间。
  • addressables_content_state.bin:所有ab包之间的依赖关系,以及资源的分组信息。

流程

  • 启动时,跟服务器对比catalog.hash文件。
  • 如果hash不同,则说明服务器更新了资源,此时启动最新的catalog.json文件的下载。

建议

  • Group打出来的bundle非常小,<1M建议合起来打,因为资源文件存在io的过程。

  • Group打出来的bundle非常小,<4kb建议合起来打,因为资源在磁盘上都占据4k独立空间。

  • 确定不会存在依赖的资源,不会存在资源重复打包的资源,而且不需要使用代码加载的资源,不要丢到assetbundle的group里面,不然会导致catalog文件变大,例如一个角色模型,不存在依赖,之间给预知体打group就可以了。

加载方式

三种加载方式

  • Use Asset Database(fastest):快速,直接加载文件而不打包,一般在开发时使用此模式。
  • Simulate Groups(advanced):在不打包的情况下模拟AssetBundle的模操作。
  • Use Existing Build:实际上是从AssetBundle打包和加载,需要先通过Build打包,才能使用,也可以加载本地和远程Bundle。

加载注意点

  • AssetReference 方式加载的时候,资源即使没有设置使用Addressable,一旦拖到界面的public变量时,会自动设置为使用Addressable。

  • 声明是我们常用的GameObject等类型,那么场景就直接依赖了这个资源,打包时这个资源就会被打到场景中。如果声明的是AssetReference 类型,它是一个弱引用,场景并不会真的依赖这个资源。

  • WaitForCompletion的作用是会让系统阻拦代码执行,直到资源加载完成。

  • 除了我们常用的资源类型(预制,贴图,音频,配置文件)这些可以使用可寻址代码加载,场景也可以使用可寻址代码加载代码Addressables.LoadSceneAsync("Assets/Scenes/Game.unity");

  • 使用key的方式加载的好处在于不管我们之后如何修改路径或者是修改预制体名称,都不会影响到上面代码的加载逻辑,这就是可寻址。只要key不修改就不用修改代码,若AddressablesGroups中存在相同的key,则代码会返回列表中靠上的资源。

释放注意点

  • 资源释放 不影响场景中实例化出的对象,但是会影响非实例化的资源(材质、音效等)。
  • 释放后的资源,再次使用需要重新加载。
  • 资源释放后AssetReference的资源引用(Asset)会清空 但AsyncOperationHandle类的资源引用(Result)不为空
  • AA系统中的资源释放有两个方法一个是Release,另外一个ReleaseInstance。两个方法分别用于不同的情况。大致可以记忆为:Release释放不需要实例化资源,ReleaseInstance释放实例化资源。
  • 使用LoadAssetAsync加载然后Instantiate实例化的,是不能通过ReleaseInstance来进行释放资源的,而通过Release来释放也只能传递handle来释放不能传递instance这个游戏对象。

使用

启动资源热更

  1. 找到Assets/AddressableAssetSettings/AddressableAssetSettings
  2. 勾选Content Update下的Build Remote CatalogDisbale Catalog Update on Startup
  3. 重新打一个新资源包,勾选之前打的包不会生效。
  4. 增量热更的时候,除了提交.bundle文件,还需要将catalog_xxx.hashcatalog_xx.json也提交,不提交是热更不了的。
  5. 注意:更了最新的catalog文件到服务,如果.bundle文件还没更上去,是会导致更新失败,所以先更.bundle在更catalog文件

修改缓存目录

  1. 选中Assets/AddressableAssetSettings目录
  2. 鼠标右键 create->Addressables->Initialization->Cache Initialization Settings
  3. 选中新创建的 Cache Initialization Settings,修改 Cache Directory Override;目录根profile不一样,{UnityEngine.Application.persistentDataPath}
  4. 选中 AddressableAssetSettings,在 Initialization Objects 里添加新创建的 Cache Initialization Settings

资源放到StreamingAssets内

  1. buildPath 写Assets/StreamingAssets/[BuildTarget]

Https://blog.csdn.net/qq_14903317/article/details/108582372?spm=1001.2014.3001.5501

资源启动全部下载

可变更的热更下载地址

  1. 用www将自定义的catalog文件下载persistantDataPath
  2. 用Addressables.LoadContentCatalogAsync读取该文件
1
2
3
4
5
var catalogPath = @"";

// 加载catalog
Addressables.LoadContentCatalogAsync(catalogPath).Completed += (h) => {
};

源码修改(v1.19.19)

丢到项目会报错处理

  1. AddressableAssetUtility.cs 修改函数 GetVersionFromPackageData

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    internal static string GetVersionFromPackageData()
    {
    if (string.IsNullOrEmpty(m_Version))
    {
    /**改动**/
    // var jsonFile = AssetDatabase.LoadAssetAtPath<TextAsset>("Packages/com.unity.addressables/package.json");
    var jsonFile = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Thirds/com.unity.addressables/package.json");
    var packageData = JsonUtility.FromJson<PackageData>(jsonFile.text);
    var split = packageData.version.Split('.');
    if (split.Length < 2)
    throw new Exception("Could not get correct version data for Addressables package");
    m_Version = $"{split[0]}.{split[1]}";
    }
    return m_Version;
    }
  2. 修改BuildScriptBase.csWriteBuildLog函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /**改动**/ 
    struct PackageData
    {
    public string name;
    public string version;
    }

    internal static void WriteBuildLog(BuildLog log, string directory)
    {
    Directory.CreateDirectory(directory);

    /**改动**/
    var jsonFile = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Thirds/com.unity.addressables/package.json");
    var packageData = JsonUtility.FromJson<PackageData>(jsonFile.text);

    // PackageManager.PackageInfo info = PackageManager.PackageInfo.FindForAssembly(typeof(BuildScriptBase).Assembly);
    log.AddMetaData(packageData.name, packageData.version);
    File.WriteAllText(Path.Combine(directory, "AddressablesBuildTEP.json"), log.FormatForTraceEventProfiler());
    }

抽取打包功能

  1. 修改 AddressableAssetsSettingsGroupEditorpublish
  2. 修改 AddressableAssetsSettingsGroupEditor 新加函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /// <summary>
    /// 暴露给外部打包
    /// </summary>
    /// <param name="context"></param>
    public static void OnBuildScriptCustom(object context)
    {
    AddressableAssetSettingsDefaultObject.Settings.ActivePlayerDataBuilderIndex = (int)context;
    AddressableAssetSettings.BuildPlayerContent();
    }
  3. 修改 AddressableAssetsWindowpublish

修改打包记录文件位置

  1. 修改 ContentUpdateScriptGetContentStateDataPath 函数
    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
    // 新加
    public static string addressables_content_state_path = "";

    /// <summary>
    /// Gets the path of the cache data from a selected build.
    /// </summary>
    /// <param name="browse">If true, the user is allowed to browse for a specific file.</param>
    /// <returns></returns>
    public static string GetContentStateDataPath(bool browse)
    {
    string assetPath = AddressableAssetSettingsDefaultObject.Settings != null ?
    AddressableAssetSettingsDefaultObject.Settings.GetContentStateBuildPath() :
    Path.Combine(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder, PlatformMappingService.GetPlatformPathSubFolder());

    if (browse)
    {
    if (string.IsNullOrEmpty(assetPath))
    assetPath = Application.dataPath;

    assetPath = EditorUtility.OpenFilePanel("Build Data File", Path.GetDirectoryName(assetPath), "bin");

    if (string.IsNullOrEmpty(assetPath))
    return null;

    return assetPath;
    }

    // 新加
    if (!string.IsNullOrEmpty(addressables_content_state_path))
    {
    // 自定义生成路径
    return addressables_content_state_path;
    }

    if (AddressableAssetSettingsDefaultObject.Settings != null)
    {
    try
    {
    Directory.CreateDirectory(assetPath);
    }
    catch (Exception e)
    {
    Debug.LogError(e.Message + "\nCheck \"Content State Build Path\" in Addressables settings. Falling back to config folder location.");
    assetPath = Path.Combine(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder,
    PlatformMappingService.GetPlatformPathSubFolder());
    Directory.CreateDirectory(assetPath);
    }
    }
    else
    Directory.CreateDirectory(assetPath);

    var path = Path.Combine(assetPath, "addressables_content_state.bin");
    return path;
    }

抽取热更打包功能

  1. 修改 AddressableAssetsSettingsGroupEditor 添加函数 OnUpdateBuildCustom
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /// <summary>
    /// 自定义热更打包
    /// </summary>
    /// <param name="binPath">热更记录文件路径</param>
    public static void OnUpdateBuildCustom(string binPath)
    {
    if (!string.IsNullOrEmpty(binPath))
    ContentUpdateScript.BuildContentUpdate(AddressableAssetSettingsDefaultObject.Settings, binPath);
    }

修改build的bin目录

  1. 修改BuildScriptPackedMode函数DoBuild
    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
    // 新加
    public static string addressables_content_state_path = "";

    /// <summary>
    /// The method that does the actual building after all the groups have been processed.
    /// </summary>
    /// <param name="builderInput">The generic builderInput of the</param>
    /// <param name="aaContext"></param>
    /// <typeparam name="TResult"></typeparam>
    /// <returns></returns>
    protected virtual TResult DoBuild<TResult>(AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult
    {
    ExtractDataTask extractData = new ExtractDataTask();
    List<CachedAssetState> carryOverCachedState = new List<CachedAssetState>();
    var tempPath = Path.GetDirectoryName(Application.dataPath) + "/" + Addressables.LibraryPath + PlatformMappingService.GetPlatformPathSubFolder() + "/addressables_content_state.bin";

    // 新加
    if (!string.IsNullOrEmpty(addressables_content_state_path))
    {
    // 自定义生成路径
    tempPath = addressables_content_state_path;
    }

    ...
    }

bundle加密

  1. 修改 AssetBundleProviderGetAssetBundle函数
    1
    2


链接

http://github.com/favoyang/unity-addressable-importer

项目代码:https://gitee.com/hahafox_0/unity-tutorial-addressable.git
使用参考:https://czhenya.blog.csdn.net/article/details/126873219
工具参考:https://blog.csdn.net/Czhenya/article/details/126679181