uniapp 微信小程序与h5双向通信

70 阅读3分钟

用处

比如重置导航栏标题 调用小程序功能比如扫码

方法

本人采取的是第二种方法

1.服务号API developers.weixin.qq.com/doc/service… 后端提供授权接口 前端先授权再调用js-sdk 微信后台还要配置 2.webview

developers.weixin.qq.com/miniprogram… image.png image.png image.png uniapp.dcloud.net.cn/component/w… image.png 下面演示扫码功能
可以专门准备显示webview的页面 webview会自动撑满屏幕

webview->小程序
webview需要引入jweixin 或 npm引入weixin-js-sdk @types/weixin-js-sdk uniapp可引入uni.webview
如果是uniapp打包出h5项目 存在有wx可能被修改和内置uni对象冲突
jweixin里面的wx改成jWeixin改成 不清楚为什么wx后面时空对象了 uni.webview里面的uni改成自定义名称比如webUni
jweixin 文件时打包压缩混淆的umd格式文件 通过 npx prettier jweixin.min.js --parser babel --write 格式化

jweixin和uni.webview 文件可以放在文件服务器或者前端打包文件里
如果是前端打包文件公共文件放在static注意不是public文件 uniapp可能修改vite配置publicPath行为
publicPath文件不能访问但能拷贝
如果有publicPath必须要手动加上 但是body里面src/main.ts文件不需要

 <script src="/publicPath/static/script/jweixin-1.3.2.js"></script>
  <script src="/publicPath/static/script/uni.webview.1.5.6.js"></script>

jweixin 赋值 image.png wx jWeixin对象 image.png jWeixin对象内部调用WeixinJSBridge对象 image.png

WeixinJSBridge对象 image.png
uni赋值(webUni) image.png uni对象(webUni) image.png

这里uni对象做了适配针对不同环境全局对象进行赋值 比如微信小程序ua判断
各大厂商小程序 app环境(weex uniapp_x ) 浏览器 plus 控制台查看的时候wx时空对象 所以可能是window.parent.postMessage 或者 wx(jWeixin).xx 我也不清楚是哪个 可能公众号是wx 小程序webview是window.parent.postMessage

var _ = window.wx && window.wx.miniProgram && /micromessenger/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent);
  if (_)
            return window.WeixinJSBridge && window.WeixinJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener("WeixinJSBridgeReady", e),
            window.wx.miniProgram

