如何将uniapp开发的小程序移植到公众号H5
发布于 2021-09-27 16:22
背景
下文示例代码需要用到uni-app的 条件编译,关于条件编译的用法可参考这里:https://uniapp.dcloud.io/platform?id=preprocessor
一、修改uniapp项目工程配置
1、修改manifest.json的h5设置,设置 运行的基础路径 为 /xxxx-mp/,此处的xxxx-mp就是H5在nginx的发布路径;
2、修改manifest.json的h5设置,设置 地图与定位 的key,该key从 腾讯地图管理后台创建;
二、修改后端API访问方式
// #ifdef MP-WEIXIN
import Fly from 'flyio/dist/npm/wx'
import serverUrl from './serverUrl.js'
const fly = new Fly()
// #endif
// #ifdef H5
let baseURL = ''
import Fly from 'flyio/dist/npm/fly'
const fly = new Fly()
fly.config.baseURL = baseURL
// #endif
在h5的情况下,开发过程中uniapp会加载vue.config.js文件的配置,如果我们在开发过程中要用到测试服务器的接口,可以在vue.config.js文件内配置proxy指向 https://your-dev-server-url.com
module.exports = {
devServer: {
// proxy: 'https://your-product-server-url.com',
proxy: 'http://your-dev-server-url.com',
}
}
三、访问微信API
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
由于我们是在uniapp中使用,可以借助npm包,这里使用的是weixin-js-sdk,只是对jssdk的一层浅包装,可以通过npm安装,支持 CommonJS,便于 browserify, webpack 等直接使用。
npm install weixin-js-sdk
安装完成之后,在适当的地方引入并初始化,由于H5有多种启动方式,有多个入口,可能需要在多个位置初始化,所以把这个初始化提取为全局方法,放在store里。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import api from '../js/flyiowrapper/api.js'
// #ifdef H5
import wx from 'weixin-js-sdk'
// #endif
const store = new Vuex.Store({
state: {
// #ifdef H5
// jssdk是否已经初始化
wxConfiged: false,
// #endif
},
mutations: {
setWxConfiged(state, configed) {
state.wxConfiged = configed
},
},
actions: {
configWxSdk({
commit,
state
}) {
if (state.wxConfiged) return
let url = window.document.location.href
let urlList = url.split('#')
if (urlList.length > 0) {
url = urlList[0]
}
if (process.env.NODE_ENV == 'development') {
url = 'http://your-product-url.com/xxxx-mp/'
}
console.log('configWxSdk', url)
let merchantCode = uni.getStorageSync('merchantCode')
api.getWxConfig(url, merchantCode).then(res => {
console.log('getWxConfig', res)
wx.config({
debug: false, // 开启调试模式,
appId: res.data.appId, // 必填,企业号的唯一标识,此处填写企业号corpid
nonceStr: res.data.nonceStr, // 必填,生成签名的随机串
signature: res.data.signature, // 必填,签名,见附录1
jsApiList: ['scanQRCode', 'chooseWXPay', 'getLocation',
'openLocation'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
commit('setWxConfiged', true)
})
}
},
})
export default store
在需要使用的地方引入,比如在主页的onLoad中调用,如下
import { mapActions } from 'vuex'
export default {
onLoad(){
// #ifdef H5
this.configWxSdk()
// #endif
},
methods:{
// #ifdef H5
...mapActions(['configWxSdk']),
// #endif
}
}
JSSDK配置好之后,就可以开始使用了。
config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
四、几个要兼容处理的uni API
(1)uni.scanCode()
onScan() {
console.log('onScan')
// #ifdef MP-WEIXIN
this.scanInMp()
// #endif
// #ifdef H5
this.scanInH5()
// #endif
},
scanInH5() {
let that = this
wx.scanQRCode({
needResult: true,
scanType: ["qrCode"],
success: function(res) {
console.log('scanCode success', res)
// TODO
}
})
},
scanInMp() {
uni.scanCode({
success: (res) => {
console.log('scanCode success' + res)
}
})
},
(2)uni.getLocation()
按照官方的说法,这个api是支持H5的,但从实际使用的情况看,支持的不好,我没调成功过,所以还是用条件编译来处理,H5的时候该用weixin-jssdk的wx.getLocation来处理,这个获取的位置精度较高,且速度快。
getPositionAndRefresh(needStopPullDown = false) {
console.log('getPositionAndRefresh')
// #ifdef MP-WEIXIN
this.getPosAndRefresh_Mp()
// #endif
// #ifdef H5
this.getPosAndRefresh_H5()
// #endif
},
getPosAndRefresh_H5() {
console.log('getPosAndRefresh_H5')
// 因为调试时,在浏览器中,下面的wx.getLocation调用失败
if(process.env.NODE_ENV == 'development'){
this.position = {
latitude: 22.728748,
longitude: 114.05278
}
// TODO
return
}
let that = this
wx.getLocation({
type: 'wgs84',
success(res) {
console.log('wx.getLocation success', res)
that.position = {
latitude: res.latitude,
longitude: res.longitude
}
// TODO
},
fail(res) {
console.log('wx.getLocation fail', res)
uni.showToast({
icon: 'none',
title: '定位失败, ....'
})
}
})
},
五、处理好自动登录逻辑
先调用微信的authorize接口
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
系统会自动跳转到redirect_uri/?code=CODE&state=STATE中,这个REDIRECT_URL是业务系统的一个接口,CODE参数是微信服务器给的。
在redirect_uri中拿到了code,请求以下链接获取access_token:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
在这个返回值中就带了openId,格式如下
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
有了openId,就可以判定该用户是否存在,要不要自动登录了。
六、微信支付
weixin-jssdk的说明
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
WeixinJSBridge.invode参照这里:
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
在项目中代码实现如下:
export function hjPayWrapper(orderInfo, onSuccess, onFail, paramList) {
// #ifdef MP-WEIXIN
payByMp(orderInfo, onSuccess, onFail, paramList)
// #endif
// #ifdef H5
// payByWXJSBridge(orderInfo, onSuccess, onFail, paramList)
payByJSSDK(orderInfo, onSuccess, onFail, paramList)
// #endif
}
export function payByMp(orderInfo, onSuccess, onFail, paramList) {
uni.requestPayment({
provider: 'wxpay',
orderInfo: orderInfo.orderId,
timeStamp: orderInfo.timeStamp,
nonceStr: orderInfo.nonceStr,
package: orderInfo.package,
signType: orderInfo.signType,
paySign: orderInfo.paySign,
success: (payRes) => {
onSuccess(orderInfo, paramList)
},
fail: (payErr) => {
console.log('updatePaidStatus', payErr)
that.$refs.uTips.show({
type: 'warning',
title: `启动支付失败`
})
}
})
}
//
function payByWXJSBridge(orderInfo, onSuccess, onFail, paramList) {
console.log('payByWXJSBridge', orderInfo)
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
'appId': orderInfo.appId,
'nonceStr': orderInfo.nonceStr, // 支付签名随机串,不长于 32 位
'package': orderInfo.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
'signType': orderInfo.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
'paySign': orderInfo.paySign, // 支付签名
},
function(res) {
console.log('getBrandWCPayRequest res', res)
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
if(onSuccess) onSuccess(orderInfo, paramList)
}else if(res.err_msg == 'get_brand_wcpay_request:fail'){
console.log('getBrandWCPayRequest err')
if(onFail) onFail(orderInfo, paramList)
}
}
)
}
function payByJSSDK(orderInfo, onSuccess, onFail, paramList) {
console.log('payByJSSDK', orderInfo)
wx.chooseWXPay({
appId: orderInfo.appId,
timestamp: orderInfo.timeStamp,
nonceStr: orderInfo.nonceStr, // 支付签名随机串,不长于 32 位
package: orderInfo.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: orderInfo.signType, // 微信支付V3的传入RSA,微信支付V2的传入格式与V2统一下单的签名格式保持一致
paySign: orderInfo.paySign, // 支付签名
success: function (res) {
// 支付成功后的回调函数
if(onSuccess) onSuccess(orderInfo, paramList)
},
fail: function(err){
if(onFail) onFail(orderInfo, paramList)
}
});
}
实现过程中,在payByJSSDK内,由于代码拷贝把timestamp写成timeStamp,结果总是报签名错误,搞得我总是怀疑是不是后端把签名的方式写错了,最终还是自己的锅,切记切记。
https://your-url.com/xxxx-mp/q?m=<mcode>&sn=<nnnn>
其中:<mcode>是我们给客户分配的唯一标识,<nnnn>是充电桩的序列号。
https://your-url.com/h5/q?m=<mcode>&sn=<nnnn>
https://your-url.com/xxxx-mp/q?sn=<nnnn>
本文来自网络或网友投稿,如有侵犯您的权益,请发邮件至:aisoutu@outlook.com 我们将第一时间删除。
相关素材