摘要

Web 组件(WebView)用于应用内直接加载在线网页、本地 HTML 静态页面,可实现内嵌 H5 商城、帮助文档、第三方活动页、网页表单等业务,无需跳转系统浏览器。API Version23 重构 Web 内核渲染、JS 与 ArkUI 双向通信、缓存管理、页面资源释放逻辑,修复低版本网页白屏、JS 调用原生失效、页面返回栈错乱、退出页面内存残留、文件下载无响应等兼容缺陷。旧项目升级 API23 后常出现:网页加载空白、H5 无法调用应用原生方法、多次打开 Web 页面卡顿、返回键直接退出 APP、缓存堆积占用存储等问题。本文基于 DevEco Studio 适配 OpenHarmony API23 及以上版本,封装 Web 通用工具类,实现网页加载、JS 桥双向交互、网页返回拦截、缓存清理、本地静态页面加载五大核心能力,搭配内嵌资讯网页、H5 交互页面两套实战代码,输出权限配置、资源销毁、JS 通信安全规范,汇总版本升级兼容故障解决方案,为鸿蒙内嵌网页业务提供标准化实操模板。

关键词

OpenHarmony;ArkUI;API Version23;Web;WebView;内嵌网页;JS 桥;网页原生交互

一、引言

1.1 Web 组件开发背景

大量应用存在 H5 混合开发需求,活动页、客服页面、用户协议、外部资讯都适合使用 Web 内嵌展示。Web 组件基于系统 Chromium 内核,支持标准 HTML/CSS/JS,同时提供 JSBridge 实现 H5 与 ArkUI 原生代码互相调用,打通网页与应用本地能力(弹窗、路由跳转、本地存储、相机)。 OpenHarmony API Version23 针对 Web 内核引擎完成全面升级,核心变更点:

  1. 标准化 WebController 生命周期,页面销毁强制销毁内核实例,杜绝内存泄漏;
  2. 重构 JS 与 ArkUI 双向调用通道,修复函数传参丢失、异步回调失效;
  3. 优化网页缓存、Cookie 隔离机制,不同 Web 实例缓存互不干扰;
  4. 新增返回栈独立管理,拦截网页返回事件,区分页面回退与 APP 退出;
  5. 强化网络权限校验,明文 http 网页新增单独白名单控制;
  6. 统一本地 assets 静态 HTML 加载接口,修复本地资源路径读取失败。

大量 API9~11 旧项目升级后,网页白屏、H5 调用原生无响应、返回键直接关闭应用,根源是未管控 WebController 生命周期、未拦截页面返回事件,因此掌握 API23 标准 Web 组件封装规范是混合开发必备技能。

1.2 开发环境与测试场景

开发工具:DevEco Studio 5.0 及以上 适配系统:OpenHarmony API Version23、HarmonyOS NEXT 导入模块:@ohos.web.webview 前置配置:INTERNET 网络权限、http 明文白名单(测试用) 测试场景:加载在线网址、加载本地 HTML、H5 调用原生弹窗、原生调用网页 JS、网页返回上一页、清除网页缓存

二、API23+ Web 组件核心 API 与版本变更说明

2.1 WebController 控制器(核心管理对象)

ets

import webview from '@ohos.web.webview'
// 创建网页控制器
webController: webview.WebController = new webview.WebController()

2.2 网页加载方法

  1. loadUrl (url):加载在线网址或本地文件路径
  2. loadData (data, mimeType, encoding, baseUrl):直接传入 HTML 字符串渲染

2.3 页面栈返回控制

  1. canGoBack ():判断网页是否存在上一页
  2. goBack ():网页内部回退,无历史记录不执行操作

2.4 JS 双向通信核心

  1. registerJavaScriptProxy ():注册 ArkUI 原生方法供 H5 调用
  2. runJavaScript ():ArkUI 主动执行网页内 JS 函数

2.5 缓存清理 API

webController.clearCache (true):清除全部网页缓存(true 同时删除磁盘缓存)

2.6 API23 废弃与强制约束

  1. 废弃页面不销毁 WebController 写法,aboutToDisappear 必须释放控制器;
  2. JS 注册代理必须在网页加载前完成,加载后注册会失效;
  3. 禁止无限制开启 JS,非可信外部网页建议关闭 JS 能力;
  4. 返回键事件必须自定义拦截,否则直接退出整个页面;
  5. 本地 HTML 资源统一放置 entry/src/main/resources/rawfile 目录;
  6. 多个 Web 页面需独立创建 WebController,不可全局共用控制器实例。

