Version: 2023.2
修补 AssetBundle
AssetBundle 下载的完整性和安全性

故障排除

Tips for Investigating AssetBundle Build results

The following methods can be useful for collecting information after an AssetBundle build has run. These can be useful when investigating unexpected behavior, or when tuning the assignment of assets to bundles.

Logs

The Unity Editor log collects information during a build, such as warning or error messages. And at the end of an AssetBundle build there is a detailed message logged that shows information about the type and size breakdown for each AssetBundle.

Build Report

AssetBundle builds generate a BuildReport which is a Unity SerializedFile written to Library/LastBuild.buildreport inside the project directory. This file is useful for seeing a summary of the timings for build steps and a detailed view of the contents of the AssetBundle. The BuildReport API can be used to read information from the BuildReport file.

Two unsupported tools are available for viewing the content of the BuildReport:

.manifest files

The manifest files generated alongside each AssetBundle give some human-readable details about the contents of an AssetBundle.

Clean Builds

To speed up iteration time Unity supports incremental building for AssetBundles. For example, elements from past builds can be reused for aspects of the project that have not changed since the last build. While this can speed up iteration time, there are a few limitations on its ability to detect changes in the input, especially if scripts run by build callbacks are changing data in a non-deterministic way. Therefore, you should always perform a clean build rather than an incremental build when you are building an official release of your AssetBundles.

The BuildAssetBundleOptions.ForceRebuildAssetBundle flag, passed as an option to BuildPipeline.BuildAssetBundles(), is the recommended way to perform a clean build.

In some rare cases it might also be desirable to erase the Library/ShaderCache directory. This cache is not flushed when BuildAssetBundleOptions.ForceRebuildAssetBundle is specified. On many projects the Shader compilation phase can be quite a time consuming step, so erasing the cache can add a lot of time to the next Player or AssetBundle build.

Alternatively, the most reliable way to perform a completely clean build is to stop Unity, erase the project’s Library directory, and then restart Unity. This can be very time consuming because all the project Assets need to be reimported and other data is regenerated.

Examining AssetBundle contents

In some cases you might want to look directly inside an AssetBundle, or compare the contents of two AssetBundles.

The Unity Editor installation includes the WebExtract and Binary2Text executables. You can use WebExtract to extract the files that are nested inside the AssetBundle, similar to extracting a zip file. Then you can use Binary2Text to produce a text format dump of the contents of a binary SerializedFile. Its output is somewhat similar to the yaml format used by Unity.

Another similar mechanism to see the content of an AssetBundle’s SerializedFiles in text form is to run UnityDataTools with its “dump” argument.

The raw content of Serialized files tends to be very technical and very large, especially when Shaders or Meshes or binary data is present. But these dumps can also provide a wealth of information if you can narrow down a problem to specific objects within a file. Comparing the extracted content of two similar AssetBundles using a diff tool can be a convenient way to narrow down the precise differences.

Target Switching

The arguments to the BuildPipeline.BuildAssetBundles API lets you specify the target (and subtarget) platform where you will be deploying the AssetBundles.

