前言

本文主要分享常见的微信 H5 真机调试方法及如何搭建微信 js-sdk的真机调试环境 ,希望对各位有所帮助。

微信 H5 真机调试

开发调试流

基础

整体页面布局,基本逻辑功能建议先使用chrome微信开发者工具调试完成再进入下一步真机调试,常用以下几个方法:

  1. ip 地址访问调试
    手机和电脑处于同一局域网内,比如连着同一个 wifi、电脑开热点给手机、手机开热点给电脑等;然后在手机微信里直接访问项目运行时的 ip 地址(如[http://192.168.0.127:8080/](http://192.168.0.127:8080/))即可进入页面,建议生成二维码扫一扫进去,此时电脑端修改的项目也会同步热更新到移动端

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图1

优点:操作简单 缺点:只能看看样式,测测按钮啥的,页面结构、日志输出之类的啥也看不到

  1. 使用 chromeinspect功能
    大致流程就是用数据线连接手机和电脑,手机授予电脑访问权限(android设备和ios设备授权操作不同),然后在chrome里访问chrome://inspect/#devices打开inspect主界面,此时在手机端访问页面就会被chrome监测到,我们勾选需要调试的页面并点击左下角的inspect就可以打开调试窗口啦。
    要注意一点的是inspect时需要科学上网一次,不然调试窗口无法加载内容。

    优点:电脑端调试窗口映射移动端页面操作,直观 缺点:调试ios设备比较麻烦;本人使用过程中出现调试窗口花屏卡死问题

  2. 使用微信开发者工具 0.7 版
    android设备支持weinre远程调试和X5 Blink内核调试(部分设备支持),若使用X5 Blink内核调试,inspect页面时同样需要科学上网一次;ios设备仅支持weinre远程调试。官方文档有很详细的介绍,这边就不再赘述了(注意手机代理地址不用加http

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图2

优点:电脑端支持调试微信 js-sdk,集成chromeDevTools,支持weinre远程调试 缺点:X5 Blink内核调试很多设备不支持了;远程调试不支持https

  1. 使用spy-debugger
    现在微信上的网页几乎都是使用https协议的,所以方案3稍显捉急,不过没关系,还有杀手锏,就是pyspy神器,只需要npm安装一下,然后按以下官方文档的截图教程操作一顿

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图3【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图4

优点:集成weinre+抓包工具,支持https网页调试 缺点:第一次加载页面较慢,调试过程中容易断开

进阶

以上几种方案基本能应付日常开发调试需求,但想要在手机调试微信js-sdk时就稍显头疼了,因为微信公众号不支持localhostip地址调试,曾经试过打包部署后再调试,但调试成本太高了,还需要后台小哥支持,所以接下来就开始搭建微信 js-sdk的真机调试环境吧

思路

公众号测试号+本地node服务+内网穿透本地运行项目+请求代理 + vconsole

准备
  1. 对本地运行项目进行内网穿透
    电脑运行项目,确定运行端口号,如8080,以uTools内网穿透插件为例,配置好穿透端口号和外网地址,点击右下角连接,成功后就可以通过外网地址访问啦,同时还是支持热更新(工程项目可能会遇到Invalid Host header问题,解决方法详见实操 4)

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图5

  1. 添加手机端调试窗口
    完成步骤 1 就通过外网访问本地项目了,但好像和通过ip地址打开没啥区别。。。别急,该vconsole登场了,本文demovue项目为例,先npm安装一下,在项目里引入并初始化,此时是不是看到页面右小角多了个绿色小按钮,没错,点它就对了。调试界面如下图,功能还是挺齐全的,可以愉快的调戏调试啦

    1. // main.js
    2. if (process.env.NODE_ENV !== 'production') {
    3. const VConsole = require('vconsole')
    4. new VConsole()
    5. }
    6. 复制代码

    【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图6

  2. 本地node服务启动一个本地 node 服务,作用有两个

    1. 用于配置测试公众号时校验url是否能正确响应 Token 验证,详见文档,下面代码示例

      1. // sign.js
      2. const checkout = obj => {
      3. const { signature, timestamp, nonce } = obj
      4. // 公众号里配置的token
      5. const token = config.token
      6. // 字典排序拼接后进行sha1加密,再与signature比对
      7. const string = sort(nonce, timestamp, token),
      8. sha1 = require('js-sha1')
      9. return signature === sha1(string)
      10. }
      11. // router
      12. router.get('/checkout', async (ctx, next) => {
      13. const { echostr, timestamp, nonce, signature } = ctx.query
      14. // 不想校验来源的话可以直接ctx.body = echostr
      15. // 校验来源
      16. const res = util.checkout({ timestamp, nonce, signature })
      17. // 签证正确时返回echostr
      18. ctx.body = res ? echostr : false
      19. await next()
      20. })
      21. 复制代码
    2. 用于生成微信js-sdk签名,首先获取access_token,再用access_token去获取jsapi_ticket,根据签名算法生成签名返回给前端,access_tokenjsapi_ticket都需要缓存到本地,有效期 7200 秒,下面是签名代码示例

      1. // 签名算法
      2. const sign = (jsapi_ticket, url) => {
      3. const ret = {
      4. jsapi_ticket,
      5. url, // 当前url,不要转义!不要转义!不要转义!
      6. nonceStr: createNonceStr(), // 随机字符串
      7. timestamp: createTimestamp() // 时间戳
      8. };
      9. // 字典排序后以url键值对形式拼接
      10. const string = raw(ret),
      11. sha1 = require("js-sha1");
      12. ret.signature = sha1(string);//sha1加密生成signature
      13. ret.appId = config.appId; // 公众号appId也由后端返回
      14. return ret;
      15. };
      16. 复制代码
  3. 前端请求代理
    内网穿透后,使用外网地址访问页面时,若页面内请求的还是真实服务地址的话会产生跨域问题,而且还不能直接请求本地 node 服务地址,所以此时需要进行请求代理。 首先把项目内的请求地址改成穿透地址,然后进行代理转发。webpack工程可以通过配置devServer实现,其他可以使用nginx,本文以vue cli工程配置devServer为例

    1. // vue.config.js
    2. module.exports = {
    3. devServer: {
    4. disableHostCheck: true, // 绕过主机检查,解决Invalid Host header问题
    5. proxy: {
    6. '/getSignature|checkout': {
    7. // checkout 用于公众号校验服务器有效性
    8. // 本地项目获取签名的api名称不为getSignature时,可以重写
    9. // pathRewrite: { "^/api": '/getSignature' }
    10. target: 'http://127.0.0.1:3000' // 代理到本地noe服务地址
    11. },
    12. '^/other': {
    13. // 其他接口也可以代理
    14. target: 'http://xxx.xxx.x.x:80',
    15. changeOrigin: true // 改变请求host,可选
    16. }
    17. }
    18. }
    19. }
    20. 复制代码
  4. 配置微信测试公众号
    首先找到测试号入口,使用微信扫一扫就可以注册一个测试号了,大概界面如下

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图7配置之前请先启动本地node服务和前端项目,然后使用内网穿透工具穿透前端项目运行端口,确定好外网地址,接着在接口配置和安全域名里填上你的穿透地址;接口配置时会发送一次请求到本地node服务校验服务器的有效性,所以要先启动本地node服务;接口安全域名要去掉协议和端口号;配置成功后再微信扫码订阅一下页面里的测试号就大功告成了

优化

经过实操后,当你满心欢喜通过内网穿透地址第一次访问 vue 项目时,是不是发现加载页面巨慢,长时间白屏,甚至因请求超时而加载失败,纳尼?那咋办?别急,可以从以下几个角度去优化

  • 改变source map模式
    vue-cli在开发环境下生成source map的默认模式为 cheap-module-eval-source-map ,该模式下为源代码打包,生成包体积较大,导致页面加载时堵塞了页面渲染,所以此时可以选择使用cheap-source-mapeval模式(构建速度上eval模式会快很多)

    1. //vue.config.js
    2. module.exports = {
    3. configureWebpack: config => {
    4. if (process.env.NODE_ENV !== 'production') {
    5. config.devtool = 'cheap-source-map'
    6. }
    7. }
    8. }
    9. 复制代码

    下面是对比图,vendors包体积减小了近60%,加载时间减少了2.68秒
    【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图8【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图9

  • 开启gzip压缩
    大型的项目在切换完source map模式后,可能会发现vendors包的体积还是很大,这时我们可以尝试开启gzip压缩(一般服务端配置即可)。
    由于uTools内网穿透工具默认开启了gzip,我们配置不了,所以这里以vue-cli开启gzip示例,使用local地址打开页面对比文件压缩前后的差异

    1. module.exports = {
    2. devServer: {
    3. compress: true, // 开启gzip压缩
    4. }
    5. };
    6. 复制代码

    【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图10【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图11

    em…体积是变小了,加载时间却变长了,是我搞错了什么吗,知道的小伙伴解答一下

  • 升级内网穿透带宽(氪金)
    natapp为例(非广告),免费通道的带宽只有1M,TCP连接数限制5个,可当你充钱后,带宽可以提升至100M,直接起飞了是吧。不过一般免费的就够用了,有需求的可以氪一下。

    小结

    完成以上步骤就可以开始愉快进行调试啦,有其他方案的小伙伴欢迎补充。

    微信 js-sdk 使用分享

    开发微信 H5 页面时会遇到许多与微信交互的场景,所以熟悉使用微信js-sdk能大大减少加班时间提升开发效率;接下来聊聊日常开发微信js-sdk中常遇到的问题,如果没使用过的小伙伴可以先看看官方文档

invalid signature签名错误

出现频次最高的错误,当确认变量名拼写、签名算法没问题的前提下,可以从url角度去入手排查,详细请看下面几种情况

  1. 获取url只要hash前面的部分

    1. const url = location.href.split('#')[0]
    2. // http://example.com/#login?age=99 -> http://example.com/
    3. 复制代码
  2. 路由模式差异
    vue路由为例,在hash模式下,无论路由如何变化,截取的url都不会变;但在history模式下,不同页面截取的url是不同的,所以当页面切换时得动态获取当前url去签名,此时还要区分平台差异,看下一条

  3. 平台差异(history模式下)
    • android平台,不同页面动态获取当前路由页面的url去签名都可以成功
    • ios平台,不同页面都需要使用第一次进入页面时的url去签名才可以成功
  4. encode问题
    文档里要求签名url使用encodeURIComponent,否则会影响页面分享,然后这里需要注意的就是服务端拿到url后一定要decodeURIComponent后执行签名算法,不然config也会失败
    1. // encodeURIComponent前
    2. 'http://example.com/'
    3. // encodeURIComponent后
    4. 'http%3A%2F%2example.com%2F'
    5. // 以下转义也会失败
    6. 'http:\/\/example.com\/'
    7. 复制代码

    require subscribe错误

    一般本地调试时才会遇到。扫码订阅公众平台测试号就可以解决

invalid url domain错误

一般是js接口安全域名没有正确配置导致,注意去掉协议和端口号,然后检查拼写

接口常见问题

wx.readywx.error

调用wx.config后,一般通过这两接口判断config是否成功,但注意以下几点

  • 执行了wx.error回调表示config一定失败了
  • wx.ready回调无论config成功与否执行(黑人问号脸???),因为会遇到以下几种情况:
    1. 第一次执行wx.config后,若config失败,会优先执行wx.error回调,随后再执行wx.ready回调
    2. 但从第二次执行wx.config开始,成功时仅执行wx.ready回调,失败时wx.error回调会在wx.ready回调后执行

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图12

  1. 只执行了wx.ready回调,但调用接口时还是会出现the permission value is offline verifying情况,此时一般都是因为config异常了,请重新执行wx.config

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图13

针对以上问题,可以使用 Promise 封装一下config方法,但仅限第一次config有效,所以最终是否config成功,我们可以放到功能接口回调里去判断

  1. // 代码示例,详见本文demo
  2. jsSdk.config({
  3. debug: false,
  4. appId,
  5. timestamp,
  6. nonceStr,
  7. signature,
  8. jsApiList
  9. })
  10. return new Promise((resolve, reject) => {
  11. // ready不一定config成功...
  12. jsSdk.ready(() => {
  13. console.log('ready')
  14. resolve(jsSdk)
  15. })
  16. // 有error 的话会比ready先执行
  17. jsSdk.error(err => {
  18. console.log('err')
  19. reject(err)
  20. })
  21. })
  22. 复制代码

分享接口

首先明确一点,H5 页面是无法通过该类接口主动调起微信菜单里的分享菜单的, 降级处理一般就是弹窗提示进行引导分享,但存在封号风险,谨慎使用!

  • wx.onMenuShareTimelinewx.onMenuShareAppMessage 可以获取到用户是否点了微信菜单里的分享按钮,但无法判断是否真正分享了出去,比如弹出分享窗口后点击“否”返回页面,也算入success回调里。这两接口即将废弃,即将是何时是个未知数,所以还是尽量别用
  • wx.updateAppMessageShareDatawx.updateTimelineShareData 这两兄弟就是为了取缔上面两兄弟的,砍到了按钮点击状态获取功能,这么好的产品经理哪里找…

    图像接口

  • wx.chooseImage返回的本地照片localId,类似于使用URL.createObjectURL创建的文件引用,android客户端可以直接当 img标签的src正常使用,但ios端不行,得使用wx.getLocalImageData转为base64格式再进行展示

  • wx.uploadImage会将你得图片上传到微信服务器保存 3 天(大厂财大气粗),并返回图片在服务器 里对应的ID,有效期内使用wx.downloadImage即可获取到该图片的localId

    待补充…

    调试 DEMO

    看到这是不是觉得有点懵,所以为了让小伙伴们更容易理解文中内容,我用vue cli整了个demo给大家,从githubclone下来就可以用了,整体项目结构如下图,项目地址vue-js-sdk-demo

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图14

  • 把项目配置放到了根目录,为了方便配置

    1. /config/index.js
    2. module.exports = {
    3. baseUrl: "http://example.com", // 启动内网穿透后在此处修改地址
    4. appId: "wxxxxxxxxxxxx43", // 测试公众号appId
    5. secret: "7acsssssssssssssss5289", // 测试公众号secret
    6. token: "candyman" // 测试公众号token,自定义
    7. };
    8. 复制代码
  • 使用natapp进行内网穿透的话(使用其他内网穿透工具的可以跳过阅读),请在natapp官网配置好穿透端口号,然后在/natapp/config.ini里填写你的通道号,Windows系统直接双击打开natapp.exe即可,Mac系统请到官网载一个对应客户端替换一下

    1. [default]
    2. authtoken= 填写你的隧道authtoken
    3. 复制代码
  • 配置微信测试公众号,步骤见上文

    1. // 初始化项目
    2. npm install
    3. // 同时启动vue项目和node服务
    4. npm run start
    5. // 单独启动vue项目
    6. npm run dev
    7. // 单独启动node项目
    8. npm run service
    9. 复制代码
  • 启动项目后,大概长下面这样子,添加了几个api方便测试,demo里有二次封装sdk的示例,可参考

【公众号】手把手教你搭建微信js-sdk真机调试环境 - 图15

更新日志

2020-4-1 补充微信js-sdk config结果说明

作者:candyman
链接:https://juejin.im/post/5e7e241f6fb9a03c317608c8
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。