三、API23 标准基础示例代码

3.1 基础在线网页加载

ets

import webview from '@ohos.web.webview'

@Entry
@Component
struct SimpleWebPage {
  webCtrl: webview.WebController = new webview.WebController()

  build() {
    Web({ src: "https://www.openharmony.cn", controller: this.webCtrl })
      .width("100%")
      .height("100%")
      .javaScriptAccess(true) // 开启JS支持
  }

  aboutToDisappear() {
    // API23强制释放网页控制器,释放内核资源
    this.webCtrl.clearCache(true)
  }
}

3.2 H5 调用 ArkUI 原生方法基础通信

ets

import webview from '@ohos.web.webview'
import promptAction from '@ohos.promptAction'

@Entry
@Component
struct JsBridgeWeb {
  webCtrl: webview.WebController = new webview.WebController()

  aboutToAppear() {
    // 注册原生方法,供网页window.h5Bridge.showToast()调用
    this.webCtrl.registerJavaScriptProxy(
      { object: "h5Bridge", methodList: ["showToast"] },
      {
        showToast: (msg: string) => {
          promptAction.showToast({ message: msg })
        }
      }
    )
    this.webCtrl.refresh()
  }

  build() {
    Web({ src: "https://xxx测试页面", controller: this.webCtrl })
      .width("100%")
      .height("100%")
      .javaScriptAccess(true)
  }
}

四、两大业务完整实战案例(全兼容 API23)

4.1 实战一:Web 通用工具类封装(utils/web_util.ets)

ets

import webview from '@ohos.web.webview'
import promptAction from '@ohos.promptAction'

class WebUtil {
  private static instance: WebUtil

  static getInstance(): WebUtil {
    if (!WebUtil.instance) {
      WebUtil.instance = new WebUtil()
    }
    return WebUtil.instance
  }

  // 创建独立控制器实例
  createController(): webview.WebController {
    return new webview.WebController()
  }

  // 注册基础JS桥通用弹窗方法
  registerCommonProxy(controller: webview.WebController) {
    try {
      controller.registerJavaScriptProxy(
        {
          object: "nativeBridge",
          methodList: ["showToast", "closePage"]
        },
        {
          showToast: (text: string) => {
            promptAction.showToast({ message: text })
          },
          closePage: () => {
            router.back()
          }
        }
      )
    } catch (err) {
      console.error("JS代理注册失败", err)
    }
  }

  // 原生主动调用网页JS函数
  async callWebJs(controller: webview.WebController, jsFunc: string): Promise<string> {
    try {
      const res = await controller.runJavaScript(jsFunc)
      return res
    } catch (err)
      return ""
    }
  }

  // 清理网页缓存与Cookie
  clearWebCache(controller: webview.WebController) {
    controller.clearCache(true)
    controller.clearAllSslCache()
  }

  // 加载rawfile本地静态HTML
  loadLocalHtml(controller: webview.WebController, fileName: string) {
    const url = `$rawfile/${fileName}`
    controller.loadUrl(url)
  }
}

export default WebUtil.getInstance()

4.2 实战二:完整内嵌网页页面(返回拦截 + JS 桥 + 缓存释放)

ets

import webview from '@ohos.web.webview'
import WebUtil from '../utils/web_util'
import router from '@ohos.router'

@Entry
@Component
struct WebViewPage {
  webCtrl: webview.WebController = WebUtil.createController()
  url: string = "https://www.openharmony.cn"

  aboutToAppear() {
    // 初始化注册JS通信桥
    WebUtil.registerCommonProxy(this.webCtrl)
    this.webCtrl.loadUrl(this.url)
  }

  // 拦截系统返回键,优先网页内部回退
  onBackPress(): boolean {
    if (this.webCtrl.canGoBack()) {
      this.webCtrl.goBack()
      return true // 消费返回事件,不关闭页面
    }
    return false // 无网页历史,执行页面退出
  }

  // 原生主动调用网页JS示例按钮
  async callWebFunction() {
    // 执行网页内 window.receiveNativeMsg("来自应用原生调用")
    await WebUtil.callWebJs(this.webCtrl, `receiveNativeMsg("来自鸿蒙ArkUI原生消息")`)
  }

