HarmonyOS鸿蒙Next中web组件加载本地沙箱中的html时,html文件里面有引用其他沙箱中文件时是否可以正常引用呢

HarmonyOS鸿蒙Next中web组件加载本地沙箱中的html时,html文件里面有引用其他沙箱中文件时是否可以正常引用呢 【问题描述】:我们资料都是从后台获取下载到本地的,然后用web组件去加载html文件,这个html里面还有请求加载了其他文件,例如.gltf后缀的文件和.txt的文件,但是其他文件是没加载出来的,只是加载了html的静态文件看起来

【问题现象】:只是加载了html的静态文件,html文件中请求的其他文件显示不了

11 回复

开发者您好,html文件里面有引用其他沙箱中文件时,会引发本地资源跨域问题,开发者可以参考这个文档解决跨域问题:本地资源跨域,通过setPathAllowingUniversalAccess()设置一个路径列表;另外,开发者可以使用DevTools工具调试前端页面,查看页面具体是报了什么错误。

更多关于HarmonyOS鸿蒙Next中web组件加载本地沙箱中的html时,html文件里面有引用其他沙箱中文件时是否可以正常引用呢的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


以下是详细的原因分析和解决方案:

核心原因分析

  1. 协议限制(file:// vs data:// vs http://)

    • 当你使用 controller.loadUrl('file:///data/.../index.html') 加载时,浏览器的安全沙箱机制会限制该页面对同级目录下其他文件的访问,或者跨目录访问。
    • 特别是对于 gltf 这种通常通过 XMLHttpRequestfetch 异步加载的模型文件,在 file:// 协议下极易被拦截,导致 404 或网络错误。
  2. 路径解析错误

    • HTML 中引用的相对路径(如 ./model.gltf)是相对于 HTML 文件本身的。如果 Web 组件的“基准路径”设置不对,它会去错误的目录寻找资源。
  3. 资源访问权限

    • 鸿蒙的 Web 组件默认禁止访问任意本地文件,需要显式开启 setAllowFileAccesssetAllowUniversalAccessFromFileURLs

解决方案

请按照以下步骤逐一排查和修复:

1. 开启 Web 组件的本地文件访问权限(必须)

在你的 ArkTS 代码中,必须配置 WebControllerWeb 组件的属性,允许文件访问:

Web({ src: $rawfile('your_html_path'), controller: this.controller })
  .javaScriptAccess(true) // 必须开启JS,否则gltf的js加载器无法运行
  .zoomAccess(false)
  .fileAccess(true) // 【关键】开启文件访问权限
  .domStorageAccess(true) // 【关键】开启DOM存储
  .mixedMode(MixedMode.All) // 【关键】允许混合模式,允许file协议加载http资源或加载本地资源
  .onReady(() => {
      // 监听页面加载完成
  })

注意: 最关键的是 .fileAccess(true).mixedMode(MixedMode.All)

2. 使用正确的路径加载方式

不要使用绝对路径字符串硬编码,建议使用相对路径逻辑。

场景A:HTML和图片都在沙箱目录(Context.filesDir)

确保你的目录结构如下:

/data/storage/el2/base/haps/entry/files/
├── index.html
├── model.gltf
└── texture.png

index.html 中,引用必须是相对路径:

<!-- 正确 -->
<img src="texture.png">
<script src="model-loader.js"></script>

<!-- 错误(除非你确定绝对路径) -->
<img src="file:///data/.../texture.png">

场景B:HTML在沙箱,但资源加载失败(推荐方案:本地服务器)

如果 gltf 文件依然加载不出来(因为 gltf 内部通常是 JSON,会发起 Ajax 请求读取 bin/图片,而 file 协议禁止 Ajax),最稳妥的方案是启动一个轻量级本地 HTTP 服务器

  • 原理:在鸿蒙应用内启动一个 HttpServer(可以使用 @ohos.net.http 实现或第三方库),将沙箱目录映射为 http://127.0.0.1:8080/
  • 加载:Web 组件加载 http://127.0.0.1:8080/index.html
  • 优势:彻底解决跨域、文件协议限制、Ajax 读取本地文件失败的问题。

3. 针对 GLTF 文件的特殊处理

Gltf 文件本质上是一个 JSON,它加载后还会去请求 .bin 文件和纹理图片。

如果必须用 file:// 协议加载:

  1. 确保路径分隔符:HTML 中必须使用 / 而不是 \
  2. MIME 类型问题:Web 组件在读取本地 .gltf.bin 文件时,可能无法识别 MIME 类型。
    • 解决方法:将 .gltf 转为 .glb(二进制格式,包含所有资源),这样就是一个单独的文件,Web 组件加载它时就不会去请求外部文件,成功率极高。

总结建议

  1. 首选尝试:在 Web 组件属性中添加 .fileAccess(true).mixedMode(MixedMode.All),并确保 HTML 内部使用相对路径。
  2. 如果涉及复杂 3D (gltf):强烈建议将资源合并为 GLB 格式,避免多文件引用问题。
  3. 终极方案:如果上述都失败,在应用内嵌一个 Local Http Server,通过 http://localhost 协议加载本地沙箱文件,这是兼容性最好的方式。

核心原因是 Web 组件的安全沙箱隔离了被引用的文件

解决办法:

  1. loadDataWithBaseUrl 指定正确 baseUrl

  2. fileAccess(true) 开启文件访问

  3. onInterceptRequest 兜底拦截放行

    注意点,下面的配置是必须的

    Web({ ... })
     .fileAccess(true) // ★ 允许访问本地文件
     .domStorageAccess(true) // ★ 允许 localStorage
     .javaScriptAccess(true) // ★ 允许 JS
     .mixedMode(MixedMode.All) // ★ 允许加载 HTTP 资源(如果有远程的)
    

    module.json5 里也要加权限

    "name": "ohos.permission.INTERNET"
    

加载失败原因,本地资源跨域:

通过本地文件系统直接打开HTML页面,并访问同目录下的本地脚本、样式或图片等资源的情况。这时,浏览器会因为协议不同而判定为跨域,从而触发安全限制,导致资源加载失败。

解决方案:

一、通过 setPathAllowingUniversalAccess() 设置一个路径列表。当使用file协议访问该列表中的资源时,允许进行跨域访问本地文件。

// xxx.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: WebviewController = new webview.WebviewController();
  uiContext: UIContext = this.getUIContext();

  build() {
    Row() {
      Web({ src: "", controller: this.controller })
        .onControllerAttached(() => {
          try {
            // 设置允许可以跨域访问的路径列表
            this.controller.setPathAllowingUniversalAccess([
              this.uiContext.getHostContext()!.resourceDir,
              this.uiContext.getHostContext()!.filesDir + "/example"
            ])
            this.controller.loadUrl("file://" + this.getUIContext().getHostContext()!.resourceDir + "/index.html")
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
        .javaScriptAccess(true)
        .fileAccess(true)
        .domStorageAccess(true)
    }
  }
}

二、使用 WebServer 直接在沙箱目录开启一个本地静态服务器,使用 [http://192.168.2.x:8080/index.html] 加载本地H5。

出于安全考虑,Web内核默认禁止通过 file:// 协议进行跨域请求。简单说,就是你的主HTML文件在一个“虚拟位置”,它想去请求另一个“虚拟位置”的 model.gltf 文件,被浏览器的同源策略给拦下了。

两种方案都可以解决,你可以根据项目情况选择:

方法 核心思路 优点 缺点
方法一:自定义域名 + 资源拦截 (灵活) 使用 https:// 等协议加载,通过 onInterceptRequest 拦截请求,手动返回本地文件。 最灵活,可以精细控制每一个网络请求。 需要为每个资源编写拦截代码,工作量大。
方法二:设置路径白名单 (推荐) 使用 setPathAllowingUniversalAccess API,把存放资源的文件夹加入白名单,允许跨域访问。 简单高效,一次配置,全局生效。 仅支持配置特定的应用目录。

可能你要到AGC配置服务器域名:

进入域名配置页:

左侧导航选择 “域名配置” > “服务器域名”页签1。

修改域名:

点击 “修改”,在弹框中按类型填写域名:

httpRequest:以 https://开头(如 https://api.example.com)。

webSocket:以 wss://开头(如 wss://push.example.com)。

download/upload:以 https://开头,端口需显式声明(如 https://cdn.example.com:8080)。

提交后生效。

可以引用

但你这个 .gltf / .txt 场景,大概率是 fetch / XHR / three.js loader 这类“运行时请求”被本地 file:// 或等效本地来源限制住了。

.gltf 往往是通过 GLTFLoader 发请求读取,它们不是纯静态展示,而是 JS 主动请求本地资源。

在本地页面场景下,这类请求经常会遇到:

  • 本地来源限制
  • 同源/CORS 风格限制
  • Web 组件不允许直接访问某些沙箱路径
  • 资源路径基准不对
  • 返回的 MIME type 不对

建议排查一下

HarmonyOS的开发者模式提供了很多实用的工具,方便我们进行调试和优化。

可以将html中使用的沙箱文件放到rawfile目录里直接使用比较方便。

可以。在HarmonyOS NEXT中,通过Web组件加载本地沙箱中的HTML文件时,若HTML内引用的其他文件(如JS、CSS、图片等)也位于同一沙箱目录或子目录,且路径使用相对路径,则可以正常引用。需确保Web组件已获取对应沙箱路径的读取权限。

在HarmonyOS Next中,Web组件加载本地沙箱内的HTML时,能否正确引用其他沙箱文件,取决于路径传递方式。直接使用相对路径或沙箱文件路径可能失败。

核心原因

Web组件的沙箱机制限制了文件访问权限。HTML文件自身在沙箱内,但Web组件内部的JavaScript发起的网络请求或文件加载(如fetchXMLHttpRequest<img><script>等)默认遵循同源策略,且本地沙箱路径不被视为标准文件URL。

解决方案方向

  • 路径格式:将HTML文件以及所有引用的附属文件(.gltf、.txt等)放在同一个沙箱子目录下,使用相对路径(如./model.gltf)。不跨目录引用。
  • 路由映射:若需跨目录或使用非相对路径,需通过Web组件的onInterceptRequest接口拦截请求,重定向到沙箱对应文件。这是官方推荐方案。
  • 文件协议:避免使用file://协议直接引用其他沙箱路径,因为Web组件的WebView引擎可能不支持或受限。

实际表现

你描述的“只加载了HTML静态文件,其他文件未显示”正是因跨目录或路径不被解析所致。常见于.gltf这类通过AJAX或WebGL请求的文件。

验证方式

  • 确保所有文件在同一个沙箱子目录下,HTML使用相对路径。
  • 若仍失败,通过webview.onInterceptRequest手动拦截所有资源请求,返回沙箱文件内容。

简言之:统一目录+相对路径是基础;跨目录需手动拦截映射。

回到顶部