鸿蒙 ArkTs 的WebView如何与JS交互

c 复制代码
import webView from '@ohos.web.webview';
import { BusinessError } from '@kit.BasicServicesKit';
import { picker } from '@kit.CoreFileKit';

@Component
export struct WebViewComponent {

  webviewController: webView.WebviewController = new webView.WebviewController();
  // 页面 loading
  isLoading: boolean = true
  // 链接
  @Prop @Require url: string = 'https://blog.csdn.net/survivorsfyh'
  // 声明注册JS侧调用鸿蒙侧交互对象
  private webCallApp: WebCallApp = new WebCallApp(this.webviewController)
  // 与JS端约定的交互协议名Key
  private proxyName:string = 'Harmony'

  onBackPress(): boolean | void { // Web 组件左滑手势返回处理
    if (this.webviewController.accessStep(-1)) {
      // 返回上一层级
      this.webviewController.backward()
      // 执行自定义逻辑
      return true
    } else { // 执行系统默认返回逻辑
      return false
    }
  }

  webDebugMethod(): void {
    try {
      // 启用网页调试功能
      webView.WebviewController.setWebDebuggingAccess(true);
    } catch (error) {
      let e: BusinessError = error as BusinessError;
      console.log(`[Web] ****** Error Code: ${e.code}, Message: ${e.message}`);
      this.webviewController.refresh(); // 页面异常,刷新
    }
  }

  aboutToDisappear(): void {
     // javaScriptProxy接口需要和deleteJavaScriptRegister接口配合使用,防止内存泄漏。
     this.webviewController.deleteJavaScriptRegister(this.proxyName)
  }

  build() {
    if (this.url) {
      Column(){
        Button('runJavaScript方法调用js方法')
          .onClick(() => {
            if (this.webviewController) {
              /**
               * 1.注意:传参时要注意一个问题,就是这里的调用这个方法,是直接写字符串去调用.
               * 但是如果要在调用方法里边传参,且正好是个字符串,就需要区分双引号和单引号,
               * 保证对runJavaScript穿的方法收尾对应的是一组符号,而方法内部传参对应的是一组符号,
               * 示范如下:
               * 2."changeMessage"是一个定义在JS端,参数入参为一个字符串的函数方法.
               * */
              this.webviewController.runJavaScript('changeMessage("调用h5方法成功")')
            }
          })
        Button('鸿蒙调用js,传递js代码块,修改颜色字体')
          .onClick(() => {
            // 传递runJavaScript侧代码方法,也可以像这样直接将整个JS方法体传递过去以达到我们修改颜色的目的.
            this.webviewController.runJavaScript(`function changeColor(){document.getElementById('text').style.color = 'red'}`);
          })
        /// 白屏情况可能是权限导致,把权限全部开启,例如本地存储或者 http & https
        Web({ src: this.url, controller: this.webviewController })
          .width('100%')
          .height('100%')
          .backgroundColor(Color.White)
          .multiWindowAccess(true)
          .javaScriptAccess(true)// 访问本地资源文件
          .imageAccess(true)// 权限状态开启
          .onlineImageAccess(true)// 权限状态开启
          .fileAccess(true)// 权限状态开启
          .domStorageAccess(true)// 数据存储权限
          .mediaPlayGestureAccess(true)// 媒体权限
          .mixedMode(MixedMode.All)// https 加载
          .layoutMode(WebLayoutMode.FIT_CONTENT)// 自适应布局
          .verticalScrollBarAccess(true)// 滚动条
          .horizontalScrollBarAccess(false)// 滚动条
          .cacheMode(CacheMode.Default)// 缓存
          .zoomAccess(false)// 禁止手势缩放
          .geolocationAccess(true)// 定位权限
          .onConsole((event) => {
            console.log('[交互] - onConsole')
            console.info(event?.message.getMessage())
            return false
          })
          .onPageBegin(() => { // 页面加载中
            console.log('[Web] - 页面加载中:', this.url)
          })
          .onPageEnd(() => { // 页面加载完成
            console.log('[Web] - 页面加载完成:', this.url)
            this.isLoading = false
          })
          .onErrorReceive((event) => { // 异常: 无网络,页面加载错误时
            if (event) {
              console.info('getErrorInfo:' + event.error.getErrorInfo());
              console.info('getErrorCode:' + event.error.getErrorCode());
              console.info('url:' + event.request.getRequestUrl());
              console.info('isMainFrame:' + event.request.isMainFrame());
              console.info('isRedirect:' + event.request.isRedirect());
              console.info('isRequestGesture:' + event.request.isRequestGesture());
              console.info('getRequestHeader_headerKey:' + event.request.getRequestHeader().toString());
              let result = event.request.getRequestHeader();
              console.info('The request header result size is ' + result.length);
              for (let i of result) {
                console.info('The request header key is : ' + i.headerKey + ', value is : ' + i.headerValue);
              }
            }
          })
          .onHttpErrorReceive((event) => { // 异常: 网页加载资源 Http code >= 400 时
            if (event) {
              console.info('url:' + event.request.getRequestUrl());
              console.info('isMainFrame:' + event.request.isMainFrame());
              console.info('isRedirect:' + event.request.isRedirect());
              console.info('isRequestGesture:' + event.request.isRequestGesture());
              console.info('getResponseData:' + event.response.getResponseData());
              console.info('getResponseEncoding:' + event.response.getResponseEncoding());
              console.info('getResponseMimeType:' + event.response.getResponseMimeType());
              console.info('getResponseCode:' + event.response.getResponseCode());
              console.info('getReasonMessage:' + event.response.getReasonMessage());
              let result = event.request.getRequestHeader();
              console.info('The request header result size is ' + result.length);
              for (let i of result) {
                console.info('The request header key is : ' + i.headerKey + ' , value is : ' + i.headerValue);
              }
              let resph = event.response.getResponseHeader();
              console.info('The response header result size is ' + resph.length);
              for (let i of resph) {
                console.info('The response header key is : ' + i.headerKey + ' , value is : ' + i.headerValue);
              }
            }
          })
          .onAlert((event) => { // 提示框处理相关
            AlertDialog.show({
              title: '温馨提示',
              message: event?.message,
              confirm: {
                value: '确认',
                action: () => {
                  event?.result.handleConfirm()
                }
              },
              cancel: () => {
                event?.result.handleCancel()
              }
            })
            return true;
          })
          .onConfirm((event) => { // 提示框处理相关
            AlertDialog.show({
              title: '温馨提示',
              message: event?.message,
              confirm: {
                value: '确认',
                action: () => {
                  event?.result.handleConfirm()
                }
              },
              cancel: () => {
                event?.result.handleCancel()
              }
            })
            return true
          })
          .onShowFileSelector((event) => { // 文件选择处理
            console.log('MyFileUploader onShowFileSelector invoked');
            const documentSelectOptions = new picker.PhotoSelectOptions();
            let uri: string | null = null;
            const documentViewPicker = new picker.PhotoViewPicker();
            documentViewPicker.select(documentSelectOptions).then((documentSelectResult) => {
              uri = documentSelectResult[0];
              console.info('documentViewPicker.select to file succeed and uri is:' + uri);
              if (event) {
                event.result.handleFileList([uri]);
              }
            }).catch((err: BusinessError) => {
              console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
            })
            return true
          })
          .onLoadIntercept((event) => {
            if (event.data.isRedirect()) {
              console.log('[重定向]');
            }
            return false
          })
            /// JS调用ArkTS,web组件初始化调用
            /*
             * 将javaScriptProxy中的ArkTS对象注册到Web组件中,该对象将使用JavaScriptProxy中指定的名称注册到网页的所有框架中
             * 这使得JavaScript可以调用javaScriptProxy中ArkTS对象的方法。
             * */
          .javaScriptProxy({
            //将交互对象注入web
            object: this.webCallApp,
            //与JS端的交互协议Key
            name: this.proxyName,
            // 基于 object 的 WebCallApp 中交互具体实现的若干函数方法
            // 交互对象中所涵盖的方法,支持多个.JS调用鸿蒙App端的方法,最终方法会在交互对象定义的方法中触发
            methodList: WebCallApp.methodList,
            // 参与注册的应用侧JavaScript对象的异步方法。但是异步方法无法获取返回值。
            asyncMethodList:WebCallApp.asyncMethodList,
            controller: this.webviewController
          })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Start)
    } else {
      // 加载异常,请重试
    }
  }

}

