0%

微信小程序从 0 到 1

大概这一年左右的时间,都在跟小程序相关的需求。从开发到上线,流程上会跟以往的 Web 开发有些不同。此前除了大学时的一次课设,其他时间未曾接触过小程序,算是从 0 开始吧。不过得益于 Uniapp 基于 Vue.js 的语法封装,除了小程序自己的 API 之外,语法学习成本几乎没有。

与H5相比,孰优孰劣

对比

  • 运行环境
    • ​网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应;
    • 在小程序中渲染层和逻辑层分别运行在不同的线程中。即 双线程模型
  • 开发差异
    • 小程序原生写法很像前端框架中的 Vue,也是 MVVM 模式,但是写法上没有完全照抄,都可以用类似虚拟 DOM 的形式能保证你的数据变化自动响应到模板;
    • 小程序里不能使用任何 window 下的属性和方法;
    • 小程序不可以过虚拟 DOM 来操作 DOM,不能使用任何 DOM 和 BOM 相关API;
      • 这是因为:小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的 DOM API 和 BOM API;
    • 小程序提供了很多 SDK 方法,几乎涵盖了 APP 能赋予 H5 的所有能力;
    • 小程序类似于离线包,只要用户访问过,就会把主包代码下载到本地。
  • 维护成本
    • 网页开发者需要面对各式的浏览器兼容 :如 PC 端需要面对 IE、Chrome、QQ浏览器等,在移动端需要面对 Safari、Chrome 以及 iOS、Android 系统中的各式 WebView,开发时只需要常用的编辑器和浏览器即可 ;
    • 小程序开发过程中需要面对的是两大操作系统 iOS 和 Android 的 微信客户端 ,以及用于辅助开发的小程序开发者工具;小程序的 开发者需要经过申请小程序帐号、安装小程序开发者工具、配置项目 等等过程才可进行小程序开发。

开发前准备

账号相关权限

开发者和测试相关的权限需要在微信后台添加;权限分为项目成员和体验成员,都有数量限制。
一般将开发者添加为 项目成员 ,将测试人员或者 PM 添加为 体验成员

开发上手

相关文档

项目目录

一个小程序主体部分由三个文件组成,必须放在项目的根目录:

文件 必须 作用
app.js 小程序逻辑:调用小程序实例、小程序生命周期 hook
app.json 全局配置:决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等
app.wxss 小程序公共样式表
project.config.json 项目配置文件(如:appId、编译时配置、依赖等)

相关概念

小程序运行机制

冷启动

如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动,即冷启动。冷启动不保留上次的浏览场景,打开即直接进入首页(可以使用 restartStrategy 配置冷启动进入的页面)。

热启动

如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态,这个过程就是热启动。热启动保留上次浏览的 path。

小程序更新机制

开发者在管理后台发布新版本的小程序之后,微信客户端会静默更新到新版本。但是无法立刻影响到所有现网用户,最差情况下,也在发布之后 24 小时之内下发新版本信息到用户。
如果需要马上应用最新版本,可以使用 wx.getUpdateManager API 进行处理。

  • UpdateManager.applyUpdate():强制小程序重启并使用新版本,在小程序新版本下载完成后调用;
  • UpdateManager.onCheckForUpdate():监听向微信后台请求检查更新结果事件。微信在小程序冷启动时自动检查更新,不需由开发者主动触发;
  • UpdateManager.onUpdateReady():监听小程序有版本更新事件。客户端主动触发下载(无需开发者触发),下载成功后回调;
  • UpdateManager.onUpdateFailed():监听小程序更新失败事件;

基础库

小程序的能力需要微信客户端来支撑,每一个基础库都只能在对应的客户端版本上运行,高版本的基础库无法兼容低版本的微信客户端。
参考:基础库版本分布

分包

某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。这样做可以优化小程序首次启动的下载时间,在多团队共同开发时可以更好的解耦协作。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。

目前小程序分包大小有以下限制:

  • 整个小程序所有分包大小不超过 20M
  • 单个分包/主包大小不能超过 2M

开发者通过在 app.json subpackages 字段声明项目分包结构:
写成 subPackages 也支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
]
}
]
}

