blog icon indicating copy to clipboard operation
blog copied to clipboard

微信分享 总结(SPA/history模式)

Open yongheng2016 opened this issue 6 years ago • 41 comments

微信分享过程中遇到的问题总结(SPA/history模式)

微信接口demo


开发文档

微信调整

image

微信JS-SDK(此总结仅使用与SPA/History模式下)

  1. 去微信公众平台设置’js接口安全域名‘
  2. 引入js接口文件
    • 引入链接:http://res.wx.qq.com/open/js/jweixin-1.2.0.js
    • 加载模块:npm install weixin-js-sdk
  3. 通过config接口注入权限验证配置
  4. 通过ready接口处理成功验证(ready函数中执行调用的微信API)
  5. 通过error接口处理失败验证
  • 错误总结:

调用微信内置的API(分享| 支付等)大部分都需要进行权限配置,配置出错基本可以分为两大类: 1. wx.config()配置中,在开启debug:true的情况下,如果提示配置失败基本都是页面url的锅,盯着url来解决问题就可以了,无论是前端还是服务端 2. 如果配置信息没有错误,只是要调用的API各种间歇性无法调用,应该是配置函数执行时机出现了问题,设置个延迟函数基本就解决了,但比较hack,应该有更好的办法,暂时还没想到

  • 错误分析

如果你遇到了config权限配置经常出错,需要先了解下面内容来帮助你解决问题

下图模拟了一个用户进入你的应用(网页)后的一些行为,包括:

  1. 点击链接或按钮跳转到其他页面
  2. 刷新页面 其中:
    • currentPage表示你正在看的页面
    • langdingPage表示落地页,也就是浏览器认为的页面

Andriod系统对url的识别机制

image

Ios系统对url的识别机制

image

如上,Andriod系统更符合我们对url的认知,而Ios系统中的每个页面的url都是刚进入项目的第一页的url,除非是刷新页面;即:在SPA模式下:

  • Ios中,页面A为整个项目的真实url
  • Andriod中,每次路由跳转都会产生新的url

微信js-sdk配置加密所校验的url是落地页url(即:landingPage),所以以下情况若调用微信API需要在当前页面配置:

  • Ios进入项目的第一页
  • Ios页面刷新后
  • Andriod路由跳转或页面刷新后