  build() {
    Column() {
      Row({ space: 10, height: 50 }) {
        Button("原生调用网页JS").fontSize(14).onClick(() => this.callWebFunction())
        Button("关闭页面").fontSize(14).backgroundColor("#f56c6c").onClick(() => router.back())
      }
      // 网页主体
      Web({ src: this.url, controller: this.webCtrl })
        .layoutWeight(1)
        .width("100%")
        .javaScriptAccess(true)
        .domStorageAccess(true) // 允许网页本地存储localStorage
    }
    .width("100%")
    .height("100%")
  }

  aboutToDisappear() {
    // 页面销毁清理缓存、释放内核资源
    WebUtil.clearWebCache(this.webCtrl)
  }
}

4.3 实战三:本地 rawfile 静态 HTML 加载页面

  1. 放置文件路径:entry/src/main/resources/rawfile/index.html
  2. 页面代码

ets

import webview from '@ohos.web.webview'
import WebUtil from '../utils/web_util'

@Entry
@Component
struct LocalHtmlPage {
  webCtrl: webview.WebController = WebUtil.createController()

  aboutToAppear() {
    WebUtil.registerCommonProxy(this.webCtrl)
    // 加载本地rawfile内静态页面
    WebUtil.loadLocalHtml(this.webCtrl, "index.html")
  }

  build() {
    Web({ src: "", controller: this.webCtrl })
      .width("100%")
      .height("100%")
      .javaScriptAccess(true)
  }

  aboutToDisappear() {
    WebUtil.clearWebCache(this.webCtrl)
  }
}

五、API23+ Web 组件适配与安全性能优化规范

5.1 控制器生命周期规范

  1. 每个 Web 页面独立 new WebController,禁止全局单例控制器多页面复用;
  2. 页面aboutToDisappear必须执行 clearCache 释放内核缓存资源;
  3. JS 代理注册放在 aboutToAppear,网页加载前完成注册,加载后注册失效。

5.2 JS 通信安全规范

  1. 外部不可信网页建议关闭javaScriptAccess(false),避免安全漏洞;
  2. 注册 JS 代理仅开放必要原生方法,不暴露数据库、文件等高权限接口;
  3. H5 传入参数增加判空、类型校验,防止注入异常代码。

5.3 返回键交互规范

  1. 页面重写 onBackPress 回调,优先执行网页 goBack;
  2. 网页无历史记录时再允许关闭当前页面,提升用户体验;
  3. 混合项目多层页面嵌套,统一封装路由 + Web 双层返回逻辑。

5.4 缓存与网络规范

  1. 频繁打开网页场景页面销毁清理缓存,减少存储占用;
  2. 线上业务全部使用 https,仅开发测试开启 http 明文白名单;
  3. 加载外部网址必须配置 module.json5 INTERNET 网络权限。

六、API23 升级高频兼容问题与解决方案

问题 1:网页打开空白,完全不渲染内容 解决:确认网络权限已配置,http 地址开启 cleartextTraffic 白名单;开启 javaScriptAccess。

问题 2:H5 调用原生 nativeBridge 方法提示不存在 解决:网页加载前完成 registerJavaScriptProxy 注册,刷新页面生效。

问题 3:按返回键直接退出整个页面,无法退回上一页网页 解决:重写页面 onBackPress,判断 canGoBack 优先执行网页 goBack。

问题 4:多次进出 Web 页面,应用存储占用持续上涨 解决:页面销毁调用 clearWebCache 清理磁盘与内存缓存,释放 WebController。

问题 5:runJavaScript 调用网页函数无返回结果 解决:网页 JS 函数需要 return 返回值,异步 JS 需用 Promise 包裹。

问题 6:加载本地 html 文件提示路径找不到 解决:静态 html 放入 rawfile 目录,使用 $rawfile / 文件名路径加载。

七、总结

Web 组件是 OpenHarmony 混合开发、内嵌 H5 页面标准方案,API Version23 重构 Web 内核资源生命周期、JS 桥双向通信、缓存回收底层逻辑,解决旧版网页白屏、JS 交互失效、返回逻辑错乱、内存持续占用等核心兼容问题。项目封装通用 Web 工具类,统一管理控制器创建、JS 代理注册、缓存清理、本地 HTML 加载,实现网页与 ArkUI 双向通信、返回拦截核心能力,适配活动页、用户协议、内嵌资讯、本地静态文档等业务场景。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