打包原则

  • 声明 subpackages 后,将按 subpackages 配置路径进行打包,subpackages 配置路径外的目录将被打包到 app(主包)中
  • app(主包)也可以有自己的 pages(即最外层的 pages 字段);
  • subpackage 的根目录不能是另外一个 subpackage 内的子目录;
  • tabBar 页面必须在 app(主包)内。

引用原则

  • packageA 无法 require packageB JS 文件,但可以 require app、自己 package 内的 JS 文件;
  • packageA 无法 import packageB 的 template,但可以 require app、自己 package 内的 template;
  • packageA 无法使用 packageB 的资源,但可以使用 app、自己 package 内的资源。

例如:nodemodules 包中引用的代码会打包到主包中,因为该文件路径在 subPages 之外。

鉴权登录

小程序鉴权登录流程图

常用 API 及能力

  • 常用事件如 Tap、longPress 参照:WXML的冒泡事件列表

  • getApp():获取全局的应用实例,全局数据可以在 App 中设置

    1
    2
    3
    4
    5
    6
    7
    8
    // app.js
    App({
    globalData: 1
    })

    // a.js
    var app = getApp()
    app.globalData++
  • 授权相关信息

    • 获取用户手机号
      • 需要将 <button> 组件 open-type 的值设置为 getPhoneNumber,当用户点击同意之后,可以通过 bindgetphonenumber 事件回调获取到微信服务器返回的加密数据;
        1
        <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
    • wx.getSetting() 获取用户当前权限配置,常可以用来在调用某项系统功能时,查看用户是否授权(例如保存存图片到相册)
    • wx.authorize() 向用户发起授权请求,调用后会立即弹窗询问用户是否同意授权小程序使用某项功能( 如果用户之前已经同意授权,则不会出现弹窗
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      // 下边这段代码就是上两个 API 的应用
      wx.getSetting({
      success: (res?: any) => {
      // 判断是否已经授权
      if (!res['scope.writePhotosAlbum']) {
      wx.authorize({
      scope: 'scope.writePhotosAlbum',
      success: () => {
      // 存储图片
      wx.saveImageToPhotosAlbum(...)
      }
      })
      } else {
      // 调起客户端小程序设置界面,返回用户设置的操作结果
      wx.openSetting()
      }
      }
      })
    • 若想取消当前用户授权,可【点击小程序右上角三个点】->【设置】->【用户信息】里取消授权
  • 生成小程序二维码

    • wxacode.createQRCode:获取小程序二维码,适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制;
  • 小程序运行版本的区分

    • __wxConfig.envVersion:会返回当前小程序运行版本
      • develop - 开发版
      • trial - 体验版
      • release - 正式版
    • 注:此方法没有在官方文档上注明,只是挂在在全局 this 下,使用时注意该对象是否存在。
    • 客户端分享的小程序链接可以指定小程序版本,需要跟客户端同学提前约定好,例如:
  • 与其他第三方应用进行交互

    • 跳转第三方小程序:需要将被调用的第三方小程序的 AppId 加入到小程序项目白名单中,正式版只能打开正式版;
      • wx.navigateToMiniProgram
      • wx.navigateBackMiniProgram
    • 小程序内关注公众号:
      • <official-account> 原生组件,只能关注与小程序主体相同的公众号(后台配置),且样式不允许自定义,使用场景受限(扫码);
    • 小程序唤起 app:
      • 直接唤起:否;
      • 由 app 直接调起小程序,然后小程序可以通过操作再调起 app;
      • 从 app 分享出去的小程序,可以调起 app:需要将 <button> 组件 open-type 的值设置为 launchApp,可通过 app-parameter 参数给 App 传参(详情
        (PS:App分享到小程序的参数,支持选择 正式版、体验版、开发板)
      • 2021.5.19 后,小程序不再支持唤起 App 的能力;
      • 无法从小程序的 webview 组件中唤起 App,微信做了 Url Scheme 拦截;
    • 小程序内 webview 访问 H5:
      • <web-view> 原生组件,个人类型的小程序暂不支持使用,需要在微信后台将域名加入白名单;
      • 在微信后台下载”校验文件“,并将校验文件上传至网站根目录,供小程序平台进行验证,验证通过了才能成功添加域名;
      • 注:若要从 webview 打开的 H5 跳转回小程序原生页,则需要提前引入 wx-js-sdk,使用 wx.miniProgram.navigateTo 方法 (官方文档)
    • 小程序内打开公众号文章:
      • 使用 <web-view> 组件即可打开相关联的公众号文章,非关联的公众号则提示“无法打开图文消息”;
      • 在微信管理后台:设置 -> 关联设置 中可以看到“关联的公众号”,(需要到公众号中关联小程序)。
  • 第三方应用与小程序的交互

    • APP 调起微信小程序(只能调用与当前APP相关联的小程序) 参考
      • 在微信管理后台:设置 -> 关联设置 中可以看到“关联的移动应用”;
      • 可跳转到指定页面
      • 限制
        • APP和小程序相同主体:如果在同一个主体下,不存在调用个数限制;
        • APP和小程序不同主体:如果不在同一个主体下,一个app最多只能关联3个小程序。也就是说,非相同主体的小程序最多拉起3个;
    • 外部 H5 调起微信小程序
      • 直接调用:否;
      • 可根原生同学协商,使用 APP 提供的 SDK 方法调用;
      • 或者使用使用微信云开发能力的托管 H5,免鉴权直接跳转任意合法的小程序;
    • 短信跳转小程序
      • 直接调用:否;
      • 微信开放能力 - 服务端接口 - 可以获取打开小程序任意页面的 URL Link。适用于从短信、邮件、网页、微信中直接打开;
      • 使用微信云开发能力,打开M页跳转小程序(待调研);
    • 公众号打开小程序(只能调用与当前公众号相关联的小程序)参考

常见的问题

项目测试

可以从 H5 直接进入小程序体验版

在移动端打开:

https://open.weixin.qq.com/sns/getexpappinfo?appid={AppId}&path={pagesPath}.html

即可访问小程序体验版,并跳转到对应路径(注意:此链接只能在移动端微信中打开).

也可以,通过判断微信版本,自己写一个测试/入口构造页面来作为测试入口。

缓存

小程序的所有缓存数据上线为 10MB,像 storage 中的数据,除非用户主动删除或因存储空间原因被系统清理,否则数据都一直可用。
清除缓存:

  • 发现-小程序-在列表中删除掉测试的小程序;
  • 微信-我-设置-通用-存储空间;
  • 安卓在私信聊天页输入 debugx5.qq.com ,利用腾讯的工具清理 cookie;
  • 退出登录,重新登录。

Android

由于安卓9的安全限制,无法信任用户自行安装的证书,正常状态连代理打开小程序会报错“获取运行环境失败”;
将手机 root 后,解决证书信任问题后才能访问。

IOS

直接连代理,访问小程序即可。

框架对比

业内知常见小程序框架:wepy、mpvue、uni-app、taro、chameleon。
主流框架对比:详情
主流框架性能对比:详情
目前使用的是 Uniapp,因为可以编译多平台的小程序,且与 Vue 的语法能无缝衔接,开发成本较低。

个人偏见

关于功能开发

从一个开发者的角度,我并不希望听到 PM 说“这个功能和页面要和APP保持一致”。
个人认为 APP 承载的功能是核心且重的,也是在用户体验上最优的一端,若将 H5 和小程序的功能完全与 APP 拉齐,不仅开发周期长,维护难度高,同时会让小程序和 H5 失去本身的轻量优势。
小程序 和 H5 应该承载更多引流的功能,而不是一整套完备的 APP,当然了,这句话是针对公司有核心 APP 的情况;若是主要产品就是小程序方向,就看功能利弊的权衡了,只是个人认为“小程序”不应该变成一个庞然大物,对于 PM 而言应该更侧重于对于不同端的用户给出不同的产品特性,而不是一味的追求“复刻”。

关于设计还原

由于小程序提供的通用的原生组件有的时候,是不允许开发者更改某些样式的,此时要跟设计同学及时反馈;若要自己开发某些组件,记得增加工期。
用现有的框架也可以:汇总9款优秀的开源小程序UI框架

关于部署上线

最后一点,不管是开发还是审核部署,小程序强烈依赖微信运行环境,被封禁和能否上线的话语权(例如小程序中有游戏广告之类的,通常就会被封禁)并非掌握在自己手里,需要做好被封禁时的准备,域名同理。

参考链接