当前位置: 首页 > article >正文

uniapp 微信小程序webview 和 h5数据通信

项目是uniapp编写,因为是先开发了h5和app,小程序是突然要用的,做兼容开发已经来不及,由于微信小程序webview载入h5 因为通信必须要特殊限制(网页向小程序 postMessage 时,会在以下特定时机触发并收到消息:小程序后退、组件销毁、分享、复制链接(2.31.1)。e.detail = { data },data是多次 postMessage 的参数组成的数组。),不能满足使用,所以搞了一套特别low的通信机制,缺点是通信时候会有一个loading的过渡页面

业务逻辑大致为:
1、微信小程序webview访问h5带参数的url,获取初始的参数,可以携带页面参数或者登录token等,通过reciver接受h5返回的参数。
2、h5通过一个中间html页面存储小程序的通信逻辑,然后在h5页面通过定时器一直获取缓存本地的数据,根据数据信息执行不同的业务逻辑

1、微信小程序项目
(1)微信小程序项目
index.vue

<template>
  <web-view v-if="src" :src="src" bindload="bindload" binderror="binderror"></web-view>
</template>

<script lang="ts">
import { cfg } from '@/cfg'
import Base64 from '@/utils/Base64'

export default {
  data() {
    return {
      src: '',
    }
  },
  onLoad(e: any) {
    let loginA = parseInt(e.loginA)
    console.log(e.loginA)
    if (loginA) {
      let self = this
      wx.login({
        success(res: any) {
          // 自动登录成功
          self.msg(Base64.encode64('loginA,' + JSON.stringify([loginA, cfg.mpApp, res.code])))
        },
        fail(res: any) {
          // 自动登录失败
          self.msg(Base64.encode64('loginAFail,' + JSON.stringify([loginA, res.errMsg])))
        },
      })
      return
    }

    this.msg(e.msg)
  },
  methods: {
    msg(msg: any) {
      if (msg) {
        this.src = cfg.mpUrl + 'static/mpMsg.html?uid=' + cfg.mpid + '&msg=' + msg
        // this.src = 'http://www.baidu.com/#/'
        console.log(this.src)
        // 超时自动关闭
        // @ts-ignore
        this['$timer'] = setTimeout(() => {
          this.navBack()
        }, 3000)
        return
      }

      this.navBack()
    },
    bindload() {
      console.log('bindload')
      this.navBack()
    },
    binderror() {
      console.log('binderror')
      this.navBack()
    },
    navBack() {
      let pages = getCurrentPages()
      if (pages[pages.length - 1].$vm == this) {
        uni.navigateBack()
      }

      // @ts-ignore
      let timer = this['$timer']
      if (timer) {
        // @ts-ignore
        delete this['$timer']
        clearTimeout(timer)
      }
    },
  },
}
</script>

<style></style>

(2)reciver.vue

<template>
  <view id="preloader"></view>
</template>

<script lang="ts">
import { App } from '@/store/app'
import Base64 from '@/utils/Base64'

export default {
  data() {
    return {
      src: '',
    }
  },
  onLoad(e: any) {
    try {
      let msg = e.msg
      if (msg) {
        msg = Base64.decode64(msg)
        let i = msg.indexOf(',')
        let key = msg
        let val = ''
        if (i > 0) {
          key = msg.substring(0, i)
          val = msg.substring(i + 1)
        }
        // 如果是pc小程序bridge支付,则直接跳转到支付页面
        // const info = uni.getSystemInfoSync()
        // if ((info?.deviceType == 'pc' || info?.deviceType == 'PC') && key == 'pay') {
        //   uni.redirectTo({
        //     url: `/pages/index/pay?pay=${Base64.encode64(val)}`,
        //   })
        // } else {
        //   uni.navigateBack({
        //     complete() {
        //       // setTimeout(() => {
        //       App.mpRecieverMsg(key, val)
        //       // }, 100)
        //     },
        //   })
        // }
        uni.navigateBack({
          complete() {
            // setTimeout(() => {
            App.mpRecieverMsg(key, val)
            // }, 100)
          },
        })
        return
      }
    } catch (e) {
      console.error(e)
    }

    uni.navigateBack()
  },
  methods: {},
}
</script>

<style scoped>
#preloader {
  position: absolute;
  width: 30px;
  height: 30px;
  background: rgba(253, 87, 17, 1);
  border-radius: 50px;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  -webkit-animation: preloader_1 1.5s infinite linear;
  -moz-animation: preloader_1 1.5s infinite linear;
  -ms-animation: preloader_1 1.5s infinite linear;
  animation: preloader_1 1.5s infinite linear;
}
#preloader:after {
  position: absolute;
  width: 50px;
  height: 50px;
  border-top: 10px solid rgba(255, 139, 9, 1);
  border-bottom: 10px solid rgba(255, 139, 9, 1);
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-radius: 50px;
  content: '';
  top: -20px;
  left: -20px;
  -webkit-animation: preloader_1_after 1.5s infinite linear;
  -moz-animation: preloader_1_after 1.5s infinite linear;
  -ms-animation: preloader_1_after 1.5s infinite linear;
  animation: preloader_1_after 1.5s infinite linear;
}

