1.APP跳转小程序
bash
goWX(payConfirmList) {
//小程序跳转路径 希携带参数
const miniProgramPath = 'payPages/pages/pay/payConfirm';
const path =miniProgramPath +'?payList=' +payConfirmList
+'&flag=app'+'&selectShop='+JSON.stringify(uni.getStorageSync('presentShop'))
+ '&openid='+uni.getStorageSync('CUSTOMER_USER_INFO_DY').user.openid
+ '&mer_id='+uni.getStorageSync('CUSTOMER_USER_INFO_DY').user.mer_id
+ '&mer_name='+uni.getStorageSync('CUSTOMER_USER_INFO_DY').user.mer_name
+ '&apptoken='+uni.getStorageSync('CUSTOMER_USER_INFO_DY').token;
console.log('[goWX] launch', miniProgramId, path);
this.showGoWXLoading();
plus.share.getServices(
(services) => {
const weixin = (services || []).find(
(item) => item.id === 'weixin'
);
if (!weixin) {
uni.showModal({
title: '微信 SDK 未就绪',
content:
'请使用「自定义调试基座」运行,并确认 manifest 已配置微信分享',
showCancel: false
});
return;
}
if (typeof weixin.launchMiniProgram !== 'function') {
uni.showModal({
title: '不支持跳转小程序',
content: '请重新制作自定义调试基座',
showCancel: false
});
return;
}
weixin.launchMiniProgram(
{
id: miniProgramId,//需是原生gh_开头的原生微信appid
path,
type: 2 //小程序版本 0-正式版; 1-测试版; 2-体验版。
},
() => {
this.hideGoWXLoading();
console.log('[goWX] launchMiniProgram success');
},
(err) => {
this.hideGoWXLoading();
console.log('[goWX] launchMiniProgram fail', err);
uni.showModal({
title: '打开小程序失败',
content:
(err && (err.message || err.code)) ||
JSON.stringify(err || {}),
showCancel: false
});
}
);
},
(err) => {
this.hideGoWXLoading();
console.log('[goWX] getServices fail', err);
uni.showModal({
title: '获取分享服务失败',
content: JSON.stringify(err || {}),
showCancel: false
});
}
);
},
2.小程序获取APP参数,支付
onLoad获取参数
创建支付订单
bash
createOrder() {
uni.showLoading({
title: '支付中',
mask: true
})
let data = {
openid: this.openid,
// openid:'opP7A5b-k_ibUp0cr7RF853FCC6M',
charge_list_ids: this.selectId, //物业缴费项id:(多个英文逗号隔开),
pay_mode: '扫码支付',
pay_channel: 'wx_lite',
mer_id: this.mer_id,
mer_name: this.mer_name,
able_pay_amt: this.totalCount,
goods_title: '市场管理费',
goods_desc: '市场管理费',
device_type: 1,
unit_area: this.payList[0].unit_area_name,
unit_location: this.payList[0].unit_location_name,
unit_no: this.payList[0].unit_no,
unit_id: this.payList[0].unit_id
}
this.Util.postRequest(
'index/system/wycharge/order/create',
data,
this.isFromApp() ? this.apptoken : undefined
).then(res => {
uni.hideLoading()
if (res.status === 200) {
let payInfo = res.data;
if (res.message == '您还有待支付的订单') {
console.log(res)
wx.requestPayment({
'timeStamp': payInfo.pay_info.timeStamp, //时间戳
'nonceStr': payInfo.pay_info.nonceStr, //随机字符串
'package': payInfo.pay_info.package, //prepay_id 参数值
'signType': payInfo.pay_info.signType,
'paySign': payInfo.pay_info.paySign, //签名
'success': (res) => {
this.handlePaySuccess()
},
})
} else {
wx.requestPayment({
'timeStamp': payInfo.timeStamp, //时间戳
'nonceStr': payInfo.nonceStr, //随机字符串
'package': payInfo.package, //prepay_id 参数值
'signType': payInfo.signType,
'paySign': payInfo.paySign, //签名
'success': (res) => {
this.handlePaySuccess()
},
'fail': function(res) {
console.log(res)
}
})
}
} else {
uni.showModal({
title: '提示',
content: res.message,
showCancel: false
})
}
})
3.支付成功,返回APP
bash
handlePaySuccess() {
//区分小程序支付,还是app跳转来支付
if (this.isFromApp()) {
//返回APP,通知APP支付成功参数
this.appParameter = JSON.stringify({
paySuccess: true
})
this.showAppPaySuccess = true
} else {
uni.showModal({
title: '提示',
content: '支付成功',
showCancel: false,
success: (res) => {
if (res.confirm) {
let pages = getCurrentPages()
let beforePage = pages[pages.length - 2]
uni.navigateBack({
success: function() {
beforePage.onLoad()
}
})
}
}
})
}
},
app跳转来的支付,不能使用uni.showModal返回APP,需要手动点击返回按钮才能正确返回APP
bash
<!-- App支付成功弹框,用户主动点击返回App -->
<view class="pay-success-mask" v-if="showAppPaySuccess" @click.stop>
<view class="pay-success-modal">
<view class="pay-success-icon-wrap">
<view class="pay-success-icon">✓</view>
</view>
<view class="pay-success-title">支付成功</view>
<view class="pay-success-content">请点击下方按钮返回 App</view>
<view class="pay-success-footer">
<button class="launch-app-btn" open-type="launchApp" :app-parameter="appParameter"
@launchapp="onLaunchApp" @error="onLaunchAppError">返回 App</button>
</view>
</view>
</view>
bash
showAppPaySuccess: false,
appParameter: '',
onLaunchApp(e) {
console.log('launchApp success', e)
this.showAppPaySuccess = false
},
onLaunchAppError(e) {
console.error('launchApp fail', e)
uni.showModal({
title: '提示',
content: '返回App失败,请手动关闭小程序',
showCancel: false
})
},
4.APP接收小程序支付成功参数
miniProgramPayReturn.js
bash
// #ifdef APP-PLUS
/**
* 小程序 launchApp 回传 app-parameter,对应微信 SDK onResp.extMsg
* Android: WXEntryActivity.onResp -> WXLaunchMiniProgram.Resp.extMsg
* iOS: WXApiDelegate.onResp -> WXLaunchMiniProgramResp.extMsg
* uni-app 云端打包会把 extMsg 桥接到 JS,Android/iOS 读取方式略有差异
*/
/** 解析 extMsg / extraData 字符串 */
export function parseMiniProgramExtMsg(extMsg) {
if (extMsg == null || extMsg === '') return null
if (typeof extMsg === 'object') return extMsg
const raw = String(extMsg).trim()
if (!raw) return null
try {
return JSON.parse(raw)
} catch (e) {
if (raw.includes('paySuccess')) {
return {
paySuccess: raw.includes('true') ||
raw.includes('"paySuccess":true') ||
raw.includes('paySuccess=1')
}
}
return null
}
}
/** Android onResp.extMsg:优先 arguments,后台唤醒时再从 Intent 补读 */
export function getAndroidMiniProgramExtMsg() {
let extMsg = plus.runtime.arguments
if (extMsg) return extMsg
try {
const main = plus.android.runtimeMainActivity()
const intent = plus.android.invoke(main, 'getIntent')
if (!intent) return ''
const keys = [
'_wxapi_launch_mini_program_resp_ext_msg',
'wx_launch_mini_program_ext_msg',
'extMsg',
'APP_PARAMETER'
]
for (let i = 0; i < keys.length; i++) {
const value = plus.android.invoke(intent, 'getStringExtra', keys[i])
if (value) return value
}
} catch (e) {
console.log('[miniProgramPayReturn] android extMsg read fail', e)
}
return ''
}
/** iOS onResp.extMsg:uni 桥接至 plus.runtime.arguments */
export function getIOSMiniProgramExtMsg() {
return plus.runtime.arguments || ''
}
export function clearMiniProgramExtMsg() {
plus.runtime.arguments = null
plus.runtime.arguments = ''
}
/** 微信文档:从 App 打开的小程序返回时 launcher 为 miniProgram */
export function isFromMiniProgramReturn() {
return plus.runtime.launcher === 'miniProgram'
}
export function getMiniProgramReturnDelayMs() {
const osName = uni.getSystemInfoSync().osName
return osName === 'ios' ? 500 : 200
}
/** 按平台读取 onResp.extMsg 并解析为 extraData */
export function readMiniProgramPayExtraData() {
const osName = uni.getSystemInfoSync().osName
let extMsg = ''
if (osName === 'android') {
extMsg = getAndroidMiniProgramExtMsg()
} else if (osName === 'ios') {
extMsg = getIOSMiniProgramExtMsg()
} else {
extMsg = plus.runtime.arguments || ''
}
if (!extMsg) return null
// 有 extMsg 即视为小程序回传;launcher 仅作辅助日志
if (!isFromMiniProgramReturn()) {
console.log('[miniProgramPayReturn] extMsg without miniProgram launcher', plus.runtime.launcher)
}
return parseMiniProgramExtMsg(extMsg)
}
// #endif
app.vue
bash
import {
readMiniProgramPayExtraData,
clearMiniProgramExtMsg,
getMiniProgramReturnDelayMs
} from './common/miniProgramPayReturn.js'
onLaunch: function() {
plus.globalEvent.addEventListener('newintent', () => {
this.handleMiniProgramPayReturn();
});
}
onShow: function(options) {
/** App 从小程序返回:Android onResp.extMsg / iOS onResp.extMsg */
handleMiniProgramPayReturn() {
const delay = getMiniProgramReturnDelayMs()
setTimeout(() => {
const extraData = readMiniProgramPayExtraData()
if (extraData && extraData.paySuccess) {
uni.$emit('miniProgramPayResult', extraData)
}
clearMiniProgramExtMsg()
}, delay)
},
}
跳转小程序页处理
bash
onLoad() {
this.selectShop = uni.getStorageSync('presentShop')
this.menusList.forEach((list) => {
list.listData = []
})
uni.$on('miniProgramPayResult', this.onMiniProgramPayResult)
this.payDatail()
},
onUnload() {
uni.$off('miniProgramPayResult', this.onMiniProgramPayResult)
},
methods: {
onMiniProgramPayResult(extraData) {
if (extraData && extraData.paySuccess) {
this.refreshAfterPaySuccess()
}
},
refreshAfterPaySuccess() {
uni.showToast({
title: '支付成功',
icon: 'success'
})
this.menusList.forEach((list) => {
list.listData = []
})
if (this.companyList.length) {
this.payListDetail()
}
this.hideModal()
},
}