It is possible the requested platform is different from what is currently configured on the Build Settings dialog. However you should always make sure the settings in the Build Settings match the settings for your AssetBundle build, prior to triggering your build script. When the targets don’t match, Unity must recompile the Editor scripts to reflect the new platform and also potentially trigger imports for Assets like textures that have platform specific representations. Then at the end of the build it will restore the state back to match the original target platform. Typically this works fine, but it can add significant time to each build, which can add up when performing a lot of build iterations. Furthermore the script that contains the call to BuildPipeline.BuildAssetBundles will continue to execute in the script domain as compiled for the current target, not the specified build target. This is only a problem if the build script, or callback scripts, expects platform-specific code or assemblies to be available. For many projects this subtle difference will not be an issue. But to help avoid this sort of pitfall you should always make sure that any code executed during a build checks the target dynamically (e.g. with if statements) instead of using platform conditional compilation (#ifdef statements).

For command line builds the --buildTarget command line argument should be used to match the target you want to build.

Asset Duplication

Unity’s AssetBundle system will discover all dependencies of an Object when the Object is built into an AssetBundle. This is done using the Asset Database. This dependency information is used to determine the set of Objects that will be included in an AssetBundle.

Assignment to AssetBundles happens at the Asset level. The Objects inside an Asset that is explicitly assigned to an AssetBundle will only be built into that single AssetBundle. Depending which signature of BuildPipeline.BuildAssetBundles is called, an Asset is “explicitly assigned” either by setting the Asset’s AssetImporter.assetBundleName property to a non-empty string, or by listing it in AssetBundleBuild.assetNames.

Any Object that is part of an Asset that is not explicitly assigned in an AssetBundle will be included in each AssetBundle that contains any Objects that reference it.

In other words, if two different Objects are assigned to two different AssetBundles, but both have references to a common dependency Object, then that dependency Object will be copied into both AssetBundles. The duplicated dependency will also be instanced, meaning that the two copies of the dependency Object will be considered different Objects with a different identifiers. This will increase the total size of the application’s AssetBundles. This will also cause two different copies of the Object to be loaded into memory if the application loads both of its parents.

有几种方法可以解决这个问题:

  1. 确保构建到不同 AssetBundle 中的对象不共享依赖项。任何共享依赖项的对象都可以放在同一个 AssetBundle 中,而不会复制它们的依赖项。

    • 对于具有许多共享依赖项的项目,此方法通常不可行。这种情况下可能生成单独的 AssetBundle,必须高度频繁进行重建和重新下载,因此很不方便或高效。
  2. 对 AssetBundle 进行分段,确保不会同时加载两个共享依赖项的 AssetBundle。

    • This method may work for certain types of projects, such as level-based games. However there is still a trade-off, because duplicated objects will increase the build time and sizes of the project’s AssetBundles, and could impact loading times.
  3. 确保所有依赖项资源都构建到自己的 AssetBundle 中。这样可以完全消除重复资源的风险,但也带来了复杂性。应用程序必须跟踪 AssetBundle 之间的依赖关系,并确保在调用任何 AssetBundle.LoadAsset API 之前加载了正确的 AssetBundle。

Object dependencies are tracked via the AssetDatabase API, located in the UnityEditor namespace. As the namespace implies, this API is only available in the Unity Editor and not at runtime. AssetDatabase.GetDependencies can be used to locate all of the immediate dependencies of a specific Object or Asset. Note that these dependencies may have their own dependencies so this can be a recursive calculation. The assignment of Assets to AssetBundles will either be defined explicitly by passing arrays of AssetBundleBuild structures when calling BuildPipeline.BuildAssetBundles, or can be queried using the AssetImporter API. It is possible to write an Editor script that ensures that all of an AssetBundle’s direct or indirect dependencies are assigned to AssetBundles, or that no two AssetBundles share dependencies that have not been assigned to an AssetBundle.

Note: When building AssetBundles with the Addressables package, the Addressables Analyze window can be used to discover duplicated assets.

Sprite Atlas Duplication

The following sections describe a quirk of asset dependency calculation code when used in conjunction with automatically-generated sprite atlases.

任何自动生成的精灵图集都将与生成精灵图集的精灵对象一起分配到同一个 AssetBundle。如果精灵对象被分配给多个 AssetBundle,则精灵图集将不会被分配给 AssetBundle 并且将被复制。如果精灵对象未分配给 AssetBundle,则精灵图集也不会分配给 AssetBundle。

为了确保精灵图集不重复,请确保标记到相同精灵图集的所有精灵都被分配到同一个 AssetBundle。

Android Textures

Due to heavy device fragmentation in the Android ecosystem, it’s often necessary to compress textures into several different formats. While all Android devices support ETC1, ETC1 doesn’t support textures with alpha channels.

To use AssetBundle Variants, all textures that can’t be cleanly compressed using ETC1 must be isolated into texture-only AssetBundles. Next, create sufficient variants of these AssetBundles to support the non-ETC2-capable slices of the Android ecosystem, using vendor-specific texture compression formats such as DXT5, PVRTC. For each AssetBundle Variant, change the included textures’ TextureImporter settings to the compression format appropriate to the Variant.

在运行时,可以使用 SystemInfo.SupportsTextureFormat API 检测对不同纹理压缩格式的支持情况。应使用此信息来选择和加载含有以受支持格式压缩的纹理的 AssetBundle 变体。

有关 Android 纹理压缩格式的更多信息,请查看此处

Interactions between Shaders and AssetBundles

When you build an AssetBundle, Unity uses information in that bundle to select which shader variants to compile. This includes information about the scenes, materials, Graphics Settings, and ShaderVariantCollections in the AssetBundle.

Separate build pipelines compile their own shaders independently of other pipelines. If both a Player build and an Addressables build reference a shader, Unity compiles two separate copies of the shader, one for each pipeline.

This process doesn’t account for any runtime information such as keywords, textures, or changes due to code execution. If you want to include specific shaders in your build, either include a ShaderVariantCollection with the desired shaders, or include the shader in your build manually by adding it to the Always Included Shaders list in your graphics settings.

修补 AssetBundle
AssetBundle 下载的完整性和安全性