实现webView和小程序通讯,webView和iframe通讯,而后以webView作为中转站,实现webView中 的iframe和小程序通讯。

之前领导要求就打通webView、小程序和iframs三者之间的通讯做一份技术文档说明,功能是做出来了,结果后面没有接到那个项目,也就没有继续开发下去,但也值得记录一下。

项目目标

实现webView和小程序通讯,webView和iframe通讯,而后以webView作为中转站,实现webView中的iframe和小程序通讯。

需求确定

在商城小程序中以webView的形式引入客服聊天页面IM,在IM中以iframe的形式嵌入第三方页面,内容和样式第三方自定义。iframe的操作需求整理如下:

  1. 跳转到文章详情

  2. 链接到另一个客服

  3. 跳转到商品详情

  4. 跳转到商品购物车页

  5. 跳转到订单详情

  6. 发送消息

可以整理为三大类:1.小程序页面跳转2.向某一个客服发起会话3.在当前会话发送消息

实现

  1. webView和小程序通讯

    官方文档对于web-view组件的描述是:承载网页的容器。会自动铺满整个小程序页面,个人类型的小程序暂不支持使用。所以在小程序中webView是不能以弹窗的形式或者占据页面一部分和其它内容共存,这个特点微信小程序和支付宝小程序都具备。

    webView组件和小程序只能通过bindmessage事件绑定进行通讯,对于这个事件官方的描述是这样的:网页向小程序 postMessage 时,会在特定时机(小程序后退、组件销毁、分享)触发并收到消息。也就是说无论webView通过postMessage向小程序发送多少次消息,只要不是在特定的时机(小程序后退、组件销毁、分享),小程序就不会收到webView的消息。

    通过以上两点,我们可以确定小程序的当前页面只有一个webView是有效内容,那小程序和webView之间的通讯最常用的也就是小程序进行页面的跳转了。

// 在webView页面中引入微信JS文件
<script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
// 进行页面跳转
wx.miniProgram.navigateTo({
    url: '/pages/home2/index', // 小程序页面路径
})

  2. webView和内嵌的iframe页面通讯

      两者通过postMessage进行通讯,主要代码如下

window.addEventListener('message', (event) => {
    if (window.parent !== event.source) { return }
    console.log(event, 'event');  //接收到的信息
    top.postMessage("发送给父级页面的信息,可以为对象", '父级页面url或者*');
}, false);

完整主要代码

  1. 小程序

<WebView src="xxxx"></WebView>
  1. webView客服聊天页面IM

// 在webView页面中引入微信JS文件
<script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>

let ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == "micromessenger") {
    //ios的ua中无miniProgram,但都有MicroMessenger(表示是微信浏览器)
    wx.miniProgram.getEnv((res) => {
        if (res.miniprogram) {
            console.log("在小程序里");
            // 接收到消息
            window.addEventListener('message', this.fnTest, false);
        } else {
            console.log("不在小程序里");
        }
    })
} else {
    console.log('不在微信里');
}

fnTest = (event) => {
    let data = event.data;
    if (data.operation === 'msg') {
        // 在当前会话发送消息
        let r = Math.ceil(Math.random() * 100000)
        let uuid = this.state.memberData.memberId + Date.now() + r;
        let sendData = '';
        // 0视频,1图片,2文件,4文本,8富文本,103iframe
        switch (data.data.type) {
                // 消息类型处理
            case 103:
                sendData = data.data.iframeUrl;
                break;
        }
        // this.sendMessage IM中发送消息函数
        this.sendMessage(sendData, data.data.type, uuid);
    } else if (data.operation === 'action') {
        // 小程序页面跳转
        wx.miniProgram.navigateTo({
            url: data.data.url  //'/pages/home2/index'
        })
    } else if (data.operation === 'chat') {
        let code = StringUtils.getQueryString('code')
        let url = `index.html?code=${code}&otherId=7&sessionScope=1&userCode=${data.data.userCode}`
        // 向某一个客服发起会话
        window.app.router.push(url)
    }
}

  3. 第三方iframe页面

<!-- 简单的模拟html页面 -->
<span class="btn" style="margin-left: 0">发送消息</span>
<span class="action" style="background: lightpink">跳转页面</span>
<span class="chat" style="background: lightseagreen">跟他聊聊</span>
window.addEventListener('message', (event) => {
   if (window.parent !== event.source) { return }
   console.log(event, 'event');  //接收到的信息
   top.postMessage("发送给父级页面的信息,可以为对象", '父级页面url或者*');
}, false);

