小程序 webview 内嵌 h5 支付、路由跳转
发布于 3 年前 作者 nren 679 次浏览 来自 分享

一.介绍

允许通过特定方式在小程序内通过 webview 内嵌 h5 页面,跳转以及支付等流程。

大致流程如下:

小程序创建 webview 加载 h5 url(https://3400.retail.../shop/index),后续跳转通过 url 后拼接的参数判断是否要跳转新的 webview 页面(参数符合规则并且此跳转点击使用了 CommonRouter(见在H5页面中集成的小程序跳转路由),否则只是普通的页面跳转),支付环节需要小程序创建一个原生页面用于支付中转;

二.集成

1.创建 webview 容器用于承载 h5 页面(webview 组件用法参考官方组件) 

创建一个 webview page,用于加载 h5 url,路径没有要求,只需在 步骤2>参数拼接 时带上路径即可。

2.参数拼接

在 webview 加载 url 之前,需要在 url 后拼接上必要的参数,否则无法在新的 webview 打开下一次页面和在H5生成支付参数,在H5页面生成支付参数,请求后端生成支付参数接口要用小程序的appid,openid。webview 完整示例如下:

Page({
  data: {
    weburl:'' //加载的 url
  },
  onLoadfunction (options) {
    let url = decodeURIComponent(options.url)
    // url 拼接参数
    this.dealUrl(url)
  },
 
  dealUrl(url) {
    /**
      * miniProgramWebviewPath webview 的路径, 必传 解决采用小程序路由跳转H5嵌在多个小程序webview,跳回小程序webview
      * miniProgramPayPath 支付中转页路径,必传
      * pageStackLength 页面路由栈个数,必传 解决小程序跳转10级问题,改用redirectTo跳转,
      * ec_appid、ec_openid 两个参数为支付所需参数,必传
    */
    let miniProgramWebviewPath = encodeURIComponent(`${this.route}?weburl=`)
    let miniProgramPayPath = "pages/h5payment/payMiddle/index"
    let pageStackLength = getCurrentPages().length
    let ec_appid = "wxb956c83845b9c0"
    let ec_openid = "oOVgY4xSj-LyuFifcaF_YDcRLU"
 
    const urlParams = {}
    urlParams.ec_openid = ec_openid
    urlParams.ec_appid = ec_appid
    urlParams.miniProgramWebviewPath = miniProgramWebviewPath
    urlParams.pageStackLength = pageStackLength
    urlParams.miniProgramPayPath = miniProgramPayPath
 
    let weburl = this.onInsterParamsInUrl(url, urlParams)
    this.setData({
      weburl
    })
  },
 
  /**
   * 解析 url param
   */
  onInsterParamsInUrl(url, params) {
    let tempUrl = ''
    let hasParams = url.indexOf('?') !== -1;
    tempUrl = Object.keys(params).reduce(function (before, after) {
      return before + after + '=' + params[after] + '&'
    }, tempUrl)
    tempUrl = tempUrl.substring(0, tempUrl.length - 1)
    return hasParams ? (url + '&' + tempUrl) : (url + '?' + tempUrl)
  }
})

3.支付中转页

小程序内嵌 h5 的支付无法直接使用微信环境 sdk 支付,需要借助小程序的支付能力,所以小程序需要提供一个支付页面,接收在h5 生成的小程序支付参数,支付成功失败的回调url,发起小程序支付。小程序支付完成,需要跳转到结果回调页面,此页面需要由 webview 打开,所以在下面代码  PayDoneCallback 方法里的跳转路径对应 webview 的路径。

Page({
  onLoad: function(options) {
   /**
   * 解析 options, options为H5传过来的参数(支付参数,回跳H5的URL)
   */
    this.successUrl = options.successUrl
    this.failUrl = options.failUrl
    options.package = decodeURIComponent(options.package);
    options.paySign = decodeURIComponent(options.paySign);
    delete options.successUrl
    delete options.failUrl
    const { success, fail, cancel } = this.PayDoneCallback(this.successUrl, this.failUrl)
    this.payment({options, success, fail, cancel})
    
  },
  payment(opts) {
    const data = opts.options
    let hasComplete = false;
    wx.requestPayment({
      ...data,
      success: function(res){
        typeof opts.success =='function'&&opts.success()
      },
      fail: function(res) {
        if (res.errMsg == 'requestPayment:fail cancel') {
          typeof opts.cancel =='function'&&opts.cancel();
          hasComplete = true;
          return;
        }
        typeof opts.fail =='function'&&opts.fail()
      },
      complete:function(res){
        console.log(res)
        if (hasComplete) {
          hasComplete = false;
        }else if(res.errMsg =='requestPayment:fail cancel'||res.errMsg=="requestPayment:cancel") {
          typeof opts.cancel =='function'&&opts.cancel()
        }
        typeof opts.complete =='function' && opts.complete(res)
      }
    })
  },
  PayDoneCallback(successUrl, failUrl) {
    return {
      success(){
        wx.redirectTo({
          url: `/pages/h5payment/webview/webview?weburl=${successUrl}`
        });
      },
      fail(){
        wx.redirectTo({
          url: `/pages/h5payment/webview/webview?weburl=${failUrl}`
        });
      },
      cancel(){
        wx.redirectTo({
          url: `/pages/h5payment/webview/webview?weburl=${failUrl}`
        });
      }
    }
  }
})
回到顶部