在鸿蒙开发过程中,我们常常用到原生中加载一个h5页面,就是webview组件中加载可以一个h5的页面,但是他们之间有需要有一些通信,例如h5需要掉用一些原生的api或者原生的方法。原生页面中又需要掉用h5的函数。
通过阅读华为官方文档中是有一些api可以实现我们想要的效果的。


h5掉用原生函数

使用

Web({
  src: $rawfile("xxx.html"),
  controller: this.controller
})
  .javaScriptAccess(true) // 启用JS执行权限
  .javaScriptProxy({
    object: this.testObj,
    name: 'testObjName',
    methodList: ['test'],
    controller: this.controller
  })

其中,this.testObj是h5掉用原生的方法合集封装的一个类,在加载web的页面中new出来,
name就是在h5中掉用的方法自定义名字,methodList就是需要注册到h5中的方法的数组,controller就是加载web的controller。
在h5中就可以以window.testObjName.test()掉用了


原生掉用h5

使用this.webviewController.runJavaScript(),括号里面可以直接写h5的方法的用``包裹即可

例如:

this.webviewController.runJavaScript(`function changeColor(){document.getElementById('text').style.color = 'red'}`),

也可以使用this.webviewController.runJavaScript(`htmlTest(${param})`).
当然为了方便统一管理,可以封装一个JsBridge桥。

export class JsBridge {
  private controller: web_webview.WebviewController;

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

  // JS调用原生方法
  call = (func: string, params: string): void => {
    const paramsObj = JSON.parse(params) as SelectContactParams;
    switch (func) {
      case 'selectContacts':
        this.handleSelectContact(paramsObj.callID);
        break;
      // 添加其他功能case...
    }
  }

  // 处理联系人选择
  private handleSelectContact(callID: number) {
    // 实现原生联系人选择逻辑...
    const contacts: Contact[] = [{ name: "张三", phone: "13800138000" }];
    let result: Promise<string> = new Promise((resolve) => resolve(''));
    this.chooseContact().then((data: string) => {
      this.executeH5Callback(callID, data);
    })
    // this.executeH5Callback(callID, contacts);
  }

  // 回调H5方法
  executeH5Callback(callID: number, data: Object) {
    const script = `window.handleNativeCallback(${callID}, ${JSON.stringify(data)})`;
    this.controller.runJavaScript(script); // 执行JS回调
  }


  /**
   * 选择本地联系人
   */
  chooseContact = (): Promise<string> => {
    let phone = '';
    let name = '';
    return new Promise((resolve) => {
      let promise = contact.selectContact();
      promise.then((info: Array<contact.Contact>) => {
        info.forEach((item: contact.Contact) => {
          phone = item?.phoneNumbers ? item?.phoneNumbers[0].phoneNumber : '';
          name = item?.name ? item?.name?.fullName : '';
        })
        resolve(phone + '_' + name);
      }).catch((err: object | string) => {
        console.error(`selectContact fail: err->${JSON.stringify(err)}`);
      });
    })
  }

  // 注册JS代理对象
  javaScriptProxy(): JavaScriptItem {
    return {
      object: {
        call: this.call
      },
      name: "JSBridgeHandle",
      methodList: ['call'],
      controller: this.controller
    };
  }

以上示例中,javaScriptProxy就是注册JS代理对象JavaScriptItem,JavaScriptItem是一个接口

export interface JavaScriptItem {
  object: callType,
  name: string,
  methodList: Array<string>,
  controller: WebviewController
}

我们这里就是一个h5页面中点击一个按钮调取原生中本地联系人选择联系人传给h5页面

其中联系人对象

//联系人对象
interface Contact {
  name?: string;
  phone?: string;
}
/**
 * 联系人加一个id对象
 */
interface SelectContactParams {
  callID: number,
  data: Contact
}

现在我们根据调取顺序逐步分析

首先h5中的一个按钮点击之后事件selectContacts()

<button class="btn-primary" οnclick="selectContacts()">选择联系人</button>

调用原生方法

// 调用原生方法
function selectContacts() {
  const callID = Date.now(); // 生成唯一调用ID
  window.JSBridgeHandle.call('selectContacts', JSON.stringify({ callID }));
}

这样就会调到selectContacts方法,再然后handleSelectContact,再到chooseContact选择本地联系人拿到联系人对象回调给h5

executeH5Callback(callID: number, data: Object) {
  const script = `window.handleNativeCallback(${callID}, ${JSON.stringify(data)})`;
  this.controller.runJavaScript(script); // 执行JS回调
}

执行h5的函数handleNativeCallback将结果给h5

window.handleNativeCallback = (callID, data) => {
  console.log(`回调ID: ${callID}`, data);
  addLog(`回调ID: ${callID}`, data);
  addLog(`获取联系人: ${JSON.stringify(data)}`);
};

具体调用如图:

上面就是arkts和h5通信的全部内容了

谢谢观看,多多点赞,谢谢!

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