前言

三月伊始,此月任务重心在于用户的拉新与传播,自然也少不了新增加些许需求。由我负责用户分享传播的需求,主要任务就是在于微信分享。
在做之前觉得这个很简单,就几个接口的事情罢,实际上做起来,却是不如意料那般简单,踩坑颇多。

在做这个分享需求之前,和同事们也已经讨论过大致的流程。无非常用的手法,针对用户生成唯一二维码,通过微信分享出去,然后其他人注册填写邀请码获取奖励。

在填写邀请码这里,我参考了一些主流 APP 的做法。正常是复制邀请码然后用户找到入口粘贴邀请码并进行激活,但是发现有个别的 APP 体验很好,可以做到复制邀请码后,直接抵达 APP(网易蜗牛读书) 内部 WebView 中自动填写邀请码。

在对这个 APP 抓包分析之后发现了其中的奥妙所在,这是他们分享页面的地址:

https://du.163.com/static/wechatFallback.html?openurl=nesnailreader://webview?url=https://du.163.com/invite?code=EPPEG&inside=true&downloadurl=https://du.163.com/download

原来他们使用了一种叫做 schema 的技术,可以直接在浏览器中打开 APP。于是开始了模仿之旅。

知道了其他 APP 的做法后,便询问了客户端的同事,能不能实现同样的效果,他们都是说以前没有这样做过,但是可以做。协调了前端与客户端同事,共同开发这个看起来挺简单的功能需求。客户端同事都很给力,虽然出现了一些小插曲,但很快便调通了功能,剩下了 WAP 版本微信分享,由于之前都没有做过,踩了不少的坑,分享这次踩坑,这也是本文重心所在。

坑一

后台代码开发不必多说,跟着文档开发,因为需要获取 微信公众号的 AccessToken 所有需要在微信后天白名单处添加本机 IP 。

在微信开发者工具中,调试微信 JSSDK 时,发现 JS-SDK 提示签名错误{errmsg:config: invalid signature},但是通过 微信 JS 接口签名校验工具 提交相关参数进行校验后,发现程序生成的和微信网页生成的签名是一样的,但是这里就一直提示是无效的签名。

我查看了 JS-SDK 下注册 config 信息处的输入参数,发现本该提交五个参数,但是只提交了四个,漏提交了nonceStr 参数,如果你发现程序生成的和微信网页生成的签名是一样的,但是提示无效签名,务必检查是否是这里的问题。还有提交了五个参数,但是参数的大小写不正确的的,比如 nonceStr 写成了 nonceStr 也是不行的。可以对比下图进行校验。

坑二

坑一种提到了 AccessToken,使用 JSSDK 时还需要另外一个 ticket,这二者都有超时时间的限制,如果过期了,那么 config 是无论如何也不会初始化成功的。

坑三

踩了前两个坑之外,其实 WAP 版的开发也都差不多调通了,但是分享之后,分享人进入分享的链接后,二次分享时,便又出现了无效签名的情况,仔细排查之后,发现是分享后,微信会在分享的链接后面自动加上了一些参数,正是因为这些参数的存在,导致签名失败。

刚开始没有细看文档,因此分享 URL 的地址就没有进行动态传递到后台进行签名,所以导致了二次分享出现了问题,于是修改为了动态传递当前 URL 到后台进行签名,才解决了这个问题。

需要注意的是,如果当前的 URL 中包含了中文,需要进行
encodeURIComponent 后传递,再在后台进行 URL 解码处理。另外编码之后最好再将参数中的 & 临时替换为 %26,后台再替换为 &,如果直接传到后台,存在多个参数的情况下,后台将只会接收到第一个参数。

小插曲

安卓客户端进行开发的时候,出现了很奇怪的状况,就是在 WebView 里面无法获取当前 APP 登录的用户信息,即 WebView 发送请求到服务器,发现获取不到 Cookie 中登录用户信息的值,而 IOS 客户端便没有出现这种情况。

之前安卓在做签到功能的时候,也是使用的 WebView,负责签到后台开发的同事也遇到了这种情况,当时没有彻底解决这种问题,使用了一种折中的方法来实现,让安卓客户端传递一串包含用户信息的加密串参数,后台解析这个参数判断用户。

谷歌查找这种情况之后,发现安卓需要将 Cookie 同步到 WebView 中,询问安卓同事之后,他说同步过了啊,这就很奇怪了!

继续万能谷歌查找,然后看了一下同事的客户端代码,发现他同步 Cookie 到 WebView 部分的代码并没有设置 Cookie 的 domainpath,而后台获取登录用户信息时,只去获取指定域名指定路径下的 Cookie 值,自然是获取不到 WebView 里登录用户信息的值了。

知道了问题,解决起来就简单多了,只要将需要同步的每一条 Cookie 信息设置 DomainPath 即可,后台也就可以拿到同步的 Cookie 信息了。

1
2
3
4
public static boolean syncCookie(String url, String cookie) {
cookie += ";Max-Age=3600" + ";Domain=.cctv.com" + ";Path = /"
cookieManager.setCookie(url, cookie);
}