/**
 * javaScriptProxy和registerJavaScriptProxy异同
 *
 * 相同点:二者都可以注入JavaScript对象到window对象中,并在window对象中调用该对象的方法.
 *
 * 不同点:
 * 1.从注册对象的角度来看,前者仅支持注册一个对象,而后者支持注册多个对象。
 * 2.从生命周期上讲,javaScriptProxy在Web组件初始化调用,registerJavaScriptProxy在Web组件初始化完成后调用。
 * 3.从接口角度来看,javaScriptProxy是Web组件的方法,而registerJavaScriptProxy是WebviewController的方法。
 * */

class WebCallApp {

  private controller: webView.WebviewController;
  constructor(controller: WebviewController) {
    this.controller = controller
  }

  /// JS调用ArkTS 同步方法数组,包含同步方法的方法名.
  static methodList:string[] = [
    'WebCallApp',
  ]
  static asyncMethodList:string[] = [
    'WebTestAsync',
    'WebTest',
  ]

  WebCallApp(value: string) {

  }
  async WebTestAsync(value: string):Promise<string>{
    return '测试 - 异步'
  }
  WebTest(value: string): Promise<string> { // 测试 - promise
    return new Promise((resolve, reject) => {
      try {
        resolve('[Callback]:你好')
      } catch (e) {
        reject('[Callback]:异常')
      }
    })
  }

}

参考链接

修改问题:避免web不适配,需要做下面修改

相关推荐
L-岁月染过的梦19 小时前
前端使用JS实现端口探活
开发语言·前端·javascript
2501_9444460020 小时前
Flutter&OpenHarmony字体与排版设计
android·javascript·flutter
小安同学iter20 小时前
Vue3 进阶核心:高级响应式工具 + 特殊内置组件核心解析
前端·javascript·vue.js·vue3·api
Roc.Chang20 小时前
Vue 3 setup 语法糖 computed 的深度使用
前端·javascript·vue.js
玄尺_00720 小时前
uniapp h5端使浏览器弹出下载框
前端·javascript·uni-app
军军君0120 小时前
Three.js基础功能学习三:纹理与光照
前端·javascript·3d·前端框架·three·三维·三维框架
淡笑沐白20 小时前
Vue3基础语法教程
前端·javascript·vue.js
Random_index20 小时前
#HarmonyOS篇:学习UI规范基本语法&&学习UI范式装填管理V1&&学习UI范式装填管理V2&&学习UI范式渲染控制
harmonyos
可触的未来,发芽的智生20 小时前
2025年终总结:智能涌现的思考→放弃冯诺依曼架构范式,拥抱“约束产生智能”
javascript·人工智能·python·神经网络·程序人生
前端世界20 小时前
鸿蒙分布式权限管理实战指南:架构原理 + 可运行 Demo
分布式·架构·harmonyos