HarmonyOS 6.0 WebView嵌入与交互
Hybrid开发模式在HarmonyOS NEXT里依然有一席之地。Web组件不是简单嵌个网页就完了——原生和Web的双向通信、JavaScript代理、导航控制、错误处理每一块都有专门的API。回调参数类型跟Web标准不一样这点坑过不少人。基础用法Web组件的创建需要配合WebviewControllerimport{webview}fromkit.ArkWeb;StatewebController:webview.WebviewControllernewwebview.WebviewController();Web({src:https://example.com,controller:this.webController}).width(100%).layoutWeight(1).javaScriptAccess(true)// 允许JS执行.domStorageAccess(true)// 允许DOM Storage.onlineImageAccess(true)// 允许加载网络图片.zoomAccess(true)// 允许缩放.overviewModeAccess(true)// 概览模式javaScriptAccess默认false这点跟Android WebView不一样。不手动开启的话页面里的JS全部不执行连onclick都不响应。回调类型最容易搞错的地方Web组件的事件回调参数类型跟直觉不同很多人第一次写都会用错类型// 错误写法.onPageBegin((event:string){...}).onPageEnd((event:string){...}).onErrorReceive((event:ErrorEvent){...})// 正确写法.onPageBegin((event:OnPageBeginEvent){this.addLog(开始加载: event.url);}).onPageEnd((event:OnPageEndEvent){this.addLog(加载完成: event.url);this.canGoBackthis.webController.accessBackward();this.canGoForwardthis.webController.accessForward();}).onErrorReceive((event:OnErrorReceiveEvent){this.addLog(错误: event.error.getErrorInfo());})onPageBegin的参数是OnPageBeginEvent有.url属性onPageEnd的参数是OnPageEndEvent有.url属性onErrorReceive的参数是OnErrorReceiveEvent不是ErrorEvent通过.error.getErrorInfo()获取错误信息onSslErrorReceive的参数是SslErrorEvent这些类型不需要额外import直接用就行。但用错类型编译会报错而且错误信息不一定能看出是类型名搞错了。导航控制WebviewController提供完整的导航能力// 前进后退判断letcanBack:booleanthis.webController.accessBackward();letcanForward:booleanthis.webController.accessForward();// 执行导航this.webController.backward();// 后退this.webController.forward();// 前进this.webController.refresh();// 刷新this.webController.clearHistory();// 清除历史// 加载URLthis.webController.loadUrl(https://example.com);// 加载本地文件this.webController.loadUrl($rawfile(index.html));accessBackward/accessForward只判断不执行backward/forward才真正跳转。在自定义导航栏里通常先check再actionButton(←).enabled(this.canGoBack).onClick((){this.webController.backward();})注意backward/forward是同步调用但页面加载是异步的。点击后退后URL不会立即变得等onPageEnd回调里再更新canGoBack/canGoForward。JavaScript代理原生→Web通信javaScriptProxy是在Web页面里注入原生对象让JS直接调用原生方法StatewebController:webview.WebviewControllernewwebview.WebviewController();aboutToAppear():void{this.webController.javaScriptProxy({object:this,name:nativeBridge,methodList:[showToast,getData,navigateTo],controller:this.webController});}// 被JS调用的方法必须是类的成员方法showToast(msg:string):void{// 显示原生Toast或弹窗this.addLog(JS调用showToast: msg);}getData():string{return来自原生的数据;}Web页面里这样调用// JS代码nativeBridge.showToast(Hello from Web);letdatanativeBridge.getData();methodList里声明的方法名必须和实际方法一一对应未声明的方法JS调用不到。方法参数和返回值会自动做类型转换但复杂对象建议用JSON字符串传递。runJavaScriptWeb→原生反向调用从原生侧执行Web页面里的JS代码this.webController.runJavaScript(document.title,(result:string){this.addLog(页面标题: result);});this.webController.runJavaScript(updateUI(new data),(result:string){this.addLog(JS执行结果: result);});runJavaScript是异步的回调在JS执行完后触发。回调参数是JS表达式的返回值字符串。这套机制构成了双向通信的闭环JS通过javaScriptProxy调原生原生通过runJavaScript调JS。SSL错误处理HTTPS页面遇到证书问题时触发onSslErrorReceive.onSslErrorReceive((event:SslErrorEvent){// event.handler.confirm() // 忽略错误继续加载(不推荐生产环境用)// event.handler.cancel() // 取消加载(默认行为)this.addLog(SSL错误: event.error.toString());})默认行为是cancel页面加载失败。confirm可以强行继续但只适合调试。生产环境不该忽略SSL错误。加载本地HTMLrawfile目录下的HTML文件可以直接加载Web({src:$rawfile(web/index.html),controller:this.webController}).javaScriptAccess(true).domStorageAccess(true).allowFileAccess(true)// 允许文件访问.allowFileAccessFromFileURLs(true)// 允许file协议跨域本地HTML里引用其他资源用相对路径scriptsrcjs/app.js/scriptlinkrelstylesheethrefcss/style.cssimgsrcimg/logo.pngrawfile路径是resources/rawfile/web/目录结构跟HTML里的引用路径对应。自定义User-AgentWeb({src:url,controller:this.webController}).userAgent(MyApp/1.0 webview.getDefaultUserAgent())在默认UA后面追加自己的标识方便服务端识别应用内WebView。网络拦截onOverrideUrlLoading可以拦截URL跳转.onOverrideUrlLoading((webResourceRequest:WebResourceRequest){leturl:stringwebResourceRequest.url;if(url.indexOf(myscheme://)0){// 处理自定义schemethis.handleCustomScheme(url);returntrue;// 返回true阻止加载}returnfalse;// 返回false允许加载})返回true阻止当前URL加载返回false放行。这个能力可以用来实现深度链接拦截。onInterceptRequest拦截资源请求更底层的拦截可以替换网络请求的响应.onInterceptRequest((event:WebInterceptRequest){if(event.url.indexOf(local://)0){// 返回本地资源替换网络请求returnnewWebResourceResponse(text/html,UTF-8,$rawfile(cached/page.html));}returnnull;// 返回null不拦截})这可以用来做离线缓存——有网时加载网络资源断网时返回本地缓存。调试DevEco Studio支持Web组件调试。在Web组件上开启webDebuggingAccessWeb({src:url,controller:this.webController}).webDebuggingAccess(true)然后Chrome浏览器打开chrome://inspect就能看到WebView页面用DevTools调试JS。注意这个开关只在debug模式生效release包自动关闭。性能优化初始加载用domStorageAccess(true)避免某些页面白屏大量图片的页面用onlineImageAccess控制不需要缩放就关掉zoomAccess预加载提前创建WebviewController并loadUrlWeb组件复用搭配Reusable避免反复创建避免在onPageBegin里做耗时操作会影响渲染踩坑总结问题原因解决JS不执行javaScriptAccess没开设为trueDOM Storage报错domStorageAccess没开设为true回调类型错误用了string/ErrorEvent用OnPageBeginEvent等本地文件404路径不对或allowFileAccess没开检查rawfile路径javaScriptProxy调不到methodList没声明补充方法名后退无反应accessBackward为false检查历史栈runJavaScript无回调JS表达式无返回值检查JS语法HTTPS页面加载失败SSL证书问题onSslErrorReceive处理WebView在HarmonyOS里不是嵌个浏览器那么简单它是一个有完整生命周期和通信体系的第一等组件。原生和Web的边界通过javaScriptProxyrunJavaScript打通回调类型用官方定义的Event类型导航用WebviewController——搞清楚这三条线复杂交互都能实现。