uniapp鸿蒙Next、安卓、ios 内嵌webview 通信处理

3,181 阅读2分钟

前言

最近Uniapp也更新了鸿蒙系统的打包,然后本人开发鸿蒙app时候发现webview的通信方式,与安卓、ios略有不同,踩坑好久才解决,发现网上对于这个问题解决方案基本没有,所以记录下来,帮助新入坑的同学。

环境

  • Hbuilder:4.29
  • H5引用的uni-webview版本:1.5.5
  • uni:uniapp vue3 版本(注意非uniapp-x)

首先H5向APP发送消息

  • H5不管向鸿蒙APP发消息还是安卓ios发消息,方式都是一样的,首先要引用uni.webview.1.5.5.js文件,我是放在了static目录下,然后在index.html引用
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
    />
      <!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->
      <script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <title>XJU App</title>
  </head>
  <body>
    <!-- uni 的 SDK,必须引用。 -->
    <script type="text/javascript" src="/uni.webview.1.5.5.js"></script>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
  • 封装一个jsbridge.js文件,用来向APP发送消息,并且能收到对应的回调消息
class NativeInstance {
  customInvoke(data) {
   const tp = new Date().getTime().toString()
   data = {
    type: 'customInvoke',
    ...data,
    tp
   }
   // 发送消息
   uni.postMessage(
    {
     data
    },
    '*'
   )
   return new Promise((resolve, reject) => {
    window[`invokeResolve${tp}`] = resolve
    window[`invokeReject${tp}`] = reject
   })
  }
}

let instance: any = null

export default () => {
  if (!instance) {
   instance = new NativeInstance()
  }
  return instance
}
  • 使用方法
<script setup lang="ts">
import getNativeInstance from '@/utils/JSBridge'

const getAppToken = () => {
  getNativeInstance()
   .customInvoke({
    action: 'oauth',
    data: {
        a: 123123
    }
   })
   .then((res) => {
       console.log(res)
   })
}
</script>

鸿蒙、安卓、ios接受H5消息

  • APP中,使用web-view标签
  • 注意必须要设置id
<template>
	<div class="openUrl">
		<web-view id="webviewId" ref="webviewRef" :update-title="false" @message="onMessage" v-if="visible" :src="url"></web-view>
	</div>
</template>
  • 获取webview实例
onReady() {
    // #ifdef APP-HARMONY
            //!!! webview标签必须设置id并且是webviewId,this必传
            this.currentWebview = uni.createWebviewContext('webviewId', this)
    // #endif

    // #ifndef APP-HARMONY
            // #ifdef APP || MP-WEIXIN
                    let wv = this.$scope.$getAppWebview()
                    setTimeout(() => {
                            this.currentWebview = wv.children()[0]
                    }, 1000);
            // #endif
    // #endif
}

注意鸿蒙和安卓、ios获取实例的方式不一样,鸿蒙没有plus对象,所以要通过uni.createWebviewContext('webviewId', this) 获取,并且都要从onReady 生命周期获取

  • 接受H5消息,并向H5发送回调消息
onMessage(e) {
    console.log(`【UNILOG】-【onGetH5Message】`);
    console.log('【UNILOG】', JSON.stringify(e.detail.data));
    let action = null
    let data = null
    let tp = null

    // #ifdef APP || MP-WEIXIN
    action = e.detail.data[0].action
    data = e.detail.data[0].data
    tp = e.detail.data[0].tp
    // #endif

    // #ifdef APP-HARMONY
    // 鸿蒙通信里面会多套一层data
    action = e.detail.data[0].data.action
    data = e.detail.data[0].data.data
    tp = e.detail.data[0].data.tp
    // #endif

    // #ifdef APP-HARMONY
            //!!! webview标签必须设置id并且是webviewId,this必传
            this.currentWebview.evalJs(`invokeResolve${tp}('3213asd')`)
    // #endif

    // #ifndef APP-HARMONY
            // #ifdef APP || MP-WEIXIN
                    this.currentWebview.evalJS(`invokeResolve${tp}('3213asd')`)
            // #endif
    // #endif
}
  • 注意

在接受消息时候,鸿蒙会多嵌套一层data

在发送消息时候,鸿蒙发送方法是evalJs,而安卓是大写evalJS

完整代码

<template>
  <div class="openUrl">
   <up-loadmore status="loading" />
   <!-- <up-navbar :title="name" :autoBack="true"></up-navbar> -->
   <web-view id="webviewId" ref="webviewRef" :update-title="false" @message="onMessage" v-if="visible" :src="url"></web-view>
  </div>
</template>

<script>
  import { forEach } from 'lodash'
  import { useUserStore } from '@/store/user'
  export default {
   data() {
    return {
     url: null,
     name: null,
     visible: false,
     statusBarHeight: 0,
     height: 0,
     currentWebview: null // 安卓、ios、鸿蒙
    }
   },
   onReady() {
    // #ifdef APP-HARMONY
     //!!! webview标签必须设置id并且是webviewId,this必传
     this.currentWebview = uni.createWebviewContext('webviewId', this)
    // #endif
    
    // #ifndef APP-HARMONY
     // #ifdef APP || MP-WEIXIN
      let wv = this.$scope.$getAppWebview()
      setTimeout(() => {
       this.currentWebview = wv.children()[0]
      }, 1000);
     // #endif
    // #endif
    
    if(this.name) {
     uni.setNavigationBarTitle({
      title: this.name
     })
    }
   },
   onLoad(options) {
    console.log('options: ',options);
    if(options.paramsUrl) {
     // 如果传入的Url本身就要带参数则需要这种格式:paramsUrl=encodeURIComponent(['https://www.baidu.com?a=123$b=123'])
     const urlStr = decodeURIComponent(options.paramsUrl)
     console.log('paramsUrl: ',urlStr);
     this.url = urlStr
    } else {
     // 常规Url:url=https://www.baidu.com
     this.url = options.url
    }
    this.name = options.name
    this.visible = true
   },
   methods: {
    onMessage(e) {
     console.log(`【UNILOG】-【onGetH5Message】`);
     console.log('【UNILOG】', JSON.stringify(e.detail.data));
     let action = null
     let data = null
     let tp = null
     
     // #ifdef APP || MP-WEIXIN
     action = e.detail.data[0].action
     data = e.detail.data[0].data
     tp = e.detail.data[0].tp
     // #endif
     
     // #ifdef APP-HARMONY
     // 鸿蒙通信里面会多套一层data
     action = e.detail.data[0].data.action
     data = e.detail.data[0].data.data
     tp = e.detail.data[0].data.tp
     // #endif
     const userStore = useUserStore()
     const token = userStore.userInfo['xjuToken']
     
     // #ifdef APP-HARMONY
      //!!! webview标签必须设置id并且是webviewId,this必传
      this.currentWebview.evalJs(`invokeResolve${tp}('${token}')`)
     // #endif
     
     // #ifndef APP-HARMONY
      // #ifdef APP || MP-WEIXIN
       this.currentWebview.evalJS(`invokeResolve${tp}('${token}')`)
      // #endif
     // #endif
    }
   }
  }
</script>

<style lang="scss" scoped>
  .openUrl {}
</style>

以上就是踩坑过程,如果有问题请留言,对你有帮助请点个赞。