为什么需要 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('页面加载完成')
})
}
}
}
- 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("来自原生")')
桥的名字要约定好,参数传 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 结构,能省掉不少"网页正常、应用里不对"的排查时间。上线前记得把调试开关关掉,避免暴露内部页面和接口。
安全与权限
WebView 是攻击面:加载不可信内容、放开 JS 开关、暴露敏感桥方法都可能出问题。只加载 https,只对可信域名开放 JS 桥。
Web({ src: url, controller: this.controller })
.fileAccess(false)
.mixedMode(MixedMode.None)
.javaScriptAccess(true)
桥方法要做来源校验,参数做白名单;不要在桥里透传 token 给任意网页。用户输入的 URL 先校验协议,防止跳转钓鱼页面。
实战:WebView 缓存优化
首屏要快,缓存是关键。设置 WebView 缓存模式、开启 DOM 存储,再配合资源预加载,重复进入的页面能省一大截加载时间。
Web({ src: url, controller: this.controller })
.cacheMode(WebCacheMode.Default)
.domStorageAccess(true)
本地化更强的做法:把活动页的静态资源打成离线包,冷启动时优先读本地,再后台拉更新。页面切换时用 controller 控制前进后退,而不是重新创建组件。
小结
WebView 让鸿蒙应用随时接入网页能力:Web 组件加载页面、registerJavaScriptProxy 给网页开桥、runJavaScript 往回传数据。安全上锁死 https、校验来源;性能上靠缓存和离线包。混合不是把一切都塞进网页,而是原生与网页各干各擅长的事。