Unity Addressables 加载失败:路径变量未替换导致的 404 错误分析与解决
- 问题详情
- 错误原因分析
-
- [Addressables 路径变量替换机制](#Addressables 路径变量替换机制)
- [为什么 `{UnityEngine.Application.version}` 没有被替换?](#为什么
{UnityEngine.Application.version}没有被替换?)
- 解决方法
-
- [使用 `AddressablesRuntimeProperties.SetPropertyValue`](#使用
AddressablesRuntimeProperties.SetPropertyValue) - 为什么这行代码能生效?
- 最佳实践:何时设置属性值?
- [使用 `AddressablesRuntimeProperties.SetPropertyValue`](#使用
- [深入理解:Addressables 属性解析流程](#深入理解:Addressables 属性解析流程)
- 总结与建议
问题详情
在项目中使用 Unity Addressables 进行资源远程加载时,运行时出现了如下错误日志:
Web request failed to load from cache. The cached AssetBundle will be cleared from the cache and re-downloaded. Retrying...
ProtocolError : HTTP/1.1 404 Not Found
ResponseCode : 404, Method : GET
url : https://czy-download.oss-cn-beijing.aliyuncs.com/czhenya_test/Android/UnityEngine.Application.version/aotassembly_assets_all_29933893036cf97ad685fa8b88a57497.bundle
紧接着是更详细的异常:
RemoteProviderException : Unable to load asset bundle from : https://czy-download.oss-cn-beijing.aliyuncs.com/czhenya_test/Android/UnityEngine.Application.version/aotassembly_assets_all_29933893036cf97ad685fa8b88a57497.bundle
UnityWebRequest result : ProtocolError : HTTP/1.1 404 Not Found
仔细观察请求的 URL,发现其中包含了一个奇怪的路径段:UnityEngine.Application.version。而在 Addressables 面板中配置的远程加载路径为:
https://czy-download.oss-cn-beijing.aliyuncs.com/czhenya_test/[BuildTarget]/{UnityEngine.Application.version}
显然,运行时并没有将 {UnityEngine.Application.version} 替换为实际的应用程序版本号(例如 1.0.0),而是保留了字面量字符串,导致服务器返回 404 错误。
错误原因分析
Addressables 路径变量替换机制
Addressables 允许在配置文件(如远程加载路径)中使用大括号包裹的变量 (例如 {UnityEngine.Application.version}),在运行时这些变量会被替换为实际的值。这种机制非常有用,可以根据平台、版本等动态生成资源 URL。
变量替换的核心是 AddressablesRuntimeProperties 类 。当 Addressables 需要解析路径中的变量时,它会通过 AddressablesRuntimeProperties.EvaluateProperty 或类似方法获取变量的值。默认情况下,Addressables 内置了一些系统属性的解析逻辑,例如 [BuildTarget] 会被替换为当前平台的名称(如 Android、iOS 等)。但对于自定义变量或一些 Unity 运行时属性(如 UnityEngine.Application.version),则需要开发者主动注册或设置值。
为什么 {UnityEngine.Application.version} 没有被替换?
从错误日志中可以看到,变量名称 UnityEngine.Application.version 没有被任何值替换,直接作为字符串拼接到了 URL 中。这通常意味着在 Addressables 尝试解析该变量时,没有找到对应的属性提供者(Property Provider)。
Addressables 提供了多种方式来定义属性值:
- 通过代码设置 :使用
AddressablesRuntimeProperties.SetPropertyValue(string name, string value)。 - 通过全局属性提供者 :实现
IPropertyProvider接口并添加到AddressablesRuntimeProperties中。 - 从编译常量或环境变量中获取(但需要自定义)。
在项目启动时,如果开发者没有预先设置 UnityEngine.Application.version 的值,Addressables 解析器就会认为该变量不存在,从而保留原始字符串。这正是本次错误的根源。
解决方法
使用 AddressablesRuntimeProperties.SetPropertyValue
用户通过添加一行代码解决了问题:
csharp
AddressablesRuntimeProperties.SetPropertyValue("UnityEngine.Application.version", Application.version);
这行代码的作用是显式地告诉 Addressables 属性系统:当遇到名为 UnityEngine.Application.version 的变量时,请使用 Application.version 的当前值进行替换。
为什么这行代码能生效?
- 提前注册 :在 Addressables 开始加载任何资源(包括初始化操作)之前,调用
SetPropertyValue将属性名与值绑定。这样当后续加载流程中解析路径时,就可以正确找到该属性。 - 覆盖默认行为 :即使 Addressables 内部可能已经尝试解析该变量,通过
SetPropertyValue注册的优先级高于隐式解析(如果有的话),确保变量被替换为正确的版本号。
需要注意的是,SetPropertyValue 的设置是全局的,并且会持续整个进程生命周期。一旦设置,后续所有对同一属性的查询都会返回设定的值。
最佳实践:何时设置属性值?
为了确保资源加载不出错,应该在 Addressables 初始化之前完成必要属性的注册。通常可以在游戏启动的最早期,例如在 Awake 或 Start 中,甚至在 Addressables 的初始化回调之前执行。
csharp
void Awake()
{
// 设置版本号变量,以便 Addressables 正确构建远程路径
AddressablesRuntimeProperties.SetPropertyValue("UnityEngine.Application.version", Application.version);
// 然后进行 Addressables 初始化或其他资源加载
Addressables.InitializeAsync();
}
深入理解:Addressables 属性解析流程
Addressables 的路径变量解析依赖于 AddressablesRuntimeProperties 类的静态方法 EvaluateString(string, char, char)。该方法会扫描字符串中的 {...} 模式,并将匹配的内容作为属性名进行查找。查找顺序大致如下:
- 检查是否已经通过
SetPropertyValue设置了该属性的值。 - 检查是否注册了自定义的
IPropertyProvider,并尝试从这些提供者中获取值。 - 如果仍然找不到,则返回原始字符串(即不替换)。
因此,如果开发者没有在步骤1或步骤2中提供值,变量将保持原样,导致路径错误。
总结与建议
问题总结
- 现象 :Addressables 加载远程资源时出现 404,URL 中包含未替换的变量名
UnityEngine.Application.version。 - 原因:运行时未设置对应属性值,变量未被正确替换。
- 解决 :在 Addressables 初始化前调用
AddressablesRuntimeProperties.SetPropertyValue注册版本号。
避坑指南
- 明确变量的作用域:Addressables 面板中使用的变量并非自动获取 Unity 的运行时属性,需要手动注册。
- 尽早注册:任何依赖属性的资源加载操作都必须在属性设置之后进行。
- 调试技巧:如果遇到类似的 404 错误,可以先检查实际请求的 URL 是否包含未替换的变量名。如果是,则说明属性解析失败。