WebView之通信,什么是WebView,为什么要通信,如何实现通信?

WebView之通信

HarmonyOS
2024-05-26 17:43:46
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
dushinongmin

什么是WebView

WebView指网页视图,基于 webkit 引擎。可以内嵌在移动端加载Web内容,实现前端的混合式开发,大多数混合式开发框架都是基于WebView模式进行二次开发的。比如:APIcloud、uni-app等等的框架。

WebView目前使用频率最多的,是客户端内嵌的WebView,小到我们地铁里用手机看的一篇公众号文章,大到我们使用App中的一些重要交互流程,其实都是WebView打开html页去承接的。

为什么要通信

绝大多数场景中,我们需要调用原生API集成酷炫的系统级功能,如传感器、存储、日历、联系人、相机等功能。而WebView作为独立的容器,其内部加载的html页面无法直接调用原生API,此时我们就需要进行容器内外通信。

通过数据传递,告知WebView容器外我们想要调用的原生API,并在ArkTS侧调用后将拿到的结果发送到html页面,然后,html页面里就可以根据拿到的数据实现各种炫酷的效果了。

如何实现通信

1、通过MessageChannel通信

  •  通过WebController.createWebMessagePorts()接口,我们可以得到两个WebMessagePort对象。然后我们需要将这两个Port分别放在ArkTS侧和html侧。之后基于这两个Port实现WebView容器内外通信。
  • 通过Port1的postMessage()方法,我们可以发消息到Port2,并通过Port2的onMessage事件接收。同样,通过Port2的postMessage()方法,也可以发消息到Port1的onMessage事件中,如下图。以此实现WebView容器内外的双向通信。

  • 参考代码:

− ArkTS侧代码

import WebView from '@ohos.web.webview'; 
@Entry 
@Component 
struct Message { 
  @State message: string = 'Hello World' 
  private controller: WebView.WebviewController = new WebView.WebviewController() 
  private port1: WebView.WebMessagePort 
  private count: number = 0 
 
  createChannel = () => { 
    const [port1, port2] = this.controller.createWebMessagePorts(); 
    this.controller.postMessage('__init_ports__', [port2], '*'); 
    this.port1 = port1; 
    this.port1.onMessageEvent((result: any) => { 
      console.log("[Demo] onMessageEvent:" + result); 
      this.message = result 
    }) 
  } 
 
  build() { 
    Column() { 
      Text(`${this.message}`).fontColor('#000').fontSize(30) 
      Button('send').onClick(() => { 
        this.port1.postMessageEvent(`ArkTS count: ${++this.count}`); 
      }) 
      Web({ src: $rawfile('message.html'), controller: this.controller }) 
        .width('100%') 
        .height('50%') 
        .onPageEnd(() => this.createChannel()) 
    }.height('100%').width('100%') 
  } 
}

− html侧代码

<!DOCTYPE html> 
  <html style="width:100%;height:100%;"> 
  <meta charset="utf-8"> 
  <body style=" width: 100%;height: 100%;background-color: #fff;"> 
  <script> 
  let port2 
let count = 0 
function onMessage(e) { 
  var output = document.getElementById("container"); 
  output.innerText = e.data; 
} 
function sendMessage(e) { 
  port2.postMessage(e || `count: ${++count}`) 
} 
window.addEventListener('message', (e) => { 
  if(e.data === '__init_ports__') { 
    port2 = e.ports[0] 
    port2.onmessage = onMessage 
    sendMessage('create channel success') 
  } 
}); 
</script> 
  <div style="width: 100%;height: 100%;"> 
  <div style="width: 100%; height: 300px; "> 
  <button>sendMessage</button> 
  <span>message: </span> <span id="container"></span> 
  </div> 
  </div> 
  </body> 
  </html>

2、javaScriptProxy通信

  • 通过Web组件的javaScriptProxy属性或WebController.registerJavaScriptProxy()接口,我们可以将ArkTS侧的JavaScript对象注册到html侧的window对象中,并在window对象中使用该对象的方法。Tips:registerJavaScriptProxy()注册后需调用refresh()接口才能生效。
  • 参考代码:

− ArkTS侧代码