① 在SPA/history模式下,不同系统对url的识别机制存在差异(如下图):

  • Ios(所有页面的url等于落地页url 进入项目的落地页为配置页,只需要在落地页配置一次即可
  • Android(每次页面跳转都会产生新的url 需要调用微信api的页面需单独配置

② Sha1加密注意事项

  • 向后端发送的url进行sha1加密,url必须是动态获取(放在函数中动态执行)
  • 本项目下向后端传入的url需进行encodeURIComponent转码,防止参数中的’&’出现混淆

③ 自定义分享配置注意事项:

  • 分享链接link: 必须和公众号中设置的js安全域名一致,并且不需要使用encodeURIComponent转码,否则安卓端异常
  • 若配置方法是在导航守卫中执行,注意weixin API的加载校验为异步,配置信息要在weixin校验完成后执行

import wx from 'weixin-js-sdk'
import axios from 'base/axios/axios'
import baseHttp from 'common/js/checkout_url'
import {get_userInfo} from '@/utils'
import {saveWXConfig, getWXConfig} from 'common/js/cache'
import {saveSharingPerson, getSharingPerson} from 'common/js/SharingPerson'

//分享链接配置
let userInfo = get_userInfo()
let userPhone = userInfo.userPhone ? userInfo.userPhone : ''
function configShareLink(){
  let shareLink  shareLink = `https://m.test.com/auth?phone=${userPhone}`
  return shareLink
}

//当前ulr encodeURIComponent
function enCodeLocalUrl(){
  return window.encodeURIComponent(window.location.href.split('#')[0])  // url必须动态获取,不能缓存
}

//自定义分享信息配置
let setting = {
  link: configShareLink(),  //不能用encodeURIComponent转码,安卓端配置都正常,但自定义信息不会出现
  imgUrl: 'https://www.test.com/imgs/logo.png',
  title: '自定义分享标题',
  desc: `自定义分享描述`,
  success: function (e) {
    // 用户确认分享后执行的回调函数
  },
  cancel: function (e) {
    // 用户取消分享后执行的回调函数
  },
  complete: function () {
    // window.alert('接口调用完成')
  }
}

//微信配置生命周期函数

function WXConfig(data,jsApiList,wxReady){
  wx.config({
    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: data.appId, // 必填,公众号的唯一标识
    timestamp: data.timeStamp, // 必填,生成签名的时间戳
    nonceStr: data.nonceStr, // 必填,生成签名的随机串
    signature: data.signature, // 必填,签名,见附录1
    jsApiList: jsApiList
  })
  wx.ready(function () {
    wxReady()
  })
  wx.error(function(res){
    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
  })
}

//服务端对本地url加密配置
function localUrLencrypt(localUrl,jsApiList,callbackWXReady){
  console.log('分享配置localUrl', localUrl)
  var wechatConfigData = ''
  if (wechatConfigData){
    WXConfig(wechatConfigData, jsApiList, callbackWXReady)
  }else{
    var url = baseHttp + "WXPay/WXsha1?url=" + localUrl;
    axios.get(url).then(resp => {
      if (resp.data.status == 200) {
        saveWXConfig(resp.data.data)
        wechatConfigData = resp.data.data
        WXConfig(resp.data.data, jsApiList, callbackWXReady)
      } else {
        console.log("获取授权信息错误");
      }
    }).catch(error => {
      console.log("获取授权失败");
    })
  }
}

//分享配置
export function shareMsg(){
  let localUrl = enCodeLocalUrl()
  let jsApiList = ['checkJsApi',
                    'onMenuShareTimeline',
                    'onMenuShareAppMessage',
                    'showAllNonBaseMenuItem']
  let wxConfigReady = function (){
    wx.checkJsApi({
      jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
      success: function(res) {
      }
    })
    wx.onMenuShareTimeline(setting);  //朋友圈
    wx.onMenuShareAppMessage(setting);  //好友
    wx.showAllNonBaseMenuItem();  //显示所有非基础组件
  }
  localUrLencrypt(localUrl,jsApiList, wxConfigReady)
}

//隐藏功能按钮
export function hideMenuTemp(){
  let localUrl = enCodeLocalUrl()
  let jsApiList = ['checkJsApi','hideAllNonBaseMenuItem']
  let wxConfigReady = function (){
    wx.hideAllNonBaseMenuItem()
  }
  localUrLencrypt(localUrl,jsApiList, wxConfigReady)
}

//显示功能按钮
export function showMenuItems(){
  let localUrl = enCodeLocalUrl()
  let jsApiList = ['checkJsApi','showMenuItems',]
  let wxConfigReady = function (){
    wx.showMenuItems({
      menuList: ['menuItem:share:appMessage', 'menuItem:share:timeline', 'menuItem:share:qq'] // 要显示的菜单项,所有menu项见附录3
    });
  }
  localUrLencrypt(localUrl,jsApiList, wxConfigReady)
}



yongheng2016 avatar Jan 12 '18 10:01 yongheng2016

感谢总结的的经验,现在我这里遇到一个很诡异的问题的就是我们一个SPA进入应用的时候立马进行了微信授权后再返回应用。整个授权就是客户端的操作,不牵扯后端。但分享的自定义就是会失败,但config会成功,自定义按钮会有效。如果把授权去掉,就一切正常。请问有什么思路吗

fbsstar avatar May 05 '18 14:05 fbsstar

@fbsstar ios? 在微信授权成功后,会重定向到你的项目地址,但微信在后面加了一些参数(codestate),如下:

m.test.com/home?code=xxxxx&state=xxx

如果你确定在落地页传给了后端完整的url(如上m.test.com/home?code=xxxxx&state=xxx),基本就是后端的锅了,可以让后端检查是否完整接收了你传过去的url(特别是&符号的处理),最好打印出来,眼见为实。

yongheng2016 avatar May 06 '18 10:05 yongheng2016

@yongheng2016 感谢对问题的总结和分享,关于上面那位大兄弟( @fbsstar ) 遇到的问题,我也遇到了,再次做一个详细的说明,首先通过拉取授权地址,重定向到类似

m.test.com/home?code=xxxxx&state=xxx

的地址,把此地址存起来作为落地页的地址,给后端签名,获取到的签名是通过了的未进任何的wx.error或者fail,此时分享,却无法分享正确的自定义内容,title,link也为落地页的内容,但是会触发分享方法中的success方法。如果,去掉微信授权登录只是通过普通的方法来进入页面分享是一切正常的。此问题当真诡异至极。。。

CavinHuang avatar May 19 '18 02:05 CavinHuang

@CavinHuang 是把授权地址放一个单独的html中了么? image 看一下你鉴定的地址是:m.test.com/auth.html还是m.test.com/home

如果是放在Vue实例下,可以联系我详细说明一下你那边的具体写法;

yongheng2016 avatar May 19 '18 04:05 yongheng2016

你好 我这边有一个vue写的spa应用 vue-router是 hash模式 没有使用微信的sdk ios分享总是第一次进去的页面 这个问题请问怎么解决呢

MiracleRo avatar May 24 '18 07:05 MiracleRo

@MiracleRo 单页应用在ios系统下,无论路由怎么跳转,整个项目的url就是落地页url(你的第一次进去的页面),没有使用sdk进行自定义分享设置的话,微信会使用默认配置,即当前url页面下的tile和第一张规定规格的图片 image

  1. 设置自定义分享,设置自定义分享的链接未每次路由跳转后的链接地址
  2. 改变ios下的url(刷新页面或使用window.href=xxxxx)

yongheng2016 avatar May 25 '18 02:05 yongheng2016

@yongheng2016 十分感谢

MiracleRo avatar May 25 '18 02:05 MiracleRo

先点赞在提问! 博主能否把自己的nginx配置分享以下,我现在也是用的history,是在二级域名下配置的,但是并没有用 location ^~ /h5/ { try_files $uri $uri/ /index.html =404; } 报的是500

wqb2017 avatar Jul 12 '18 07:07 wqb2017

@wqb2017 不好意思,nginx的配置我不太了解

yongheng2016 avatar Jul 13 '18 01:07 yongheng2016

@yongheng2016 你好。最近在做一个公众号项目,也是遇到了config问题,好多天还没解决。用的框架是react+dva。 android里没有问题,因为在每个页面都会去config一次,能正常调起wx的api。 ios里是不是只需要进入网页时config一次,config的url就是进入页面时的url?后面也无须config(不考虑页面刷新的情况)?

budiga avatar Aug 25 '18 11:08 budiga

@budiga 对 image

yongheng2016 avatar Aug 29 '18 15:08 yongheng2016

@yongheng2016 我也遇到了和@CavinHuang一样问题 image 问题描述:iOS端,第一次进来触发授权,发给后端签名的url为window.encodeURIComponent( m.test.com/home?code=xxxxx&state=xxx .split('#')[0]),提示签名成功了.但是无法分享正确的自定义内容,title,link确认过了为落地页的内容 如果关掉页面重新从微信菜单进来,此时有token不触发授权.签名的页面是路由的第一个页面,就能分享正确的自定义内容.

wengtinggui avatar Sep 23 '18 02:09 wengtinggui

@wengtinggui 是间断出现自定义分享失败么?如果是的话:参考一下上面的错误总结第二条 image

yongheng2016 avatar Sep 23 '18 16:09 yongheng2016

@yongheng2016不是间歇性,就是授权后的第一次必现,加你qq联系方式了,麻烦通过下

wengtinggui avatar Sep 23 '18 23:09 wengtinggui

@wengtinggui 你好,请问你解决了这个问题吗? 我遇到的也是授权之后必现。。。

helloljq avatar Sep 26 '18 07:09 helloljq

@helloljq 还没解决.你解决了麻烦分享下

wengtinggui avatar Sep 26 '18 09:09 wengtinggui

感谢经验总结!现在我遇到一个问题,在部分苹果手机(发现是6/7的多,具体IOS版本、微信版本不明)调用JSSDK分享接口成功,没有问题且成功分享!但是在success回调函数貌似没有执行???因为只有部门的iphone 6/7 有这个问题!其他也拿过iphone进行测试,也没发现什么!!!!! ===========疑惑========= 如上反应的部门 ios分享成功后貌似不进入回调的问题,请问有遇到过吗? (开发者工具、安卓测试都是通过的,仅有部分ios问题)

nongzhenli avatar Oct 03 '18 02:10 nongzhenli

你好,我现在遇到一个问题,IOS端,history模式下,xxxx.com进首页可以自定义分享,路由跳转到详情页后设置分享内容,此时详情页自定义分享就失效了;xxxx.com/或xxx.com?a=1这样的url进入项目就不会有问题,所有页面都可以正常自定义分享,唯独xxxx.com进入不行,请问这是什么原因?

xingxinglail avatar Jan 22 '19 07:01 xingxinglail

同一个页面,Android和iOS均能分享出来,且自定义的titledesc均正常显示,但是分享成功之后,iOS点击该分享卡片能正常进入该页面,Android点击之后则进入首页,分别复制出该分享链接后发现:iOS端链接末尾加了参数from=singlemessage&isappinstalled=0#/lawoffice/10433,Android端则仅为from=singlemessage。 开发环境:Vue 2.X,vue-router为hash模式,微信版本均为最新的7.X,JSSDK版本为1.2.0,分享接口为onMenuShareAppMessage

zhoubhin avatar Mar 22 '19 05:03 zhoubhin

同一个页面,Android和iOS均能分享出来,且自定义的titledesc均正常显示,但是分享成功之后,iOS点击该分享卡片能正常进入该页面,Android点击之后则进入首页,分别复制出该分享链接后发现:iOS端链接末尾加了参数from=singlemessage&isappinstalled=0#/lawoffice/10433,Android端则仅为from=singlemessage。 开发环境:Vue 2.X,vue-router为hash模式,微信版本均为最新的7.X,JSSDK版本为1.2.0,分享接口为onMenuShareAppMessage

https://segmentfault.com/q/1010000011061623/a-1020000018806544 试试这种做法?

microJ avatar Apr 10 '19 02:04 microJ

同一个页面,Android和iOS均能分享出来,且自定义的titledesc均正常显示,但是分享成功之后,iOS点击该分享卡片能正常进入该页面,Android点击之后则进入首页,分别复制出该分享链接后发现:iOS端链接末尾加了参数from=singlemessage&isappinstalled=0#/lawoffice/10433,Android端则仅为from=singlemessage。 开发环境:Vue 2.X,vue-router为hash模式,微信版本均为最新的7.X,JSSDK版本为1.2.0,分享接口为onMenuShareAppMessage

https://segmentfault.com/q/1010000011061623/a-1020000018806544 试试这种做法?

我最后找到一种骚操作:在main.js文件中关于微信JS-SDK配置中继续保留onMenuShareAppMessage方法,同时加入新方法updateAppMessageShareData,然后在需要调用分享功能的页面继续使用onMenuShareAppMessage,JS-SDK版本则继续使用原先接入的1.2.0,最后测试发现均可在iOS以及Android平台实现分享功能。

zhoubhin avatar Apr 12 '19 05:04 zhoubhin

同一个页面,Android和iOS均能分享出来,且自定义的titledesc均正常显示,但是分享成功之后,iOS点击该分享卡片能正常进入该页面,Android点击之后则进入首页,分别复制出该分享链接后发现:iOS端链接末尾加了参数from=singlemessage&isappinstalled=0#/lawoffice/10433,Android端则仅为from=singlemessage。 开发环境:Vue 2.X,vue-router为hash模式,微信版本均为最新的7.X,JSSDK版本为1.2.0,分享接口为onMenuShareAppMessage

https://segmentfault.com/q/1010000011061623/a-1020000018806544 试试这种做法?

我最后找到一种骚操作:在main.js文件中关于微信JS-SDK配置中继续保留onMenuShareAppMessage方法,同时加入新方法updateAppMessageShareData,然后在需要调用分享功能的页面继续使用onMenuShareAppMessage,JS-SDK版本则继续使用原先接入的1.2.0,最后测试发现均可在iOS以及Android平台实现分享功能。

思路奇特啊同学👍,然而 onMenuShareAppMessage 要被微信废弃了 :(

microJ avatar Apr 12 '19 09:04 microJ

同一个页面,Android和iOS均能分享出来,且自定义的titledesc均正常显示,但是分享成功之后,iOS点击该分享卡片能正常进入该页面,Android点击之后则进入首页,分别复制出该分享链接后发现:iOS端链接末尾加了参数from=singlemessage&isappinstalled=0#/lawoffice/10433,Android端则仅为from=singlemessage。 开发环境:Vue 2.X,vue-router为hash模式,微信版本均为最新的7.X,JSSDK版本为1.2.0,分享接口为onMenuShareAppMessage

https://segmentfault.com/q/1010000011061623/a-1020000018806544 试试这种做法?

我最后找到一种骚操作:在main.js文件中关于微信JS-SDK配置中继续保留onMenuShareAppMessage方法,同时加入新方法updateAppMessageShareData,然后在需要调用分享功能的页面继续使用onMenuShareAppMessage,JS-SDK版本则继续使用原先接入的1.2.0,最后测试发现均可在iOS以及Android平台实现分享功能。

思路奇特啊同学👍,然而 onMenuShareAppMessage 要被微信废弃了 :(

废弃之前先用着再说,之前找过其他很多方法,就是不能实现在两大移动操作系统上的分享功能,我表示我也很无奈……

zhoubhin avatar Apr 13 '19 01:04 zhoubhin

你好,我现在遇到一个问题,IOS端,history模式下,xxxx.com进首页可以自定义分享,路由跳转到详情页后设置分享内容,此时详情页自定义分享就失效了;xxxx.com/或xxx.com?a=1这样的url进入项目就不会有问题,所有页面都可以正常自定义分享,唯独xxxx.com进入不行,请问这是什么原因?

@xingxinglail 你好 请问后来有解决吗?昨天跟人一起调了一下午加一晚上 也没找到解决办法😭

dingcaiying avatar Jun 08 '19 09:06 dingcaiying

你好,我现在遇到一个问题,IOS端,history模式下,xxxx.com进首页可以自定义分享,路由跳转到详情页后设置分享内容,此时详情页自定义分享就失效了;xxxx.com/或xxx.com?a=1这样的url进入项目就不会有问题,所有页面都可以正常自定义分享,唯独xxxx.com进入不行,请问这是什么原因?

@xingxinglail 你好 请问后来有解决吗?昨天跟人一起调了一下午加一晚上 也没找到解决办法😭

要不试下我前面提到的方法?假如你做的分享功能很重要的话,可能还得继续找别的方法试试了,我那个方法只是为了完成分享功能而已,后来PM说不需要了2333

zhoubhin avatar Jun 10 '19 00:06 zhoubhin

你好,我现在遇到一个问题,IOS端,历史模式下,xxxx.com进首页可以自定义分享,路由跳转到详情页后设置分享内容,此时详情页自定义分享就失效了; XXXX .COM /或xxx.com?a=1这样的网址进入项目就不会有问题,所有页面都可以正常自定义分享,唯独xxxx.com进入不行,请问这是什么原因?

@xingxinglail你好请问后来有解决吗?昨天跟人一起调了一下午加一晚上也没找到解决办法😭

1560148032908 这样写已经解决了我的问题

xingxinglail avatar Jun 10 '19 06:06 xingxinglail

@zhoubhin 你们PM好棒棒 想要一个233 意思是同时使用新旧API: updateAppMessageShareData, updateTimelineShareData, onMenuShareAppMessage... 一起用是吗?

dingcaiying avatar Jun 10 '19 06:06 dingcaiying

@xingxinglail 哇!谢谢!我试一下!(不过为啥这么用就好了呢?🤐

dingcaiying avatar Jun 10 '19 06:06 dingcaiying

@zhoubhin 你们PM好棒棒 想要一个233 意思是同时使用新旧API: updateAppMessageShareData, updateTimelineShareData, onMenuShareAppMessage... 一起用是吗?

是的,我试了下新旧一起用,居然能用,醉了,不过最后这个分享功能又不要了……

zhoubhin avatar Jun 11 '19 00:06 zhoubhin

@zhoubhin 😯很迷了。感谢回复~(我们等不及直接上线了 暂时没有机会试...

dingcaiying avatar Jun 11 '19 06:06 dingcaiying