uniapp-ios开发之App端与webview端相互通信的方法以及注意事项

 更新时间:2024年07月22日 09:02:48   作者:叫我菜菜就好  
在uni-app与Webview之间进行数据交互是非常常见的需求,下面这篇文章主要给大家介绍了关于uniapp-ios开发之App端与webview端相互通信的方法以及注意事项的相关资料,需要的朋友可以参考下

前言

在开发中,使用uniapp开发的项目开发效率是极高的,使用一套代码就能够同时在多端上线,像笔者之前写过的使用Flutter端和webview端之间的相互通信方法和问题,这种方式本质上实际上是h5和h5之间的通信,网上有非常多的方案,最简单的就是使用postMessage和addEventListener的方式,这个在我之前的文章有讲解,这里不再赘述。

那么今天的问题,是使用uniapp开发的App端和H5端(webview)之间的通信问题

注意前提,是使用uniapp同时去开发app端和h5端。

问题

uniapp本质开发的app实际上还是web,那么能不能用postMessage的方式呢?

答案当然是可以的,但是你要区分情况,仔细看看官方文档

平台差异说明:App-nvue,是App-nvue的方法,这是个坑!!!

所以,这个时候就需要去区分情况了,你使用的是vue写的webview还是nvue写的webview

vue类型的webview

<web-view :src="src" ref="webview" :fullscreen="false" @message="receiveData"></web-view>

app传递数据给h5

本质:h5在webview环境中提取放入一个函数,app调用该函数传递数据进去。

h5端接收:可以在app.vue的onLaunch阶段

window.msgFromUniapp = (res) =>{
	console.log("原生传递过来的数据:",res)
}

app端发送:

methods: {
			//给webview传递数据
			postMess(msg) {
				const currentWebview = this.$scope.$getAppWebview();
				const wv = currentWebview.children()[0];
				wv.evalJS(`msgFromUniapp('${JSON.stringify(msg)}')`)
			}
		},
		onLoad(item) {
			this.src = decodeURIComponent(item.url)
			// 传入需要跳转的链接 使用web-view标签进行跳转
			this.title = item.title
			// #ifdef APP-PLUS
			const currentWebview = this.$scope.$getAppWebview();
			const that = this
			setTimeout(function() {
				let wv = currentWebview.children()[0];
				that.postMess({
					type: 'app/systemInfo',
					data: {
						sys: 'ios'
					},
					code: 1,
				})
			}, 500);
			// #endif
		}

h5传递给app

app端接收:添加监听即可

@message="receiveData"

h5端发送:

  import '@/utils/uni.webview.1.5.4..js'

  //传递url给原生应用
          uni.webView.postMessage({
              data:{
                  action:'openUrl',
                  url:this.orderDetail.url
              }
          })

uni.webview.1.5.4.js

