为什么需要 WebView

有的页面更新快、样式重,原生重写成本高;有的内容就是网页本身。鸿蒙的 Web 组件(WebView)让你在应用里嵌入网页,还能和原生互相调方法,这就是混合开发。

原生负责系统能力,网页负责内容与速度。

适合的场景:活动页、富文本详情、后台可配置页面、需要复用既有 Web 资产的模块。不适合:强交互、强动效、重列表的页面,这些用原生或 ArkUI 更稳。

Web 组件基础

Web 组件直接用 ArkUI 声明:给定 src 就能加载页面,支持网络地址和本地资源。加载状态用 onPageEnd 等回调观察。

@Entry
@Component
struct WebPage {
  controller: WebviewController = new WebviewController()
  build() {
    Column() {
      Web({ src: 'https://example.com/article', controller: this.controller })
        .javaScriptAccess(true)
        .onPageEnd(() => {
          console.info('页面加载完成')
        })
    }
  }
}
Web 组件要点
  • src支持 https 与本地资源。
  • javaScriptAccess控制 JS 开关。
  • controller执行前进后退刷新。

JSBridge 双向通信

网页要调原生能力(拍照、分享、定位),原生要往网页传数据,靠的是双向桥:原生通过 registerJavaScriptProxy 注册方法给网页,网页用 runJavaScript 调原生。

// 原生注册给网页的方法
this.controller.registerJavaScriptProxy({
  objectName: 'nativeBridge',
  methodList: ['getToken', 'shareText'],
  controller: this.controller
})

// 原生往网页执行 JS
this.controller.runJavaScript('window.showToast("来自原生")')
鸿蒙 WebView:发光浏览器窗口内嵌页面布局方块、底部数据流连接后端节点的蓝调插画
浏览器窗口与原生能力互联。

桥的名字要约定好,参数传 JSON 字符串最稳。方法名别和网页自带方法冲突,注册时机要在 onPageBegin 之前完成,否则首屏调用会扑空。

加载与生命周期

Web 组件有自己的生命周期:onPageBegin、onPageEnd、onError、onProgressChange。页面切走时记得暂停加载和媒体,回来再恢复,省电省流量。

Web({ src: url, controller: this.controller })
  .onError((error) => {
    console.error('加载失败', JSON.stringify(error))
  })
  .onProgressChange((progress) => {
    if (progress === 100) {
      console.info('加载完成')
    }
  })

加载失败给用户一个重试入口,别只留白屏。进度回调配合 loading 状态,体验会好很多。

页面加载策略要提前想好:首屏用本地壳页面占位,数据到齐再切换内容;加载中显示骨架屏而不是白屏;失败给重试按钮,并区分网络错误和服务器错误,给用户明确的下一步。Web 组件内存占用不小,页面栈里不要同时挂太多 Web 实例,切走就销毁、回来再建。还有一点常被忽略:WebView 的滚动和原生滚动手感不同,长列表、强交互的页面尽量用原生实现,把 WebView 留给内容型页面,性能体验才不会分裂。

调试时开启 Web 组件的开发者调试开关,配合 DevTools 看网络请求与 DOM 结构,能省掉不少"网页正常、应用里不对"的排查时间。上线前记得把调试开关关掉,避免暴露内部页面和接口。