d = {
        navigateTo: function() {
            var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}
              , n = e.url;
            r("navigateTo", {
                url: encodeURI(n)
            })
        },
        navigateBack: function() {
            var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}
              , n = e.delta;
            r("navigateBack", {
                delta: parseInt(n) || 1
            })
        },
        switchTab: function() {
            var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}
              , n = e.url;
            r("switchTab", {
                url: encodeURI(n)
            })
        },
        reLaunch: function() {
            var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}
              , n = e.url;
            r("reLaunch", {
                url: encodeURI(n)
            })
        },
        redirectTo: function() {
            var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}
              , n = e.url;
            r("redirectTo", {
                url: encodeURI(n)
            })
        },
        getEnv: function(e) {
            a() ? e({
                uvue: !0
            }) : o() ? e({
                nvue: !0
            }) : window.plus ? e({
                plus: !0
            }) : e({
                h5: !0
            })
        },
        postMessage: function() {
            var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
            r("postMessage", e.data || {})
        }
    }
    
     function(e) {
        return document.addEventListener("DOMContentLoaded", e),
        d
    }
    
    
        var r = function(e, n) {
        var i = {
            options: {
                timestamp: +new Date
            },
            name: e,
            arg: n
        };
        if (a()) {
            if ("postMessage" === e) {
                var r = {
                    data: n
                };
                return window.__uniapp_x_postMessage ? window.__uniapp_x_postMessage(r) : window.__uniapp_x_.postMessage(JSON.stringify(r))
            }
            var d = {
                type: "WEB_INVOKE_APPSERVICE",
                args: {
                    data: i,
                    webviewIds: t
                }
            };
            window.__uniapp_x_postMessage ? window.__uniapp_x_postMessageToService(d) : window.__uniapp_x_.postMessageToService(JSON.stringify(d))
        } else if (o()) {
            if ("postMessage" === e) {
                var s = {
                    data: [n]
                };
                return window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessage(s) : window.__dcloud_weex_.postMessage(JSON.stringify(s))
            }
            var w = {
                type: "WEB_INVOKE_APPSERVICE",
                args: {
                    data: i,
                    webviewIds: t
                }
            };
            window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessageToService(w) : window.__dcloud_weex_.postMessageToService(JSON.stringify(w))
        } else {
            if (!window.plus)
                return window.parent.postMessage({
                    type: "WEB_INVOKE_APPSERVICE",
                    data: i,
                    pageId: ""
                }, "*");
            if (0 === t.length) {
                var u = plus.webview.currentWebview();
                if (!u)
                    throw new Error("plus.webview.currentWebview() is undefined");
                var g = u.parent()
                  , v = "";
                v = g ? g.id : u.id,
                t.push(v)
            }
            if (plus.webview.getWebviewById("__uniapp__service"))
                plus.webview.postMessageToUniNView({
                    type: "WEB_INVOKE_APPSERVICE",
                    args: {
                        data: i,
                        webviewIds: t
                    }
                }, "__uniapp__service");
            else {
                var c = JSON.stringify(i);
                plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE", '",').concat(c, ",").concat(JSON.stringify(t), ");"))
            }
        }
    }

1.wx.miniProgram.postMessage(定制事件)
2.wx.miniProgram.redirectTo 导航(向小程序发送消息,会在以下特定时机触发组件的message事件:小程序后退、组件销毁、分享、复制链接)
3.webview bindmessage

小程序->webview
1.重写url带上回调函数的参数(参数)

  1. 页面刷新 初始化生命周期 onLoad onMounted 判断获取结果或者是不是上一次调用状态
--------------webview--------------
        // uni.scanCode
	// uni.postMes
	// jWeixin.miniProgram.navigateBack
	wx.miniProgram.postMessage({
		data:{
			action:"scanCode",
		}
	})
	wx.miniProgram.redirectTo({
        url: '/pages/webview/webview'
    })

onLoad(async(options)=>{
	const {result} = Object.fromEntries(new URLSearchParams(location.search))
	if(!result) return
	const res = await scanPatient(result)
			if (res.code === 200) {
				uni.navigateTo({
					url: `/pages-sub/dynamic/patient/patient`
				});
	}
})
    
onLoad(async(options)=>{
	const {result} = Object.fromEntries(new URLSearchParams(location.search))
	if(!result) return
	const res = await scanPatient(result)
			if (res.code === 200) {
				uni.navigateTo({
					url: `/pages-sub/dynamic/patient/patient`
				});
	}
})
    
--------------小程序--------------
<web-view  :src="webviewStore.url" @message="onMessage" ></web-view>

const onMessage = (e)=>{
	const {action} = e.detail.data[0]
	if(action==="scanCode"){
		wx.scanCode({
			scanType: ['qrCode'],
			success: async (res1) => {
				const str = res1.result;
				if(import.meta.env.DEV){
                                    // localhost 192.168.1.xx  www.xx.com
					webviewStore.url = `http://localhost:9000/xx?code=${webviewStore.search.code}&result=${result}#/pages/xx/xx`
				}else{
                                    webviewStore.url = webviewStore.url = `http://www.xx.com:9000/xx?code=${webviewStore.search.code}&result=${result}#/pages/xx/xx`
				}
			},
		})
	}
}

3.websocket 需要后端 小程序后台socket合法域名

h5->后端->小程序API-> 小程序回调API或主动事件->后端->h5 需要制定统一规则 比如api调用与回调函数 调用api名称 参数 返回内容