场景背景
在鸿蒙系统的 H5 混合开发中,我们常使用 Web 组件加载本地离线资源。由于 ArkWeb 内核的安全策略限制,当 Web 内部发起网络请求访问 file 或 resource 协议的资源时,若涉及跨域访问,会被直接拦截。虽然通常建议后端处理 CORS,但鸿蒙官方提供了客户端层面的解决方案。
原因分析
ArkWeb 内核为了提高安全性,默认不允许 file 协议或 resource 协议访问 URL 上下文中来自跨域的请求。这意味着直接使用 resource:// 加载本地 HTML 后,JS 发起的 AJAX 请求若指向其他路径,会触发安全拦截。开发者可以在 DevTools 控制台中看到相关报错信息。
官方方案概述
华为官方文档提供了两种主要解决思路:
- 协议替换:将 file/resource 协议替换为 http/https 自定义域名,配合
onInterceptRequest拦截并替换本地资源。这种方式需要搭建简易服务,配置相对复杂。 - 路径白名单:通过设置允许跨域访问的路径列表,使 file 协议能访问指定目录下的资源。这是更轻量级的方案,适合纯本地资源场景。
实战步骤与坑点
在实际项目中,我采用了第二种方案(路径白名单),以下是具体的落地细节和需要注意的地方。
1. 目录结构调整
项目创建时,系统不会自动生成 resfile 文件夹。我们需要手动在 src/main/resources 下新建该目录,并将打包好的 H5 文件(dist 目录)放入其中。
确保目录结构如下:
src/main/resources/
└── rawfile/
└── resfile/
└── dist/
└── index.html
2. 初始化 Web 组件
加载页面时,初始 src 可以置空,避免立即加载导致后续配置失效。重点在于获取正确的资源路径。
// 构建 Web 组件,src 暂时为空
Web({ src: '', controller: this.webController })
.onControllerAttached(() => {
try {
// 关键步骤:设置允许跨域访问的路径列表
// 必须使用 getContext().resourceDir 拼接实际路径
const basePath = getContext().resourceDir + '/dist/index.html';
this.webController.setPathAllowingUniversalAccess([basePath]);
// 配置完成后,再加载具体页面
this.webController.loadUrl('resource://rawfile/resfile/dist/index.html#/xxxx');
} catch (error) {
console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
}
})
.javaScriptAccess(true)
.fileAccess(true)
.domStorageAccess(true);
3. 注意事项
- 路径格式:
setPathAllowingUniversalAccess接收的路径必须符合应用文件目录或资源目录的子目录规范。如果路径不合法,系统会抛出异常码 401。 - 执行顺序:务必先调用
setPathAllowingUniversalAccess设置白名单,再调用loadUrl加载页面。如果在加载后设置,可能无法生效。 - 资源目录:确保
getContext().resourceDir获取到的路径不为空,这依赖于resfile文件夹是否被正确识别为资源目录。
通过以上配置,即可在不修改后端的情况下,有效解决鸿蒙 WebView 混合开发中的本地资源跨域问题。