!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function i(e,i){return n.call(e,i)}var t=[];function r(){return window.__dcloud_weex_postMessage||window.__dcloud_weex_}var o=function(e,n){var i={options:{timestamp:+new Date},name:e,arg:n};if(r()){if("postMessage"===e){var o={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(o):window.__dcloud_weex_.postMessage(JSON.stringify(o))}var a={type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(a):window.__dcloud_weex_.postMessageToService(JSON.stringify(a))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:i,pageId:""},"*");if(0===t.length){var d=plus.webview.currentWebview();if(!d)throw new Error("plus.webview.currentWebview() is undefined");var s=d.parent(),w="";w=s?s.id:d.id,t.push(w)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}},"__uniapp__service");else{var u=JSON.stringify(i);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(u,",").concat(JSON.stringify(t),");"))}},a={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;o("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("redirectTo",{url:encodeURI(n)})},getEnv:function(e){r()?e({nvue:!0}):window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};o("postMessage",e.data||{})}},d=/uni-app/i.test(navigator.userAgent),s=/Html5Plus/i.test(navigator.userAgent),w=/complete|loaded|interactive/;var u=window.my&&navigator.userAgent.indexOf(["t","n","e","i","l","C","y","a","p","i","l","A"].reverse().join(""))>-1;var g=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var v=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var c=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var m=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);var f=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var l=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var _=window.jd&&window.jd.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var E=window.xhs&&window.xhs.miniProgram&&/xhsminiapp/i.test(navigator.userAgent);for(var h,P=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},b=[function(e){if(d||s)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&w.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),a},function(e){if(m)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(v)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(u){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(c)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(f)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(l)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(_)return window.JDJSBridgeReady&&window.JDJSBridgeReady.invoke?setTimeout(e,0):document.addEventListener("JDJSBridgeReady",e),window.jd.miniProgram},function(e){if(E)return window.xhs.miniProgram},function(e){return document.addEventListener("DOMContentLoaded",e),a}],y=0;y<b.length&&!(h=b[y](P));y++);h||(h={});var B="undefined"!=typeof uni?uni:{};if(!B.navigateTo)for(var S in h)i(h,S)&&(B[S]=h[S]);return B.webView=h,B}));

注意事项

app端要延迟再去获取webview实例,等webview加载完成。

官方写的是uni.posMessage,笔者亲试,没用的,注意是是 uni.webView.postMessage

h5需要额外引入uni.webview.1.5.4..js

!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function i(e,i){return n.call(e,i)}var t=[];function r(){return window.__dcloud_weex_postMessage||window.__dcloud_weex_}var o=function(e,n){var i={options:{timestamp:+new Date},name:e,arg:n};if(r()){if("postMessage"===e){var o={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(o):window.__dcloud_weex_.postMessage(JSON.stringify(o))}var a={type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(a):window.__dcloud_weex_.postMessageToService(JSON.stringify(a))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:i,pageId:""},"*");if(0===t.length){var d=plus.webview.currentWebview();if(!d)throw new Error("plus.webview.currentWebview() is undefined");var s=d.parent(),w="";w=s?s.id:d.id,t.push(w)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}},"__uniapp__service");else{var u=JSON.stringify(i);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(u,",").concat(JSON.stringify(t),");"))}},a={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;o("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("redirectTo",{url:encodeURI(n)})},getEnv:function(e){r()?e({nvue:!0}):window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};o("postMessage",e.data||{})}},d=/uni-app/i.test(navigator.userAgent),s=/Html5Plus/i.test(navigator.userAgent),w=/complete|loaded|interactive/;var u=window.my&&navigator.userAgent.indexOf(["t","n","e","i","l","C","y","a","p","i","l","A"].reverse().join(""))>-1;var g=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var v=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var c=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var m=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);var f=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var l=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var _=window.jd&&window.jd.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var E=window.xhs&&window.xhs.miniProgram&&/xhsminiapp/i.test(navigator.userAgent);for(var h,P=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},b=[function(e){if(d||s)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&w.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),a},function(e){if(m)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(v)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(u){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(c)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(f)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(l)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(_)return window.JDJSBridgeReady&&window.JDJSBridgeReady.invoke?setTimeout(e,0):document.addEventListener("JDJSBridgeReady",e),window.jd.miniProgram},function(e){if(E)return window.xhs.miniProgram},function(e){return document.addEventListener("DOMContentLoaded",e),a}],y=0;y<b.length&&!(h=b[y](P));y++);h||(h={});var B="undefined"!=typeof uni?uni:{};if(!B.navigateTo)for(var S in h)i(h,S)&&(B[S]=h[S]);return B.webView=h,B}));

nvue类型的webview

vue页面和nvue页面的区别,这里不做赘述,官方文档写的很清楚。

这个时候就可以使用官方文档的postMessage方式来

app传递数据给h5

绑定一个ref,获取webview实例

 <web-view ref="webview" :src="src" @onPostMessage="handlePostMessage"
      :style="{height:mbHeight,width:mbWidth,top:mbTop}" fullscreen="false"></web-view>
  this.$refs.webview.postMessage(data, '*')

或者

// 调用 webview 内部逻辑
			evalJs: function() {
				this.$refs.webview.evalJs("document.body.style.background ='#00FF00'");
			}
  • 然后h5使用window.addEventListener接收

h5传递数据给app

app接收消息:

<web-view ref="webview" class="webview" @onPostMessage="handlePostMessage"></web-view>
	handlePostMessage: function(data) {
				console.log("接收到消息:" + JSON.stringify(data.detail));
			},

注意事项

页面空白

如果你是nvue页面:

大概率是你没指定宽高,不信你放入一个百度的url试试,如果还是空白,请你设置style指定宽高。

如果你是vue页面,可能就是网页本身就打不开

环境问题

这是一个非常头疼的问题,我怎么知道这个web页面是在app环境打开还是在h5打开的,为什么需要去区分环境问题,因为你可能有一个这样的场景,你开发的app需要打开一个网页,然后撑满全屏,本质还是用webview容器去打开的,h5不知道自己所处的环境是app端,那么就会带来导航栏区域和底部安全区域怎么获取和处理的问题。

你可以选择从app端下手,前提是这个webview必须是nvue页面,因为vue页面默认webview是撑满全屏的,撑满全屏,撑满全屏。

如果你是vue页面,那么你可以通知h5端当前所处的环境,当前的导航栏高度和安全区域高度,在h5端单独去做样式兼容

如果你是nvue页面,除了上述方式,你还可以自己去指定webview的样式。

我还是建议都使用第一种方案吧,笔者自己去设置webview的样式发现在全屏阶段还是有一些问题的,不如默认撑满全屏,在h5端去做调整,毕竟调整h5端端成本最小,上架之后的app还需要提审等一些列步骤。

侧滑返回问题

可能有小伙伴发现,我打开一个webview,网页里面本身有好多跳转,为什么没办法侧滑返回。

原因是,本质上,在app端你打开的实际上只有一个webview页面,它只有一个页面,你的h5页面是在里面打开的,无论你h5的路由栈有多少层多没用,对于app来说,就只有一个webview页面。

所以,一定要注意放一个返回按钮提供给用户返回的机会,如果你要跳转外部网页,也不要用window.location去进行跳转,到时候就会返回不了了,你可以通知app端使用plus方法去打开网页

总结

官方文档并没有详细去区分两者的区别,网上的信息也很杂乱,所以在此特别去做区分和处理,如果你有更好的建议和方案,欢迎在评论区提出。

到此这篇关于uniapp-ios开发之App端与webview端相互通信的方法以及注意事项的文章就介绍到这了,更多相关App端与webview端相互通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue2面试考点之$nextTick原理解析

    Vue2面试考点之$nextTick原理解析

    平时在获取真实DOM的时候获取不到最新的DOM元素,使用$nextTick就可以,那为什么$nextTick就可以获取到最新的DOM元素呢,本文就来带着这两个问题来解析一下nextTick的原理
    2023-05-05
  • Vue3+Three.js实现为模型添加点击事件

    Vue3+Three.js实现为模型添加点击事件

    本文主要介绍了如何在Vue3和Three.js环境中为模型添加点击事件监听,具体方法是利用Three.js的Vector2和Raycaster,首先,创建一个Vector2对象来获取鼠标位置;然后,创建一个Raycaster对象来投射光线
    2024-10-10
  • 让你一看就明白的$nextTick讲解

    让你一看就明白的$nextTick讲解

    在我们用vue时,我们经常用到一个方法是this.$nextTick,相信你也用过,我常用的场景是在进行获取数据后,需要对新视图进行下一步操作或者其他操作时,发现获取不到dom,这篇文章主要给大家介绍了关于$nextTick的相关资料,需要的朋友可以参考下
    2021-07-07
  • vue 绑定对象,数组之数据无法动态渲染案例详解

    vue 绑定对象,数组之数据无法动态渲染案例详解

    这篇文章主要介绍了vue 绑定对象,数组之数据无法动态渲染案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • vue中重定向redirect:‘/index‘,不显示问题、跳转出错的完美解决

    vue中重定向redirect:‘/index‘,不显示问题、跳转出错的完美解决

    这篇文章主要介绍了vue中重定向redirect:‘/index‘,不显示问题、跳转出错的完美解决方案,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-09-09
  • vue中的自定义指令clickOutside

    vue中的自定义指令clickOutside

    这篇文章主要介绍了vue中的自定义指令clickOutside,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • vue中jsonp插件的使用方法示例

    vue中jsonp插件的使用方法示例

    这篇文章主要给大家介绍了关于vue中jsonp插件的使用方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • 一篇文章带你彻底搞懂VUE响应式原理

    一篇文章带你彻底搞懂VUE响应式原理

    这篇文章主要介绍了一篇文章带你彻底搞懂VUE响应式原理,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可任意参考一下,需要的朋友可以参考下
    2022-06-06
  • vue3单文件组件中style特性的深入讲解

    vue3单文件组件中style特性的深入讲解

    单文件就是把一个页面拆分为多个,多层次的组件,通过多层引用,大大缩小vue文件的长度和页面复杂度,下面这篇文章主要给大家介绍了关于vue3单文件组件中style特性的相关资料,需要的朋友可以参考下
    2021-09-09
  • Vue3实现自定义Input组件的示例详解

    Vue3实现自定义Input组件的示例详解

    这篇文章主要为大家详细介绍了如何使用Vue3自定义实现一个类似el-input的组件,可以v-model双向绑定,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03

最新评论