前端微信开发踩坑集锦

2,693 阅读3分钟
原文链接: mp.weixin.qq.com

目的

最近半年多一直在公众号上开发业务, 由于第一次开发公众号所以踩了很多坑, 因此写这篇文章一是为了总结, 而是希望对踩坑中的童鞋有点帮助。

项目背景

基于Vue开发的单页应用, 路由hash模式。

开发前准备工作

  • 申请公众号, 开通各种需要的权限

  • 设置页面授权域名

  • 设置JS接口安全域名

  • 绑定开发者微信

  • 下载开发者工具

  • 利用开发者工具本地调试微信sdk

// 方案很多, 这里只介绍我用的方法 - 安装nginx, 设置配置文件. 思路就是监听80端口, 转向我们本地项目. server {    listen 80;    server_name localhost;    location / {          index  index.html index.htm home.html;      proxy_pass http://localhost:9999/;     }   } - 然后在你的hosts,设置你的域名指向本地. 推荐SwitchHosts!.

微信授权

微信文档已经很详细了。

微信公众平台 mp.weixin.qq.com

授权方式: 1. 静默授权: 以snsapi_base为scope发起的网页授权。 2. 用户手动触发的以snsapi_userinfo为scope发起的网页授权。获取的信息权限更多。

由于我们业务上支持游客模式与用户模式: 所有我们需要在任意页面通过业务需要触发用户模式进行授权并返回当前页或者登陆页面(即新用户)。

自定义分享

由于微信默认的分享或暴露出外链, 所有我们需要对每个页面进行自定义一次。

  • 绑定域名

  • 引入js文件

我开发时候发现没有1.4.0版本的包, 所有就自己发了一个在npm, 有需要的也可以安装. https://www.npmjs.com/package/easy-wechat-js-sdk

  • 通过config接口注入权限验证配置

- 一般都是前端用url(location.href.split('#')[0])调用后台接口去签名。 - url需要进行encodeURIComponent进行编码. - 同一个url仅需调用一次签名 - 对于变化url的SPA的web app可在每次url变化时进行调用,所以你可以在App.vue里面监听$route变化去开始签名

  • 开始调用微信分享sdk方法

这里有几个需要注意.

  1. 自定义分享成功后的页面url会带有微信返回的参数, 因此再你分享后的帖子再次二次分享时候, 如果你没考虑到的话, 二次分享就会失败, 因此最好就是使用当前页面去签名以及作为分享的link。

对于IOS系统会自动增加如下参数: 朋友圈 from=timeline&isappinstalled=0 微信群 from=groupmessage&isappinstalled=0 好友分享 from=singlemessage&isappinstalled=0 对于安卓系统会自动添加如下参数: 朋友圈 from=timeline 微信群 from=groupmessage 好友分享 from=singlemessage

   2. 安卓手机下自定义分享后会截掉你#之后的所有内容. 由于我们使用的是hash模式, 因此会有这样的bug, 这就导致二次分享时候一直只会进入首页, 显然这个在业务上是不允许的。

解决方法:

// 针对安卓系统, 需要特殊处理添加一个wx-share.html文件作为中转.处理分享的link. if (platform === 'Android') {                // fix安卓下的自定义分享                realLink = window.location.origin + window.location.pathname + 'wx-share.html?redirect=' + encodeURIComponent(window.location.href)            }

在wx-share.html里面就是直接重定向到我们之前分享的页面。

<!DOCTYPE html> <html lang="en"> <head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title></title> </head> <body>    <script type="text/javascript">    function getParmas(url) {        var theRequest = {},            strs;        if (url.indexOf('?') != -1) {            var str = url.split('?')[1];            strs = str.split("&");            for (var i = strs.length - 1; i >= 0; i--) {                theRequest[strs[i].split("=")[0]] = strs[i].split("=")[1];            }        }        return theRequest;    };    var parms = getParmas(window.location.href);    window.location.href = decodeURIComponent(parms.redirect);    </script> </body> </html>

微信支付