// operation  操作类型string  msg:发送消息 ,action:跳转页面,chat:发起聊天
// type 消息类型string operation为msg时,0视频,1图片,2文件,4文本,8富文本,103iframe
// 其他具体参数另定
$('.btn').on('click', function () {
    top.postMessage({
        operation: 'msg',
        data: {
            data: '消息内容',
            type: 103,  //Number类型
            size: 110,  //Number类型
            name: '',  //文件名称
            iframeUrl: 'https://dev.iservice.dtyunxi.cn/i-service/dev/iservice-customer-web-pc/test.html'
        },
    }, '*')
});
$('.action').on('click', function () {
    top.postMessage({
        operation: 'action',
        data: {
            url: '/pages/home2/index?xxx=xx', // 需要跳转页面
        }
    }, '*')
});
$('.chat').on('click', function () {
    top.postMessage({
        operation: 'chat',
        data: {
            userCode: '007',  // 客服工号
        }
    }, '*')
});

定义参数

参数名类型是否必填描述
operation string 枚举值:1. msg:发送消息 2.action:跳转页面 3.chat:发起聊天
data object  
data参数
参数名类型是否必填描述
type number operation为msg时必填 0视频,1图片,2文件,4文本,8富文本,103iframe
size number type为2时必填 文件大小,默认为0
name string type为2时必填 文件名称,默认为空
iframeUrl string type为103时必填 iframe路径
data string operation为msg且type不为103时必填 type为0,1,2时,为视频、图片、文件的路径,type为4,8时,为发送的内容
url string operation为action时必填 小程序跳转路径
userCode string operation为chat时必填 客服工号

支付宝小程序

小程序代码
// .axml
<view class="page">
    <web-view src="xxxx" onMessage="onmessage"></web-view>
</view>

// .js
Page({
    onmessage(e){
        // 拿到webView数据,进行一系列事件处理
        console.log(e,'e')
    }
});
webView代码
// 引入js
<script type="text/javascript" src="https://appx/web-view.min.js"></script>
<!-- 如该 H5 页面需要同时在非支付宝客户端内使用,为避免该请求404,可参考以下写法 -->
<!-- 请尽量在 html 头部执行以下脚本 -->
<script>
    if (navigator.userAgent.indexOf('AlipayClient') > -1) {
        document.writeln('<script src="https://appx/web-view.min.js"' + '>' + '<' + '/' + 'script>');
    }
</script>

componentWillUnmount() {
    // 离开页面,清除监听
    window.removeEventListener('message', this.fnTest, false);
}

fnTest = (event) => {
    // alert(JSON.stringify(event), 'event')
    let data = event.data;
    if (data.operation === 'msg') {
        // 在当前会话发送消息
        let r = Math.ceil(Math.random() * 100000)
        let uuid = this.state.memberData.memberId + Date.now() + r;
        let sendData = '';
        // 0视频,1图片,2文件,4文本,8富文本,103iframe
        switch (data.data.type) {
                // 消息类型处理
            case 103:
                sendData = data.data.iframeUrl;
                break;
        }
        // this.sendMessage IM中发送消息函数
        this.sendMessage(sendData, data.data.type, uuid);
    } else if (data.operation === 'action') {
        // 小程序页面跳转
        // my.navigateTo({ url: `../../${data.data.url}` });
        my.navigateTo({ url: `../test/test` });
    } else if (data.operation === 'chat') {
        let code = StringUtils.getQueryString('code')
        let url = `index.html?code=${code}&otherId=7&sessionScope=1&userCode=${data.data.userCode}`
        // 向某一个客服发起会话
        window.app.router.push(url)
    }
}

componentDidMount() {
    window.addEventListener('message', this.fnTest, false);
}

 

 特别说明:webView向支付宝小程序发送消息时,并没有微信小程序接收webView消息的限制【需要在特定时机(小程序后退、组件销毁、分享)触发才能收到消息】,只要webView通过 my.postMessage(obj)向小程序发送消息,小程序就能接收到消息,支付宝小程序和webView的通讯更方便灵活。

 

流程图

 

 

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/kewenxin/p/14515345.html