一、小程序web-view非调试模式下无法调用微信支付
最近在做公司的小程序项目时,在小程序里嵌入已开发好的H5商城页面,在本地真机调试的时候,H5页面能够支付成功,但是提交到体验版和正式版之后发现不能调起微信支付,最后查看了很多文档发现小程序的 web-view 不支公众号支付,只能通过跳回小程序调用小程序支付的 API,具体查看 API web-view
实现大体思路:
- 在H5页面进行下单获取支付参数,然后判断是否小程序环境,如果在,获取到的支付参数返回到小程序;
- 小程序新建一个空白页面,在 onLoad 中获取参数,调用 wx.requestPayment(Object object) 接口完成支付;
- 在支付成功的回调函数中处理相关逻辑。
二、 web-view 刷新
小程序嵌套H5页面时,有时页面在来回切换时需要刷新该H5页面,但是微信未提供相关接口,但是可以通过折中的方式来实现。
方式一
设置 web-view 动态路由地址
<web-view src="{{url}}" />
在 onShow 中修改 url 地址带时间戳参数
data: {
url: ''
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
const baseUrl = 'https://juejin.cn/user/272334611820302/posts'
const timeStamp = new Date().getTime()
this.setData({
url: `${baseUrl}?=${timeStamp}`
})
},
方式二
首先,让webview做条件渲染:
<web-view wx:if="{{url}}" src="{{url}}" />
data: {
base_url: config.kalatong_base_url + '……',
url: ''
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
let url = this.data.base_url + "#wechat_redirect"
this.data.url = decodeURIComponent(url)
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
this.refreshWebview()
},
需要刷新时,先把url设为空,销毁当前webview。然后再把url设为当前值。如下:
refreshWebview: function () {
let tmpUrl = this.data.url;
this.setData({
url: ''
});
setTimeout(() => {
this.setData({
url: tmpUrl
})
}, 500);
}
这样便可以在不影响导航栏历史的情况下刷新页面,也可以是跳转url。
这里setData之后,页面内容的更新应该是异步执行的,因此我们后一次修改url需要延时一小段时间,否则会出现error。
猜测setData后页面实际更新应该是在下一次的requestAnimationFrame,因此如果页面完全不卡顿可能16ms就可以了,保险起见,我设了100ms。
但是100ms也不保险,有些页面会空白,最后置成500ms
三、wx.miniProgram.getEnv 异步方法
在项目中,先判断当前环境是否小程序,如果是小程序走小程序的逻辑,如果不是走 H5 逻辑,项目中代码如下:
mounted() {
this.isWechat() // 1
this.init() // 2
},
init() {
// 2-1
if(this.miniProgramFlag){
// 小程序打开
this.getMiniprogramOpenId()
} else {
....
}
}
/**
* 是否在微信浏览器中打开、是否是小程序
*/
isWechat() {
wx.miniProgram.getEnv((res)=> {
// 1-1
if(res.miniprogram) {
this.weChatFlag = false
this.miniProgramFlag = true
} else {
....
}
})
},
按照设想,代码执行顺序是:
1 >>> 1-1 >>> 2 >>> 2-1
但实际执行顺序是:
1 >>> 2 >>> 2-1 >>> 1-1
所以 wx.miniProgram.getEnv 异步执行,小程序环境的判断需要写在 getEnv 的回调函数中,最终修改项目代码如下:
mounted() {
this.isWechat() // 1
},
init() {
// 2-1
if(this.miniProgramFlag){
// 小程序打开
this.getMiniprogramOpenId()
} else {
....
}
}
/**
* 是否在微信浏览器中打开、是否是小程序
*/
isWechat() {
wx.miniProgram.getEnv((res)=> {
// 1-1
if(res.miniprogram) {
this.weChatFlag = false
this.miniProgramFlag = true
} else {
....
}
})
},
四、小程序地址栏取参,会截断 = 后面的数据
在做小程序 web-view 内嵌商城H5, 在点击支付时,需要 H5 页面传递支付相关参数到小程序内,在 onLoad 方法中接收地址栏参数, 代码如下:
// H5
clickPay() {
const package = 'prepay_id=uuduudueyy838'
wx.miniProgram.navigateTo({
url:`../payment/index?package=${package}&signType=${pay_data.signType}&timeStamp=${pay_data.timeStamp}&nonceStr=${pay_data.nonceStr}&paySign=${paySign}`
})
}
/**
* 小程序————————生命周期函数--监听页面加载
*/
onLoad(query:any) {
console.log('支付页参数query', query)
this.setData({
timeStamp: query.timeStamp || '',
nonceStr: query.nonceStr || '',
package: query.package || '',
signType: query.signType || '',
paySign: query.paySign || ''
})
},
其中 package 参数包含 prepay_id= 导致在支付请求的时候 package 传递参数是 package: 'prepay_id', 导致在调用小程序支付的时候,一直报错:调用祝福 JSAPI 缺少参数: total_fee 。解决方法在 H5 对该参数进行 encodeURIComponent 在小程序内进行 decodeURIComponent
// H5
clickPay() {
const encode_package = encodeURIComponent(pay_data.package)
const encode_paySign = encodeURIComponent(pay_data.paySign)
wx.miniProgram.navigateTo({
url:`../payment/index?package=${encode_package}&signType=${pay_data.signType}&timeStamp=${pay_data.timeStamp}&nonceStr=${pay_data.nonceStr}&paySign=${encode_paySign}`
})
}
/**
* 小程序————————生命周期函数--监听页面加载
*/
onLoad(query:any) {
console.log('支付页参数query', query)
this.setData({
timeStamp: query.timeStamp || '',
nonceStr: query.nonceStr || '',
package: decodeURIComponent(query.package) || '',
signType: query.signType || '',
paySign: decodeURIComponent(query.paySign) || ''
})
},