如果你的支付页面很多的话, 我建议统一跳到一个html页面做支付业务逻辑处理, 因为你会发现你的支付目录不够配置了。

function onBridgeReady () {            const wxPayOrderInfo = getWxPayInfo()            if (!wxPayOrderInfo) {                document.querySelector('.tips').innerText = '此订单已结束';                setTimeout(() => {                    window.history.go(-1)                }, 20)                return            }            console.log('签名参数', wxPayOrderInfo)            // 正在拉起支付            document.querySelector('.tips').innerText = '正在拉起支付...';            WeixinJSBridge.invoke(                'getBrandWCPayRequest', {                    appId: wxPayOrderInfo.appid, //公众号名称,由商户传入                    timeStamp: wxPayOrderInfo.timestamp, //时间戳,自1970年以来的秒数                    nonceStr: wxPayOrderInfo.nonceStr, //随机串                    package: wxPayOrderInfo.package,                    signType: wxPayOrderInfo.signType, //微信签名方式                    paySign: wxPayOrderInfo.paySign ,  //微信签名                },                function(res){                    // 使用以下方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠                    if(res.err_msg == "get_brand_wcpay_request:ok") {                        wxPayOrderInfo.result = 'ok';                        // 支付成功                        document.querySelector('.tips').innerText = '订单支付成功';                    } else {                        wxPayOrderInfo.result = 'fail';                         // 支付失败                        document.querySelector('.tips').innerText = '订单支付失败';                    }                    setLocalStorage('dcPay', JSON.stringify(wxPayOrderInfo))                        setTimeout(() => {                            window.history.go(-1)                        }, 20)                }            );        };        if (typeof WeixinJSBridge == "undefined") {            if( document.addEventListener ) {                document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);            } else if (document.attachEvent) {                document.attachEvent('WeixinJSBridgeReady', onBridgeReady);                document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);            }        }else {            onBridgeReady();        }

支付另外需要注意在商户配置支付目录问题:

1. 需要配置一个在你项目的根目录 2. 配置到具体你的支付页面3. 多入口时候记得也要配置这个入口的url

在公众号通过浏览器打开任意界面只会进入首页问题

业务需要:  微信端我们有一个app下载引导页, 也就是为例

在任意页面你去复制链接或者通过浏览器打开等都会发现只进入首页, 这是由于x5内核就会出现pushstate问题, 在X5里,url栏不会改变。

解决方法:

// loadApp页面: 引导页 // hash模式监听的是hashChange const loadAppUrl = `${location.origin}${location.pathname}?v=2018#/loadApp?${location.hash.split('?')[1]}` const state = {  title: "下载App",  url: loadAppUrl }; window.history.pushState(state, state.title, state.url); window.location.href = loadAppUrl; // 先跳转url再绑定事件顺序不能反 window.addEventListener("popstate", this.handleGoBack, false);

这样子问题解决了, 但是会导致一个问题就是进入loadApp页面后, 我点击后退需要后退两次, 这显然用户体验不好。

所以我想到一个hack方法。

// 之所以需要手动pushState一次是因为进入loadApp也会触发popstate const state = {   title: "下载App",   url: loadAppUrl }; window.history.pushState(state, state.title, state.url); // 然后监听popstate事件, 一旦用户点击物理后退按钮就往后退 window.addEventListener("popstate", this.handleGoBack, false);  handleGoBack () {     this.$router.go(-1)  }, // 组件销毁时候需要解绑事件 window.removeEventListener("popstate", this.handleGoBack)

在微信端下唤起本地App

起始思路也比较简单:

  1. 首先微信设置有白名单, 我们在微信里面直接是拉不起App的。

   2. 只能引导用户用浏览器打开App下载页面。

   3. 与安卓端/IOS端约定Schema协议, 如果本地安卓会拉起App,没有就跳转到AppStore或者腾讯应用宝去下载。

具体思路可以参考这篇文章总结的很好, 我们的做法与他的类似,这里就不贴代码了。

H5唤起APP指南(附开源唤端库) - 掘金 juejin.im

总之: 微信下公众号坑真多!