@-webkit-keyframes preloader_1 {
  0% {
    -webkit-transform: rotate(0deg);
  }
  50% {
    -webkit-transform: rotate(180deg);
    background: #ff4f11;
  }
  100% {
    -webkit-transform: rotate(360deg);
  }
}
@-webkit-keyframes preloader_1_after {
  0% {
    border-top: 10px solid rgba(253, 87, 17, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
  50% {
    border-top: 10px solid rgba(253, 87, 17, 1);
    border-bottom: 10px solid rgba(253, 87, 17, 1);
  }
  100% {
    border-top: 10px solid rgba(255, 139, 9, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
}

@-moz-keyframes preloader_1 {
  0% {
    -moz-transform: rotate(0deg);
  }
  50% {
    -moz-transform: rotate(180deg);
    background: #ff4f11;
  }
  100% {
    -moz-transform: rotate(360deg);
  }
}
@-moz-keyframes preloader_1_after {
  0% {
    border-top: 10px solid rgba(255, 139, 9, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
  50% {
    border-top: 10px solid rgba(253, 87, 17, 1);
    border-bottom: 10px solid rgba(253, 87, 17, 1);
  }
  100% {
    border-top: 10px solid rgba(255, 139, 9, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
}

@-ms-keyframes preloader_1 {
  0% {
    -ms-transform: rotate(0deg);
  }
  50% {
    -ms-transform: rotate(180deg);
    background: #ff4f11;
  }
  100% {
    -ms-transform: rotate(360deg);
  }
}
@-ms-keyframes preloader_1_after {
  0% {
    border-top: 10px solid rgba(255, 139, 9, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
  50% {
    border-top: 10px solid rgba(253, 87, 17, 1);
    border-bottom: 10px solid rgba(253, 87, 17, 1);
  }
  100% {
    border-top: 10px solid rgba(255, 139, 9, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
}

@keyframes preloader_1 {
  0% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(180deg);
    background: #ff4f11;
  }
  100% {
    transform: rotate(360deg);
  }
}
@keyframes preloader_1_after {
  0% {
    border-top: 10px solid rgba(255, 139, 9, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
  50% {
    border-top: 10px solid rgba(253, 87, 17, 1);
    border-bottom: 10px solid rgba(253, 87, 17, 1);
  }
  100% {
    border-top: 10px solid rgba(255, 139, 9, 1);
    border-bottom: 10px solid rgba(255, 139, 9, 1);
  }
}
</style>

(3)app.ts

import cfg from '@/cfg'
import Base64 from '@/utils/Base64'

export const App = {
  shareData: {},
  mpPostMsg(key: string, val?: string, redirect: boolean = true) {
    const msg = val ? key + ',' + val : key
    if (redirect) {
      uni.redirectTo({ url: '/pages/msg/post?msg=' + Base64.encode64(msg) })
    } else {
      uni.navigateTo({ url: '/pages/msg/post?msg=' + Base64.encode64(msg) })
    }
  },
  mpRecievers: {
    userStorageCert(cert: string) {
      console.log('userCert', cert)
      if (cert) {
        uni.setStorageSync(cfg.mpApp + 'userStorageCert', cert)
      }
    },
    shareAppMessage(v: string) {
      let share
      try {
        share = JSON.parse(v)
        if (share.path) {
          // 使用正则表达式匹配 _i= 后面的字符串
          const match1 = share.path.match(/_i=([^&]+)/)
          // 如果匹配成功,获取匹配到的字符串
          if (match1) {
            const extractedString = match1[1]
            share.path = '/pages/index/index?i=' + extractedString
            console.log(' share.path', share.path)
          }
        }
      } catch (error) {}

      try {
        if (share.imageUrl) {
          share.imageUrl = share.imageUrl.replace(/(w_\d+)|(h_\d+)/g, (match: string) => {
            if (match.startsWith('w_')) {
              return 'w_300'
            } else if (match.startsWith('h_')) {
              return 'h_300'
            }
          })
        }
      } catch (error) {}

      if (share) {
        App.shareData = share
      }
    },
    pay(v: string) {
      const pay = JSON.parse(v)
      pay.success = function () {
        // 需要通知
        App.mpPostMsg('pay,1', undefined, false)
      }
      // pay.complete = function () {
      //   // 需要通知
      //   App.mpPostMsg('pay,1', undefined, false)
      // }
      pay.fail = function (e: any) {
        console.log('pay fail ' + JSON.stringify(e))
        uni.showToast({
          title: '支付失败',
          icon: 'none',
          duration: 2000,
        })
      }

      // 支付参数
      console.log(JSON.stringify(pay))
      const info = uni.getSystemInfoSync()
      // 如果是pc小程序bridge支付,则延迟掉起,防止不显示支付弹窗
      if (info?.deviceType == 'pc' || info?.deviceType == 'PC') {
        uni.showLoading()
        setTimeout(() => {
          uni.hideLoading()
          wx.requestPayment(pay)
        }, 1000)
      } else {
        wx.requestPayment(pay)
      }
    },
    bindWx() {
      wx.login({
        success: function (res: any) {
          let data = ''
          if (res) {
            let appid = ''
            if (cfg.mpApp) {
              appid = cfg.mpApp
            }
            data = JSON.stringify([appid, res.code])
          }
          App.mpPostMsg('bindWx', data, false)
        },
        fail: function (err: any) {
          console.log('bindWx fail', err)
          App.mpPostMsg('bindWx', '', false)
        },
      })
    },
    openLocation(adress: string) {
      const data = JSON.parse(adress)
      wx.openLocation({
        latitude: Number(data.latitude),
        longitude: Number(data.longitude),
        name: data.name,
        scale: 18,
        complete: e => {
          console.log('openLocation complete', e)
        },
      })
      console.log('openLocation data', data)
    },
    downloadAndSave(res: string) {
      const data = JSON.parse(res)
      const $delay = data['$delay']
      if ($delay > 0) {
        setTimeout(() => {
          wx.downloadFile({
            url: data.url,
            success: function (res) {
              wx.openDocument({
                filePath: res.tempFilePath,
                fileType: 'pdf',
                showMenu: true,
              })
            },
          })
        }, $delay)
      } else {
        wx.downloadFile({
          url: data.url,
          success: function (res) {
            wx.openDocument({
              filePath: res.tempFilePath,
              fileType: 'pdf',
              showMenu: true,
            })
          },
        })
      }
    },
    callFun(res: string) {
      const data = JSON.parse(res)
      // @ts-ignore
      const fun = wx[data['$fun']]
      if (fun) {
        delete data['$fun']
        const $delay = data['$delay']
        if ($delay > 0) {
          delete data['$delay']
          setTimeout(() => {
            fun.call(wx, data)
          }, $delay)
        } else {
          fun.call(wx, data)
        }
      }
    },
  },
  mpRecieverMsg(key: string, val?: string) {
    // @ts-ignore
    const fun = App.mpRecievers[key]
    if (fun) {
      fun(val)
      return
    }
  },
}

(3)Base64.ts

// private property
let _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

// private method for UTF-8 encoding
let _utf8_encode = function (str: string) {
  str = str.replace(/\r\n/g, "\n");
  let utftext = "";
  for (let n = 0; n < str.length; n++) {
    let c = str.charCodeAt(n);
    if (c < 128) {
      utftext += String.fromCharCode(c);
    } else if ((c > 127) && (c < 2048)) {
      utftext += String.fromCharCode((c >> 6) | 192);
      utftext += String.fromCharCode((c & 63) | 128);
    } else {
      utftext += String.fromCharCode((c >> 12) | 224);
      utftext += String.fromCharCode(((c >> 6) & 63) | 128);
      utftext += String.fromCharCode((c & 63) | 128);
    }
  }
  return utftext;
}

// private method for UTF-8 decoding
let _utf8_decode = function (utftext: string) {
  let string = "";
  let i = 0;
  let c, c1, c2, c3
  c = c1 = c2 = 0;
  while (i < utftext.length) {
    c = utftext.charCodeAt(i);
    if (c < 128) {
      string += String.fromCharCode(c);
      i++;
    } else if ((c > 191) && (c < 224)) {
      c2 = utftext.charCodeAt(i + 1);
      string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
      i += 2;
    } else {
      c2 = utftext.charCodeAt(i + 1);
      c3 = utftext.charCodeAt(i + 2);
      string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
      i += 3;
    }
  }
  return string;
}

const Base64 = {
  // public method for encoding
  encode(input: string) {
    let output = "";
    let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    let i = 0;
    input = _utf8_encode(input);
    while (i < input.length) {
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);
      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;
      if (isNaN(chr2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
        enc4 = 64;
      }
      output = output +
        _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
        _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
    }
    return output;
  },

  // public method for decoding
  decode(input: string) {
    let output = "";
    let chr1, chr2, chr3;
    let enc1, enc2, enc3, enc4;
    let i = 0;
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
    while (i < input.length) {
      enc1 = _keyStr.indexOf(input.charAt(i++));
      enc2 = _keyStr.indexOf(input.charAt(i++));
      enc3 = _keyStr.indexOf(input.charAt(i++));
      enc4 = _keyStr.indexOf(input.charAt(i++));
      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;
      output = output + String.fromCharCode(chr1);
      if (enc3 != 64) {
        output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
        output = output + String.fromCharCode(chr3);
      }
    }
    output = _utf8_decode(output);
    return output;
  },

  // 编码
  encode64(str: string, uri: boolean = true) {
    str = Base64.encode(str);
    if (uri) {
      str = str.replace(/[+|=|/]/g, function (word) {
        switch (word) {
          case "+":
            return "-";
          case "=":
            return "_";
          case "/":
            return ".";
        }
        return word;
      });
    }

    return str;
  },

  // 解码
  decode64(str: string, uri: boolean = true) {
    if (uri) {
      str = str.replace(/[-|_|.]/g, function (word) {
        switch (word) {
          case "-":
            return "+";
          case "_":
            return "=";
          case ".":
            return "/";
        }
        return word;
      });
    }
    str = Base64.decode(str);
    return str;
  },
}

export default Base64

index.vue

<template>
  <web-view :src="src" @message="receiveMessage"> </web-view>
</template>

<script lang="ts">
import { cfg } from '@/cfg'
import { App } from '@/store/app'
import Base64 from '@/utils/Base64'
export default {
  data() {
    return {
      src: '',
      srcP: '',
      shareData: {
        imageUrl:
          'https://yjy.yiyiny.com//static/images/20240122/' +
          cfg.mpApp +
          '.png?x-oss-process=image/auto-orient,1/resize,m_fixed,w_100,h_100',
      },
      shareI: '',
    }
  },
  onLoad(e: any) {
    // e.scene  生成小程序码必须是这个key
    this.setSrc(cfg.entryUrl, e.i || e.scene)

    wx.showShareMenu({
      withShareTicket: true,
      menus: ['shareAppMessage'],
      success(res) {
        console.log('mixin share success', res ? JSON.stringify(res) : res)
      },
      fail(err) {
        console.log('mixin share fail', err ? JSON.stringify(err) : err)
      },
    })
  },
  onShow() {
    cfg.mpSrcP = this.srcP
    App.shareData = {}
  },
  onShareAppMessage(res: any) {
    console.log(res)
    if (res.from === 'button') {
      return this.shareData
    }
    if (res.from === 'menu') {
      return this.shareData || {}
    }
  },

  onShareTimeline() {
    let data = {
      title: '一乙艺术山庄',
      query: 'id=1',
      // imageUrl: '',
    }
    return data
    // return axCc.vueSelf.shareData || {};
  },
 

  onHide() {},
  methods: {
    setSrc(src: string, shareI?: string) {
      let cert = uni.getStorageSync(cfg.mpApp + 'userStorageCert')
      console.log('setSrc src', src)
      console.log('setSrc shareI', shareI)
      let i = src.indexOf('#')
      let j = src.indexOf('?')
      let srcP = i > 0 && i < j ? src.substring(0, i) : j > 0 ? src.substring(0, j) : src
      if (srcP && srcP[srcP.length - 1] != '/') {
        srcP = srcP + '/'
      }

      if (i > 0) {
        cfg.mpUrl = src.substring(0, i)
      } else {
        cfg.mpUrl = cfg.entryUrl
      }
      console.log('[  cfg.mpUrl ] >', cfg.mpUrl)

      this.srcP = srcP
      cfg.mpSrcP = this.srcP
      src = j > 0 ? src + '&_mpid_=' + cfg.mpid : src + '?_mpid_=' + cfg.mpid
      if (shareI) {
        src = src + '&_i=' + shareI
        // 分享地址拼接
        const startIndex = src.indexOf('#')
        const endIndex = src.indexOf('?')
        if (startIndex !== -1 && endIndex !== -1) {
          src = src.substring(0, startIndex) + src.substring(endIndex)
          console.log(src)
        }
        this.shareI = shareI
      }
      src = src + '&ver=' + cfg.version

      if (cert) {
        src = src + '&_cert_=' + encodeURIComponent(cert)
      }
      this.src = src
      console.log('setSrc this.src', this.src)
    },
    // 监听h5 消息
    // { merber 用户信息 imageUrl 默认分享图 path 分享地址 title:分享标题   desc }
    receiveMessage(e: any) {
      console.log('receiveMessage333', e)
      let arr = e?.detail?.data
      let data = arr && arr.length > 0 ? arr[arr.length - 1] : null
      let url
      if (data && data?.merber?.id) {
        url = data?.path
          ? data.path
          : cfg.mpName == 'mp_wdysj'
          ? 'pages/artisthome/artisthome'
          : '/pagesShop/shop/wHome'
        let parms = this.gen(url, false, { mmId: data?.merber.id }, 13050, data?.merber?.id)
        console.log('data222', data)
        this.shareData = {
          path: '/pages/index/index?i=' + parms + '&fk=1',
          imageUrl: data?.imageUrl
            ? data.imageUrl
            : 'https://yjy.yiyiny.com//static/images/20240122/' +
              cfg.mpApp +
              '.png?x-oss-process=image/auto-orient,1/resize,m_fixed,w_100,h_100',
          title: data?.title ? data.title : cfg.mpName,
          desc: data?.desc ? data.desc : '',
          query: parms,
        }
      } else {
        wx.hideShareMenu()
      }
    },
    // 地址加密
    gen(uri: string, bind: boolean, reg: any, eid?: number, memberId?: number): string {
      // 标准编码
      let ps = [memberId, '', false, uri || '', reg || '', eid]
      for (let i = ps.length - 1; i >= 0; i--) {
        if (ps[i]) {
          let del = ps.length - i - 1
          if (del > 0) {
            ps.splice(i + 1, del)
          }

          break
        }
      }
      let _ps: any = ps
      _ps[0] = _ps[0] || ''
      if (bind) {
        _ps[2] = uri
        _ps[3] = ''
      } else {
        _ps[2] = ''
      }

      return Base64.encode64(JSON.stringify(ps))
    },
  },
}
</script>

<style></style>

cfg.ts

export const cfg = {
  mpApp: 'mp_wdysj', //一乙艺术商城
  mpName: '一乙艺术商城',
  mpUrl: 'https://p.yiyiny.com/xxx/',
  mpid: '',
  mpSrcP: '',
  version: '1.0.8',
  entryUrl: 'https://p.yiyiny.com/xxx/#/pagesShop/shop/wHome',
}

const info = uni.getSystemInfoSync()
if (!cfg.mpid) {
  const host = info.host
  // @ts-ignore
  if (host && host.appid) {
    // @ts-ignore
    cfg.mpid = host.appid
  }

  if (!cfg.mpid) {
    cfg.mpid = cfg.mpApp
  }
}
export default cfg

2、h5端
(1)项目初始化时候h5载入微信sdk
Ainit.ts

 // #ifdef H5
  let _mpid_;

  try {
    let search = <any>(
      (launcher.h5Search || ab_.route(false, false, false).search)
    );

    _mpid_ = search['_mpid_'];
    let _cert_ = search['_cert_'];

    // 获取小程序传递的证书
    if (_cert_) {
      _cert_ = decodeURIComponent(_cert_)
      User.status.storage.cert = _cert_
    }
    let app = axConfig.webType || 'web'
    if (Weixin.isWeiXin()) {
      axCc.Loader().wait("weixinLogin");
      ab_.reqJs(
        axCc.https
          ? "https://res.wx.qq.com/open/js/jweixin-1.6.0.js"
          : "http://res.wx.qq.com/open/js/jweixin-1.6.0.js",
        null,
        function () {
          function wxH5() {
            if (search["code"]) {
              let parms: Array<string> = [axConfig.webType, search["code"]];
              User.loginProvBack(
                "wx",
                function (logined) {
                  console.log("微信登陆成功", logined);
                  try {
                    if (logined) {
                      axCc.saveStorage("wxLogined", {
                        token: App.client.plt.headers["atoken"],
                        authPar: User.status.authPar,
                        authParas: User.status.authParas,
                      });
                    } else {
                      axCc.saveStorage("wxLogined", {});
                    }
                  } finally {
                    axCc.Loader().done("weixinLogin");
                    // 微信jsConfig
                    Weixin.wxConfig();
                  }
                },
                parms,
                true,
                true,
                true
              );
            } else {
              try {
                // 关闭自动登录
                // User.autoLogin = false;
                let wxLogined = axCc.getStorage("wxLogined");
                if (wxLogined && wxLogined.token && wxLogined.authParas && wxLogined.authParas[0] === app) {
                  User.loginToken(wxLogined.token, (logined) => {
                    if (logined) {
                      User.status.authPar = wxLogined.authPar;
                      User.status.authParas = wxLogined.authParas;
                      axCc.Loader().done("weixinLogin");
                    } else {
                      //微信浏览器 吊起微信支付必须要获取openid
                      console.log("掉起微信支付必须要获取openid");
                      Weixin.snsapi_base();
                    }
                  });
                } else {
                  //微信浏览器 吊起微信支付必须要获取openid
                  console.log("掉起微信支付必须要获取openid");
                  Weixin.snsapi_base();
                }
              } finally {
                // 微信jsConfig
                Weixin.wxConfig();
              }
            }
          }
          // @ts-ignore
          if (window.wx) {
            User.autoLogin = false;
            try {
              // @ts-ignore
              if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
                handleFontSize();
              } else {
                if (document.addEventListener) {
                  document.addEventListener("WeixinJSBridgeReady", handleFontSize, false);
                  // @ts-ignore
                } else if (document.attachEvent) {
                  // @ts-ignore
                  document.attachEvent("WeixinJSBridgeReady", handleFontSize);
                  // @ts-ignore
                  document.attachEvent("onWeixinJSBridgeReady", handleFontSize);
                }
              }
              function handleFontSize() {
                // 设置网页字体为默认大小
                // @ts-ignore
                WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 });
                // 重写设置网页字体大小的事件
                // @ts-ignore
                WeixinJSBridge.on('menu:setfont', function () {
                  // @ts-ignore
                  WeixinJSBridge.invoke('setFontSizeCallback', { 'fontSize': 0 });
                });
              }

              // @ts-ignore
              if (wx.miniProgram) {
                // @ts-ignore
                wx.miniProgram.getEnv((res) => {
                  if (res.miniprogram) {
                    User.status.info.cert = true
                    User.autoLogin = true;
                    // && search['_mpid_'] == "mp_wdysj_shop"
                    if (_mpid_) {
                      if ((_mpid_ == "mp_wdysj_shop" || _mpid_ == "mp_wdysj_yiyi_shop")) {
                        axConfig.pltName = "商城"
                        axConfig.home = "/pagesShop/shop/wHome"
                        App.shopScoreName = '商城'
                        App.client.storeHttp.head('platform', 'mp')
                        axConfig.appProv = _mpid_
                        axConfig.appEid = 13061
                      }
                      axConfig.pltApp = _mpid_
                      User.status.info.app = _mpid_
                    }
                    // 小程序
                    Weixin.initWxMpH5(_mpid_, search['ver'])
                    axCc.Loader().done("weixinLogin");
                  } else {
                    wxH5()
                  }
                })

                return
              }

            } catch (e) {
              console.error(e)
            }

            wxH5()

          } else {
            axCc.Loader().done("weixinLogin");
          }
        },
        undefined
      );

    } else {
    }

  } catch (e) {
    console.error(e);
  }
  // #endif

2、Weixin.ts

import ab_ from 'axj-ab_'; //npm install axj-ab_
import Base64 from '../util/Base64';

interface ShareInfo {
  title: string,
  desc?: string,
  link: string,
  imageUrl?: string,
  logo?: string,//兼容老项目
  imgUrl?: string,//兼容老项目
  scene?: string
}

let weixin = false;
let readyReg = false;
let wxConfigState = -1;
let wxMpH5 = false;
let wxMpApp = '';
// let wxMpToken = '';

const Weixin = {
  initStepsArray: [1000, 2000, 4000, 8000, 16000, 32000, 64000],
  initI: 0,
  erred: false,
  readyed: false,
  shareInfo: <undefined | ShareInfo>undefined,
  // 如果wx授权失败,则定时再次获取授权
  wxConfigRe(e?: any) {
    console.log('wxConfig error ' + e)
    // alert('wxConfig error ' + JSON.stringify(e))
    Weixin.erred = true
    // @ts-ignore
    setTimeout(Weixin.wxConfig, Weixin.initI < Weixin.initStepsArray.length ? Weixin.initStepsArray[Weixin.initI++] : Weixin.initStepsArray[Weixin.initStepsArray.length - 1])
  },
  // 通过config接口注入权限验证配置
  wxConfig() {
    let authUrl = location.href
    wxConfigState++
    switch (wxConfigState) {
      case 1:
        authUrl = Ainit.h5Href
        break
      // case 2:
      //   authUrl = location.protocol + '//' + location.host + location.pathname + location.search + location.hash
      //   break
      default:
        wxConfigState = 0
        break
    }
	//调接口授权的方法可以自己写
    App.client.plt.reqA(-1, 'C/wxConfig', [axConfig.webType, authUrl], function (err, rep) {
      console.log('pltClient C/wxConfig err,data:', err, rep)
      if (rep && rep.appId) {
        // rep.debug = true
        rep.jsApiList = [
          'updateAppMessageShareData',
          'updateTimelineShareData',
          'onMenuShareAppMessage',
          'onMenuShareTimeline',
          "getLocation",
          "scanQRCode",
          // 'wx-open-launch-weapp',
          // 'chooseWXPay'
        ]
        // rep.debug = true
        console.log('wxready  wx.config')
        Weixin.erred = false
        // @ts-ignore
        wx.config(rep)
        // @ts-ignore
        wx.error(Weixin.wxConfigRe)
        let readyFun = function () {
          if (Weixin.erred) {
            return
          }
          Weixin.readyed = true
        }

        if (readyReg) {
          setTimeout(readyFun, 1000);

        } else {
          readyReg = true
          // @ts-ignore
          wx.ready(readyFun)
        }

        return;
      }

      Weixin.wxConfigRe()
    })

  },
  wxShare(v: ShareInfo) {
    console.log('h5  wxShare alert', v);
    if (weixin) {
      // @ts-ignore
      v = typeof (v) === 'object' ? v : JSON.parse(v)
      if (!Weixin.readyed) {
        Weixin.shareInfo = v
        return
      }

      delete Weixin.shareInfo
      var share = {
        title: v.title || 'xx', // 分享标题
        desc: v.desc || '', // 分享描述
        link: v.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
        imgUrl: v.imageUrl || v.logo || v.imgUrl, // 分享图标
        success: (e) => {
          console.log('wxShare success  ', e)
          // 显示微信分享
          // @ts-ignore
          // if (window.WeixinJSBridge) {
          //   // @ts-ignore
          //   window.WeixinJSBridge.call('showOptionMenu')
          // }
          if (window.wx && window.wx.showMenuItems) {
            // @ts-ignore
            window.wx.showMenuItems({
              menuList: [
                'menuItem:share:appMessage',
                'menuItem:share:timeline',
                'menuItem:favorite',
                'menuItem:share:qq',
                'menuItem:share:QZone',
              ]
            })
          }
        },
        fail: function (e) {
          console.log('wxShare fail', e)
        }
      }
      console.log('updateWx', share)
      // @ts-ignore
      wx.updateAppMessageShareData(share)
      // @ts-ignore
      wx.updateTimelineShareData(share)

      // WeixinJSBridge.call("showOptionMenu");
    }
  },
  // 静默授权
  snsapi_base() {
    var backUri = Ainit.h5Href || location.href
    console.log(backUri)
    var redirectUri = axConfig.pltH5 + 'static/wx.html?u=' + Base64.encode64(backUri, true)
    redirectUri =
      'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + (axConfig.webType == 'wdysjh5' ? 'wxab385cf8a7ec96d8' : 'wx59a0fb7a9bd076e5') + '&redirect_uri=' +
      encodeURIComponent(redirectUri) +
      '&response_type=code&scope=snsapi_userinfo&state=1'
    console.log(redirectUri)
    location.replace(redirectUri)
    // setTimeout(() => {
    //   location.replace(redirectUri)
    // }, 3000);
  },
  isWeiXin() {
    return weixin;
  },
  isWxMpH5() {
    return wxMpH5
  },
  getWxMpApp() {
    return wxMpApp
  },
  initWxMpH5(mpid: string, ver?: string) {
    console.log('initWxMpH5 ' + mpid)
    weixin = false
    wxMpH5 = true

    if (mpid) {
      wxMpApp = mpid

    } else {
      console.log('initWxMpH5 no mpid' + location.href)
      console.log(launcher.h5Href)
      console.log(launcher.h5Search)
    }

    Artist.getReviewVersion(`mp-${ver}`)
    // 消息通道
    setInterval(function () {
      let msg = localStorage.getItem('_mpmsg_')
      if (msg) {
        try {
          msg = JSON.parse(msg)
          if (!mpid || msg[0] === mpid) {
            // 是发给我的消息
            msg = msg[1]
            msg = Base64.decode64(msg)
            let i = msg.indexOf(',')
            if (i > 0) {
              Weixin.onWxMpMsg(msg.substring(0, i), msg.substring(i + 1))

            } else {
              Weixin.onWxMpMsg(msg, '')
            }

            localStorage.removeItem('_mpmsg_')
          }

        } catch (e) {
          console.error(e)
          localStorage.removeItem('_mpmsg_')
        }
      }

    }, 100)
  },
  onWxMpMsg(key: string, val?: string) {
    console.log('onWxMpMsg,' + key + ',' + val)
    if (key == 'pay') {
      console.log('updatePay,更新支付状态' + key)
      uni.$emit('updatePay', { msg: '更新支付状态' })
    }
    // @ts-ignore
    wx.miniProgram.navigateBack()
    let fun = Weixin.onWxMpCenter[key]
    if (fun) {
      fun(val)
    }
  },
  forWxMpToken(back: (err?: any) => void) {
    if (User.status.authPar) {
      back && back()
      return
    }

    // @ts-ignore
    let nextT = ab_.nextT()
    // @ts-ignore
    Weixin['forWxMpTokenBacks'] = [nextT, back]
    // @ts-ignore
    wx.miniProgram.navigateTo({ url: '/pages/msg/post?loginA=' + nextT })
  },
  onWxMpCenter: {
    loginA(val: string) {
      let paras = JSON.parse(val)
      let nextT = 0
      let back: any
      let loginA = false
      if (typeof (paras[0]) === 'number') {
        loginA = true
        nextT = paras[0]
        paras = ab_.args(paras, 1, paras.length)
        let backs = Weixin['forWxMpTokenBacks']
        if (backs) {
          delete Weixin['forWxMpTokenBacks']
          if (backs[0] === nextT) {
            back = backs[1]
          }
        }
      }

      let noRep = nextT && User.state.logined
      User.loginProvBack('wx', (succ, rep) => {
        console.log('loginA ', succ, rep)
        if (succ) {
          Page.loginSuccBack()
          if (loginA) {
            // @ts-ignore
            wx.miniProgram.navigateBack()
          }

        } else if (!User.state.authing && !nextT) {
          console.log('toLogin--------')
          Weixin.postWxMpMsg('toLogin')
        }

        // 回调
        back && back(User.status.authToken ? undefined : rep)

      }, paras, false, 2, false, noRep)
    },
    loginAFail(val: string) {
      let paras = JSON.parse(val)
      let nextT = paras[0]
      let backs = Weixin['forWxMpTokenBacks']
      if (backs) {
        delete Weixin['forWxMpTokenBacks']
        if (backs[0] === nextT) {
          backs[1] && backs[1](paras[1])
        }
      }
    },
    loginInfo(val: string) {
      //let loginInfo = JSON.parse(val)
      let paras = JSON.parse(val)
      if (User.status.authToken) {
        paras[1] = User.status.authToken
      }

      User.loginProvBack('wx', (succ) => {
        if (succ) {
          Page.loginSuccBack()

        } else if (!User.state.authing) {
          User.status.authToken = ''
        }

      }, paras, true, 2)
    },
    bindWx(val: string) {
      uni.$emit('updateBindWx', { msg: val })
    }
  },
  postWxMpMsg(key: string, val?: string) {
    console.log('postWxMpMsg,' + key + ',' + val)
    if (key === 'toLogin') {
      // ios 微信新用户第一次登录 会导致不执行此逻辑
      setTimeout(() => {
        // @ts-ignore
        wx.miniProgram.navigateTo({ url: '/pages/index/login?t=' + User.status.authToken })
      }, 400);
      return
    }

    // if (key === 'toLoginA') {
    //   // @ts-ignore
    //   wx.miniProgram.navigateTo({ url: '/pages/index/login' })
    //   return
    // }

    if (key === 'share') {
      // @ts-ignore
      wx.miniProgram.navigateTo({ url: '/pages/msg/share?s=' + val })
      return
    }

    let msg = val ? (key + ',' + val) : key
    setTimeout(() => {
      // @ts-ignore
      wx.miniProgram.navigateTo({ url: '/pages/msg/reciver?msg=' + Base64.encode64(msg) })
    }, 400);
    console.log('postWxMpMsg.navigateTo');
  },
}

// #ifdef H5
try {
  // 微信环境判断
  let userAgent: any = window.navigator.userAgent.toLowerCase();
  weixin =
    userAgent.match(/MicroMessenger/i) == "micromessenger" &&
    !(window.parent && window.parent !== window);

  //兼容 微信支付路径
  if (weixin) {
    let h5Uri = location.href;
    if (h5Uri.indexOf('/#/') < 0) {
      // axCc.Loader().wait("weixinHref");
      try {
        h5Uri = location.origin + location.pathname + "#/" + location.search
        location.href = h5Uri
        setTimeout(() => {
          location.reload()
        }, 1000);
        axCc.Loader().wait("weixinHref");
      } catch (error) {

      }
    }
  }

} catch (e) {
  console.error(e);
}
// #endif

export default Weixin;

3、公共h5跳转页

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1.0,maximum-scale=1,viewport-fit=cover"
    />
    <title>···</title>

    <style>
      #loadingBg {
        width: 100vw;
        height: 100vh;
        position: fixed;
        z-index: 10000;
        top: 0;
      }
      body {
        margin: 0px;
        font-size: 12px;
      }
      #preloader {
        position: absolute;
        width: 30px;
        height: 30px;
        background: rgba(253, 87, 17, 1);
        border-radius: 50px;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        margin: auto;
        -webkit-animation: preloader_1 1.5s infinite linear;
        -moz-animation: preloader_1 1.5s infinite linear;
        -ms-animation: preloader_1 1.5s infinite linear;
        animation: preloader_1 1.5s infinite linear;
      }
      #preloader:after {
        position: absolute;
        width: 50px;
        height: 50px;
        border-top: 10px solid rgba(255, 139, 9, 1);
        border-bottom: 10px solid rgba(255, 139, 9, 1);
        border-left: 10px solid transparent;
        border-right: 10px solid transparent;
        border-radius: 50px;
        content: "";
        top: -20px;
        left: -20px;
        -webkit-animation: preloader_1_after 1.5s infinite linear;
        -moz-animation: preloader_1_after 1.5s infinite linear;
        -ms-animation: preloader_1_after 1.5s infinite linear;
        animation: preloader_1_after 1.5s infinite linear;
      }

      @-webkit-keyframes preloader_1 {
        0% {
          -webkit-transform: rotate(0deg);
        }
        50% {
          -webkit-transform: rotate(180deg);
          background: #ff4f11;
        }
        100% {
          -webkit-transform: rotate(360deg);
        }
      }
      @-webkit-keyframes preloader_1_after {
        0% {
          border-top: 10px solid rgba(253, 87, 17, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
        50% {
          border-top: 10px solid rgba(253, 87, 17, 1);
          border-bottom: 10px solid rgba(253, 87, 17, 1);
        }
        100% {
          border-top: 10px solid rgba(255, 139, 9, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
      }

      @-moz-keyframes preloader_1 {
        0% {
          -moz-transform: rotate(0deg);
        }
        50% {
          -moz-transform: rotate(180deg);
          background: #ff4f11;
        }
        100% {
          -moz-transform: rotate(360deg);
        }
      }
      @-moz-keyframes preloader_1_after {
        0% {
          border-top: 10px solid rgba(255, 139, 9, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
        50% {
          border-top: 10px solid rgba(253, 87, 17, 1);
          border-bottom: 10px solid rgba(253, 87, 17, 1);
        }
        100% {
          border-top: 10px solid rgba(255, 139, 9, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
      }

      @-ms-keyframes preloader_1 {
        0% {
          -ms-transform: rotate(0deg);
        }
        50% {
          -ms-transform: rotate(180deg);
          background: #ff4f11;
        }
        100% {
          -ms-transform: rotate(360deg);
        }
      }
      @-ms-keyframes preloader_1_after {
        0% {
          border-top: 10px solid rgba(255, 139, 9, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
        50% {
          border-top: 10px solid rgba(253, 87, 17, 1);
          border-bottom: 10px solid rgba(253, 87, 17, 1);
        }
        100% {
          border-top: 10px solid rgba(255, 139, 9, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
      }

      @keyframes preloader_1 {
        0% {
          transform: rotate(0deg);
        }
        50% {
          transform: rotate(180deg);
          background: #ff4f11;
        }
        100% {
          transform: rotate(360deg);
        }
      }
      @keyframes preloader_1_after {
        0% {
          border-top: 10px solid rgba(255, 139, 9, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
        50% {
          border-top: 10px solid rgba(253, 87, 17, 1);
          border-bottom: 10px solid rgba(253, 87, 17, 1);
        }
        100% {
          border-top: 10px solid rgba(255, 139, 9, 1);
          border-bottom: 10px solid rgba(255, 139, 9, 1);
        }
      }
    </style>
  </head>
  <script>
    function getPara(name) {
      var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
      var r = window.location.search.substr(1).match(reg);
      if (r != null) {
        return unescape(r[2]);
      }
      return null;
    }

    let uid = getPara("uid");
    let msg = getPara("msg");
    if (msg) {
      localStorage.setItem("_mpmsg_", JSON.stringify([uid, msg]));
    }
  </script>
  <body>
    <div id="loadingBg">
      <div id="preloader"></div>
      <!-- <div>加载中</div> -->
    </div>
  </body>
</html>


http://www.kler.cn/a/428180.html

相关文章:

  • 17、智能驾驶硬件架构安全设计一般原则
  • OpenCV:二值化与自适应阈值
  • 全面解析文件上传下载删除漏洞:风险与应对
  • 29. C语言 可变参数详解
  • FireFox | Google Chrome | Microsoft Edge 禁用更新 final版
  • 高级编码参数
  • 【AWS re:Invent 2024】一文了解EKS新功能:Amazon EKS Auto Mode
  • Python实现BBS论坛自动签到【steamtools论坛】
  • Python 入门教程(2)搭建环境 | 2.4、VSCode配置Node.js运行环境
  • 如何利用DBeaver配置连接MongoDB和人大金仓数据库
  • django 实战(python 3.x/django 3/sqlite)
  • AI by Hand:手搓 AI 模型
  • git遇见冲突怎么解决?
  • Dell电脑安装Centos7问题处理
  • Python Virtualenv 虚拟环境迁移, 换新电脑后 Python 环境快速迁移 Virtualenv 环境配置管理,实测篇
  • 黑马程序员Java项目实战《苍穹外卖》Day12
  • 十六、大数据之Shell 编程
  • 第四十一天 ASP应用 HTTP.sys 漏洞 iis6文件解析漏洞和短文件漏洞 access数据库泄露漏洞
  • L-BFGS 方法实现
  • Hive 中 Order By、Sort By、Cluster By 和 Distribute By 的详细解析
  • 流量转发利器之Burpsuite概述(1)
  • 监控易管理平台7.0助力打造智慧运维体系
  • DataEase 是开源的 BI 工具
  • MISRA C2012学习笔记(10)-Rules 8.15
  • 如何将 JavaWeb 项目部署到云服务器
  • PyCharm 中使用 Flask 框架和数据库