import WebView from '@ohos.web.webview'; 
@Entry 
@Component 
struct Message{ 
  private controller: WebView.WebviewController = new WebView.WebviewController() 
  private testObj = { 
    test: (d) => "test_" + Date.now() + "_" + d, 
    toString: () => 'test toString' 
  } 
  build() { 
    Column() { 
      Web({ src: $rawfile('message.html'), controller: this.controller }) 
        .javaScriptProxy({ 
          object: this.testObj, 
          name: "objName", 
          methodList: ["test"], // toString方法未注册,html调用时返回undefined 
          controller: this.controller, 
        }) 
        .width('100%') 
        .height('50%') 
    } 
    .height('100%') 
    .width('100%') 
  } 
}

− html侧代码

<!DOCTYPE html> 
  <html style="width:100%;height:100%;"> 
  <meta charset="utf-8"> 
  <body style=" width: 100%;height: 100%;background-color: #fff;"> 
  <script> 
  window.onload = () => { 
  let output = document.getElementById("container"); 
  let data = window.objName.test(2222) // 返回test_1665631134823_2222 
  const d = window.objName.toString() // 返回undefined 
  output.innerText = data; 
} 
  </script> 
  <div style="width: 100%;height: 100%;"> 
  <div style="width: 100%; height: 300px; "> 
  <span>message: </span> <span id="container"></span> 
  </div> 
  </div> 
  </body> 
  </html>

3、runJavaScript通信

  • 通过WebController.runJavaScript()接口,我们可以在ArkTS侧主动调用html侧的JavaScript方法。Tips:runJavaScript()需要在html页面加载完成后调用。
  • 参考代码:

− ArkTS侧代码:

import WebView from '@ohos.web.webview'; 
@Entry 
@Component 
struct Message { 
  private controller: WebView.WebviewController = new WebView.WebviewController() 
  build() { 
    Column() { 
      Web({ src: $rawfile('message.html'), controller: this.controller }) 
        .width('100%') 
        .height('50%') 
        .onPageEnd(() => { 
          this.controller.runJavaScript('test(123456)') 
            .then((result) => { 
              console.info(`The test() return value is: ${result}`) 
            }) 
        }) 
    } 
    .height('100%') 
    .width('100%') 
  } 
}

− html侧代码

<!DOCTYPE html> 
  <html style="width:100%;height:100%;"> 
  <meta charset="utf-8"> 
  <body style=" width: 100%;height: 100%;background-color: #fff;"> 
  <script> 
  function test(text) { 
    let output = document.getElementById("container"); 
    output.innerText = text; // 123456 
    return 'html_' + text 
  } 
  </script> 
  <div style="width: 100%;height: 100%;"> 
  <span>message: </span> <span id="container"></span> 
  </div> 
  </body> 
  </html>

限制与约束

  • 目前通信数据仅支持基础类型,不支持对象等复杂类型。
  • 适用版本:OpenHarmony 3.2.6.3 版本以上,API9 Stage模型。

总结

通过本文我们了解了OpenHarmony WebView通信的三种方式。三种方式的主要区别在于主动发起方不同:

  • MessageChannel双向通信,WebView内外均可发起
  •  javaScriptProxy单向通信,html侧主动发起
  •  runJavaScript单向通信,ArkTS侧主动发起

具体采用哪种通信方式,需要开发者根据各自业务场景去判断。

分享
微博
QQ
微信
回复
2024-05-27 22:28:45
相关问题
js Fa如何实现线程间通信
4268浏览 • 1回复 待解决
鸿蒙是否进行异步通信
2770浏览 • 1回复 待解决
fegin 和 docker 通信问题
1728浏览 • 1回复 待解决
鸿蒙音视频通信系统如何实现
3601浏览 • 1回复 待解决
TaskPool如何跟主线程进行通信
42浏览 • 1回复 待解决
OpenharmonyOS 如何使用串口通信
3193浏览 • 1回复 待解决
公共事件实现跨进程通信
530浏览 • 1回复 待解决
Open Harmony 近场通信
6049浏览 • 1回复 待解决
基于libuv异步库进行线程通信
737浏览 • 0回复 待解决
需要提供c++到js通信demo
336浏览 • 1回复 待解决
TaskPool子线程和主线程如何通信
1007浏览 • 1回复 待解决
arkts父子组件组件怎么通信传值啊?
3556浏览 • 1回复 待解决