w3cschool-微信小程序开发文档-指南
https://www.w3cschool.cn/weixinapp/9wou1q8j.html
https://www.w3cschool.cn/miniappbook/
微信小程序 小程序简介
小程序简介
小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。
小程序技术发展史
小程序并非凭空冒出来的一个概念。当微信中的 WebView
逐渐成为移动 Web 的一个重要入口时,微信就有相关的 JS API
了。
代码清单1-1 使用 WeixinJSBridge
预览图片
WeixinJSBridge.invoke('imagePreview', {
current: 'http://inews.gtimg.com/newsapp_bt/0/1693121381/641',
urls: [ // 所有图片的URL列表,数组格式
'https://img1.gtimg.com/10/1048/104857/10485731_980x1200_0.jpg',
'https://img1.gtimg.com/10/1048/104857/10485726_980x1200_0.jpg',
'https://img1.gtimg.com/10/1048/104857/10485729_980x1200_0.jpg'
]
}, function(res) {
console.log(res.err_msg)
})
代码1-1是一个调用微信原生组件浏览图片的JS API
,相比于额外引入一个JS
图片预览组件库,这种调用方式显得非常简洁和高效。
实际上,微信官方是没有对外暴露过如此调用的,此类 API
最初是提供给腾讯内部一些业务使用,很多外部开发者发现了之后,依葫芦画瓢地使用了,逐渐成为微信中网页的事实标准。2015年初,微信发布了一整套网页开发工具包,称之为 JS-SDK
,开放了拍摄、录音、语音识别、二维码、地图、支付、分享、卡券等几十个API
。给所有的 Web 开发者打开了一扇全新的窗户,让所有开发者都可以使用到微信的原生能力,去完成一些之前做不到或者难以做到的事情。
同样是调用原生的浏览图片,调用方式如代码清单1-2所示。
代码清单1-2 使用 JS-SDK
调用图片预览组件
wx.previewImage({
current: 'https://img1.gtimg.com/10/1048/104857/10485726_980x1200_0.jpg',
urls: [ // 所有图片的URL列表,数组格式
'https://img1.gtimg.com/10/1048/104857/10485731_980x1200_0.jpg',
'https://img1.gtimg.com/10/1048/104857/10485726_980x1200_0.jpg',
'https://img1.gtimg.com/10/1048/104857/10485729_980x1200_0.jpg'
],
success: function(res) {
console.log(res)
}
})
JS-SDK
是对之前的 WeixinJSBridge
的一个包装,以及新能力的释放,并且由对内开放转为了对所有开发者开放,在很短的时间内获得了极大的关注。从数据监控来看,绝大部分在微信内传播的移动网页都使用到了相关的接口。
JS-SDK
解决了移动网页能力不足的问题,通过暴露微信的接口使得 Web 开发者能够拥有更多的能力,然而在更多的能力之外,JS-SDK 的模式并没有解决使用移动网页遇到的体验不良的问题。用户在访问网页的时候,在浏览器开始显示之前都会有一个的白屏过程,在移动端,受限于设备性能和网络速度,白屏会更加明显。我们团队把很多技术精力放置在如何帮助平台上的 Web 开发者解决这个问题。因此我们设计了一个 JS-SDK
的增强版本,其中有一个重要的功能,称之为“微信 Web 资源离线存储”。
以下文字引用自内部的文档(没有最终对外开放):
微信 Web 资源离线存储是面向 Web 开发者提供的基于微信内的 Web 加速方案。通过使用微信离线存储,Web 开发者可借助微信提供的资源存储能力,直接从微信本地加载 Web 资源而不需要再从服务端拉取,从而减少网页加载时间,为微信用户提供更优质的网页浏览体验。每个公众号下所有 Web App 累计最多可缓存 5M 的资源。
这个设计有点类似 HTML5 的 Application Cache
,但在设计上规避了一些 Application Cache
的不足。
在内部测试中,我们发现 离线存储 能够解决一些问题,但对于一些复杂的页面依然会有白屏问题,例如页面加载了大量的 CSS 或者是 JavaScript 文件。除了白屏,影响 Web 体验的问题还有缺少操作的反馈,主要表现在两个方面:页面切换的生硬和点击的迟滞感。
微信面临的问题是如何设计一个比较好的系统,使得所有开发者在微信中都能获得比较好的体验。这个问题是之前的 JS-SDK
所处理不了的,需要一个全新的系统来完成,它需要使得所有的开发者都能做到:
- 快速的加载
- 更强大的能力
- 原生的体验
- 易用且安全的微信数据开放
- 高效和简单的开发
这就是小程序的由来。
小程序与普通网页开发的区别
小程序的主要开发语言是 JavaScript ,小程序的开发同普通的网页开发相比有很大的相似性。对于前端开发者而言,从网页开发迁移到小程序的开发成本并不高,但是二者还是有些许区别的。
网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。网页开发者可以使用到各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作。而如上文所述,小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的 DOM API 和 BOM API。这一区别导致了前端开发非常熟悉的一些库,例如 jQuery、 Zepto 等,在小程序中是无法运行的。同时 JSCore 的环境同 NodeJS 环境也是不尽相同,所以一些 NPM 的包在小程序中也是无法运行的。
网页开发者需要面对的环境是各式各样的浏览器,PC 端需要面对 IE、Chrome、QQ 浏览器等,在移动端需要面对 Safari 、Chrome 以及 iOS、Android 系统中的各式 WebView 。而小程序开发过程中需要面对的是两大操作系统 iOS 和 Android 的微信客户端,以及用于辅助开发的小程序开发者工具,小程序中三大运行环境也是有所区别的,如表1-1所示。
表1-1 小程序的运行环境
运行环境 | 逻辑层 | 渲染层 |
---|---|---|
iOS | JavaScriptCore | WKWebView |
安卓 | V8 | chromium定制内核 |
小程序开发者工具 | NWJS | Chrome WebView |
网页开发者在开发网页的时候,只需要使用到浏览器,并且搭配上一些辅助工具或者编辑器即可。小程序的开发则有所不同,需要经过申请小程序帐号、安装小程序开发者工具、配置项目等等过程方可完成。
微信小程序 开始
开始
开发小程序的第一步,你需要拥有一个小程序帐号,通过这个帐号你就可以管理你的小程序。
跟随这个教程,开始你的小程序之旅吧!
申请帐号
进入小程序注册页 根据指引填写信息和提交相应的资料,就可以拥有自己的小程序帐号。
在这个小程序管理平台,你可以管理你的小程序的权限,查看数据报表,发布小程序等操作。
登录 小程序后台 ,我们可以在菜单 “开发”-“开发设置” 看到小程序的 AppID 了 。
小程序的 AppID 相当于小程序平台的一个身份证,后续你会在很多地方要用到 AppID (注意这里要区别于服务号或订阅号的 AppID)。
有了小程序帐号之后,我们需要一个工具来开发小程序。
安装开发工具
前往 开发者工具下载页面 ,根据自己的操作系统下载对应的安装包进行安装,有关开发者工具更详细的介绍可以查看 《开发者工具介绍》 。
打开小程序开发者工具,用微信扫码登录开发者工具,准备开发你的第一个小程序吧!
你的第一个小程序
新建项目选择小程序项目,选择代码存放的硬盘路径,填入刚刚申请到的小程序的 AppID,给你的项目起一个好听的名字,勾选 "不使用云服务" (注意: 你要选择一个空的目录才可以创建项目),点击新建,你就得到了你的第一个小程序了,点击顶部菜单编译就可以在微信开发者工具中预览你的第一个小程序。
接下来我们来预览一下这个小程序的效果。
编译预览
点击工具上的编译按钮,可以在工具的左侧模拟器界面看到这个小程序的表现,也可以点击预览按钮,通过微信的扫一扫在手机上体验你的第一个小程序。
微信小程序 小程序代码构成
小程序代码构成
在上一章中,我们通过开发者工具快速创建了一个 QuickStart 项目。你可以留意到这个项目里边生成了不同类型的文件:
- .json 后缀的 JSON 配置文件
- .wxml 后缀的 WXML 模板文件
- .wxss 后缀的 WXSS 样式文件
- .js 后缀的 JS 脚本逻辑文件
接下来我们分别看看这4种文件的作用。
JSON 配置
JSON 是一种数据格式,并不是编程语言,在小程序中,JSON扮演的静态配置的角色。
我们可以看到在项目的根目录有一个 app.json 和 project.config.json,此外在 pages/logs 目录下还有一个 logs.json,我们依次来说明一下它们的用途。
小程序配置 app.json
app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。QuickStart 项目里边的 app.json 配置内容如下:
{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
我们简单说一下这个配置各个项的含义:
- pages字段 —— 用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。
- window字段 —— 定义小程序所有页面的顶部背景颜色,文字颜色定义等。
其他配置项细节可以参考文档 小程序的配置 app.json 。
工具配置 project.config.json
通常大家在使用一个工具的时候,都会针对各自喜好做一些个性化配置,例如界面颜色、编译配置等等,当你换了另外一台电脑重新安装工具的时候,你还要重新配置。
考虑到这点,小程序开发者工具在每个项目的根目录都会生成一个 project.config.json,你在工具上做的任何配置都会写入到这个文件,当你重新安装工具或者换电脑工作时,你只要载入同一个项目的代码包,开发者工具就自动会帮你恢复到当时你开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。
其他配置项细节可以参考文档 开发者工具的配置 。
页面配置 page.json
这里的 page.json 其实用来表示 pages/logs 目录下的 logs.json 这类和小程序页面相关的配置。
如果你整个小程序的风格是蓝色调,那么你可以在 app.json 里边声明顶部颜色是蓝色即可。实际情况可能不是这样,可能你小程序里边的每个页面都有不一样的色调来区分不同功能模块,因此我们提供了 page.json,让开发者可以独立定义每个页面的一些属性,例如刚刚说的顶部颜色、是否允许下拉刷新等等。
其他配置项细节可以参考文档 页面配置 。
JSON 语法
这里说一下小程序里JSON配置的一些注意事项。
JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据。JSON的Key必须包裹在一个双引号中,在实践中,编写 JSON 的时候,忘了给 Key 值加双引号或者是把双引号写成单引号是常见错误。
JSON的值只能是以下几种数据格式,其他任何格式都会触发报错,例如 JavaScript 中的 undefined。
- 数字,包含浮点数和整数
- 字符串,需要包裹在双引号中
- Bool值,true 或者 false
- 数组,需要包裹在方括号中 []
- 对象,需要包裹在大括号中 {}
- Null
还需要注意的是 JSON 文件中无法使用注释,试图添加注释将会引发报错。
WXML 模板
从事过网页编程的人知道,网页编程采用的是 HTML + CSS + JS 这样的组合,其中 HTML 是用来描述当前这个页面的结构,CSS 用来描述页面的样子,JS 通常是用来处理这个页面和用户的交互。
同样道理,在小程序中也有同样的角色,其中 WXML 充当的就是类似 HTML 的角色。打开 pages/index/index.wxml,你会看到以下的内容:
<view class="container">
<view class="userinfo">
<button wx:if="{{!hasUserInfo && canIUse}}"> 获取头像昵称 </button>
<block wx:else>
<image src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
和 HTML 非常相似,WXML 由标签、属性等等构成。但是也有很多不一样的地方,我们来一一阐述一下:
- 标签名字有点不一样往往写 HTML 的时候,经常会用到的标签是 div, p, span,开发者在写一个页面的时候可以根据这些基础的标签组合出不一样的组件,例如日历、弹窗等等。换个思路,既然大家都需要这些组件,为什么我们不能把这些常用的组件包装起来,大大提高我们的开发效率。从上边的例子可以看到,小程序的 WXML 用的标签是 view, button, text 等等,这些标签就是小程序给开发者包装好的基本能力,我们还提供了地图、视频、音频等等组件能力。更多详细的组件讲述参考下个章节 小程序的能力
- 多了一些 wx:if 这样的属性以及 {{ }} 这样的表达式在网页的一般开发流程中,我们通常会通过 JS 操作 DOM (对应 HTML 的描述产生的树),以引起界面的一些变化响应用户的行为。例如,用户点击某个按钮的时候,JS 会记录一些状态到 JS 变量里边,同时通过 DOM API 操控 DOM 的属性或者行为,进而引起界面一些变化。当项目越来越大的时候,你的代码会充斥着非常多的界面交互逻辑和程序的各种状态变量,显然这不是一个很好的开发模式,因此就有了 MVVM 的开发模式(例如 React, Vue),提倡把渲染和逻辑分离。简单来说就是不要再让 JS 直接操控 DOM,JS 只需要管理状态即可,然后再通过一种模板语法来描述状态和界面结构的关系即可。小程序的框架也是用到了这个思路,如果你需要把一个 Hello World 的字符串显示在界面上。WXML 是这么写 :<text>{{msg}}</text> JS 只需要管理状态即可:this.setData({ msg: "Hello World" }) 通过 {{ }} 的语法把一个变量绑定到界面上,我们称为数据绑定。仅仅通过数据绑定还不够完整的描述状态和界面的关系,还需要 if/else, for等控制能力,在小程序里边,这些控制能力都用 wx: 开头的属性来表达。
更详细的文档可以参考 WXML
WXSS 样式
WXSS 具有 CSS 大部分的特性,小程序在 WXSS 也做了一些扩充和修改。
- 新增了尺寸单位。在写 CSS 样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS 在底层支持新的尺寸单位 rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差。
- 提供了全局的样式和局部样式。和前边 app.json, page.json 的概念相同,你可以写一个 app.wxss 作为全局样式,会作用于当前小程序的所有页面,局部页面样式 page.wxss 仅对当前页面生效。
- 此外 WXSS 仅支持部分 CSS 选择器
更详细的文档可以参考 WXSS 。
JS 逻辑交互
一个服务仅仅只有界面展示是不够的,还需要和用户做交互:响应用户的点击、获取用户的位置等等。在小程序里边,我们就通过编写 JS 脚本文件来处理用户的操作。
<view>{{ msg }}</view>
<button bindtap="clickMe">点击我</button>
点击 button 按钮的时候,我们希望把界面上 msg 显示成 "Hello World",于是我们在 button 上声明一个属性: bindtap ,在 JS 文件里边声明了 clickMe 方法来响应这次点击操作:
Page({
clickMe: function() {
this.setData({ msg: "Hello World" })
}
})
响应用户的操作就是这么简单,更详细的事件可以参考文档 WXML - 事件 。
此外你还可以在 JS 中调用小程序提供的丰富的 API,利用这些 API 可以很方便的调起微信提供的能力,例如获取用户信息、本地存储、微信支付等。在前边的 QuickStart 例子中,在 pages/index/index.js 就调用了 wx.getUserInfo 获取微信用户的头像和昵称,最后通过 setData 把获取到的信息显示到界面上。更多 API 可以参考文档 小程序的API 。
微信小程序 小程序宿主环境
小程序宿主环境
我们称微信客户端给小程序所提供的环境为宿主环境。小程序借助宿主环境提供的能力,可以完成许多普通网页无法完成的功能。
上一章中我们把小程序涉及到的文件类型阐述了一遍,我们结合 QuickStart 这个项目来讲一下这些文件是怎么配合工作的。
渲染层和逻辑层
首先,我们来简单了解下小程序的运行环境。小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(下文中也会采用Native来代指微信客户端)做中转,逻辑层发送网络请求也经由Native转发,小程序的通信模型下图所示。
有关渲染层和逻辑层的详细文档参考 小程序框架 。
程序与页面
微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地。
紧接着通过 app.json 的 pages 字段就可以知道你当前小程序的所有页面路径:
{
"pages":[
"pages/index/index",
"pages/logs/logs"
]
}
这个配置说明在 QuickStart 项目定义了两个页面,分别位于 pages/index/index 和 pages/logs/logs。而写在 pages 字段的第一个页面就是这个小程序的首页(打开小程序看到的第一个页面)。
于是微信客户端就把首页的代码装载进来,通过小程序底层的一些机制,就可以渲染出这个首页。
小程序启动之后,在 app.js 定义的 App 实例的 onLaunch 回调会被执行:
App({
onLaunch: function () {
// 小程序启动之后 触发
}
})
整个小程序只有一个 App 实例,是全部页面共享的,更多的事件回调参考文档 注册程序 App 。
接下来我们简单看看小程序的一个页面是怎么写的。
你可以观察到 pages/logs/logs 下其实是包括了4种文件的,微信客户端会先根据 logs.json 配置生成一个界面,顶部的颜色和文字你都可以在这个 json 文件里边定义好。紧接着客户端就会装载这个页面的 WXML 结构和 WXSS 样式。最后客户端会装载 logs.js,你可以看到 logs.js 的大体内容就是:
Page({
data: { // 参与页面渲染的数据
logs: []
},
onLoad: function () {
// 页面渲染后 执行
}
})
Page 是一个页面构造器,这个构造器就生成了一个页面。在生成页面的时候,小程序框架会把 data 数据和 index.wxml 一起渲染出最终的结构,于是就得到了你看到的小程序的样子。
在渲染完界面之后,页面实例就会收到一个 onLoad 的回调,你可以在这个回调处理你的逻辑。
有关于 Page 构造器更多详细的文档参考 注册页面 Page 。
组件
小程序提供了丰富的基础组件给开发者,开发者可以像搭积木一样,组合各种组件拼合成自己的小程序。
就像 HTML 的 div, p 等标签一样,在小程序里边,你只需要在 WXML 写上对应的组件标签名字就可以把该组件显示在界面上,例如,你需要在界面上显示地图,你只需要这样写即可:
<map></map>
使用组件的时候,还可以通过属性传递值给组件,让组件可以以不同的状态去展现,例如,我们希望地图一开始的中心的经纬度是广州,那么你需要声明地图的 longitude(中心经度) 和 latitude(中心纬度)两个属性:
<map longitude="广州经度" latitude="广州纬度"></map>
组件的内部行为也会通过事件的形式让开发者可以感知,例如用户点击了地图上的某个标记,你可以在 js 编写 markertap 函数来处理:
<map bindmarkertap="markertap" longitude="广州经度" latitude="广州纬度"></map>
当然你也可以通过 style 或者 class 来控制组件的外层样式,以便适应你的界面宽度高度等等。
API
为了让开发者可以很方便的调起微信提供的能力,例如获取用户信息、微信支付等等,小程序提供了很多 API 给开发者去使用。
要获取用户的地理位置时,只需要:
wx.getLocation({
type: 'wgs84',
success: (res) => {
var latitude = res.latitude // 纬度
var longitude = res.longitude // 经度
}
})
调用微信扫一扫能力,只需要:
wx.scanCode({
success: (res) => {
console.log(res)
}
})
需要注意的是:多数 API 的回调都是异步,你需要处理好代码逻辑的异步问题。
更多的 API 能力见 小程序的API。
微信小程序 小程序协同工作和发布
小程序协同工作和发布
在中大型的公司里,人员的分工非常仔细,一般会有不同岗位角色的员工同时参与同一个小程序项目。为此,小程序平台设计了不同的权限管理使得项目管理者可以更加高效管理整个团队的协同工作。
以往我们在开发完网页之后,需要把网页的代码和资源放在服务器上,让用户通过互联网来访问。在小程序的平台里,开发者完成开发之后,需要在开发者工具提交小程序的代码包,然后在小程序后台发布小程序,用户可以通过搜索或者其它入口来进入该小程序。
在这一章我们会把团队的协同工作的注意事项和小程序发布前后涉及的概念和流程做一些介绍。
协同工作
如果你只是一个人开发小程序,可以暂时先跳过这部分,如果是一个团队需要先了解一些概念。
多数情况下,一个团队多人同时参与同一个小程序项目,每个角色所承担的工作或者权限不一样,中大公司的分工更为仔细。为了更形象的表达团队不同角色的关系以及权限的管理,我们通过虚拟一个项目成员组织结构来描述日常如何协同合作完成一个小程序的发布,组织关系如图5-1所示。
图5-1 虚拟小程序项目组
项目管理成员负责统筹整个项目的进展和风险、把控小程序对外发布的节奏,产品组提出需求,设计组与产品讨论并对需求进行抽象,设计出可视化流程与图形,输出设计方案。开发组依据设计方案,进行程序代码的编写,代码编写完成后,产品组与设计组体验小程序的整体流程,测试组编写测试用例并对小程序进行各种边界测试。项目一般的成员构成与工作流程如图5-2所示。
图5-2 提需求到发布小程序的流程
小程序成员管理
小程序成员管理包括对小程序项目成员及体验成员的管理。
- 项目成员:表示参与小程序开发、运营的成员,可登录小程序管理后台,包括运营者、开发者及数据分析者。管理员可在“成员管理”中添加、删除项目成员,并设置项目成员的角色。
- 体验成员:表示参与小程序内测体验的成员,可使用体验版小程序,但不属于项目成员。管理员及项目成员均可添加、删除体验成员。
不同项目成员拥有不同的权限,从而保证小程序开发安全有序。
权限 | 运营者 | 开发者 | 数据分析者 |
---|---|---|---|
开发者权限 | √ | ||
体验者权限 | √ | √ | √ |
登录 | √ | √ | √ |
数据分析 | √ | ||
微信支付 | √ | ||
推广 | √ | ||
开发管理 | √ | ||
开发设置 | √ | ||
暂停服务 | √ | ||
解除关联公众号 | √ | ||
腾讯云管理 | √ | ||
小程序插件 | √ | ||
游戏运营管理 | √ |
各权限功能说明
- 开发者权限:可使用小程序开发者工具及开发版小程序进行开发
- 体验者权限:可使用体验版小程序
- 登录:可登录小程序管理后台,无需管理员确认
- 数据分析:使用小程序统计模块功能查看小程序数据
- 微信支付:使用小程序微信支付(虚拟支付)模块
- 推广:使用小程序流量主、广告主模块
- 开发管理:小程序提交审核、发布、回退
- 开发设置:设置小程序服务器域名、消息推送及扫描普通链接二维码打开小程序
- 暂停服务设置:暂停小程序线上服务
- 解除关联公众号:可解绑小程序已关联的公众号
- 小程序插件:可进行小程序插件开发管理和设置
- 游戏运营管理:可使用小游戏管理后台的素材管理、游戏圈管理等功能
需要留意,项目管理者控制整个小程序的发布、回退、下架等敏感操作,不应把敏感操作的权限分配给不相关人员
小程序的版本
一般的软件开发流程,开发者编写代码自测开发版程序,直到程序达到一个稳定可体验的状态时,开发者会把这个体验版本给到产品经理和测试人员进行体验测试,最后修复完程序的Bug后发布供外部用户正式使用。小程序的版本根据这个流程设计了小程序版本的概念,如表5-3所示。
表5-3 小程序的版本
权限 | 说明 |
---|---|
开发版本 | 使用开发者工具,可将代码上传到开发版本中。 开发版本只保留每人最新的一份上传的代码。 点击提交审核,可将代码提交审核。开发版本可删除,不影响线上版本和审核中版本的代码。 |
体验版本 | 可以选择某个开发版本作为体验版,并且选取一份体验版。 |
审核中版本 | 只能有一份代码处于审核中。有审核结果后可以发布到线上,也可直接重新提交审核,覆盖原审核版本。 |
线上版本 | 线上所有用户使用的代码版本,该版本代码在新版本代码发布后被覆盖更新。 |
考虑到项目是协同开发的模式,一个小程序可能同时由多个开发者进行开发,往往开发者在小程序开发者工具上编写完代码后需要到手机进行真机体验,所以每个开发者拥有自己对应的一个开发版本。因为处于开发中的版本是不稳定的,开发者随时会修改代码覆盖开发版,为了让测试和产品经理有一个完整稳定的版本可以体验测试,小程序平台允许把其中一个开发版本设置成体验版,因此建议在项目开发阶段特殊分配一个开发角色,用于上传稳定可供体验测试的代码,并把他上传的开发版本设置成体验版。
发布上线
一个小程序从开发完到上线一般要经过 预览-> 上传代码 -> 提交审核 -> 发布等步骤。
预览
使用开发者工具可以预览小程序,帮助开发者检查小程序在移动客户端上的真实表现。
点击开发者工具顶部操作栏的预览按钮,开发者工具会自动打包当前项目,并上传小程序代码至微信的服务器,成功之后会在界面上显示一个二维码。使用当前小程序开发者的微信扫码即可看到小程序在手机客户端上的真实表现。
上传代码
同预览不同,上传代码是用于提交体验或者审核使用的。
点击开发者工具顶部操作栏的上传按钮,填写版本号以及项目备注,需要注意的是,这里版本号以及项目备注是为了方便管理员检查版本使用的,开发者可以根据自己的实际要求来填写这两个字段。
上传成功之后,登录小程序管理后台 - 开发管理 - 开发版本 就可以找到刚提交上传的版本了。
可以将这个版本设置 体验版 或者是 提交审核
提交审核
为了保证小程序的质量,以及符合相关的规范,小程序的发布是需要经过审核的。
在开发者工具中上传了小程序代码之后,登录 小程序管理后台 - 开发管理 - 开发版本 找到提交上传的版本。
在开发版本的列表中,点击 提交审核 按照页面提示,填写相关的信息,即可以将小程序提交审核。
需要注意的是,请开发者严格测试了版本之后,再提交审核, 过多的审核不通过,可能会影响后续的时间。
发布
审核通过之后,管理员的微信中会收到小程序通过审核的通知,此时登录 小程序管理后台 - 开发管理 - 审核版本中可以看到通过审核的版本。
点击发布后,即可发布小程序。小程序提供了两种发布模式:全量发布和分阶段发布。全量发布是指当点击发布之后,所有用户访问小程序时都会使用当前最新的发布版本。分阶段发布是指分不同时间段来控制部分用户使用最新的发布版本,分阶段发布我们也称为灰度发布。一般来说,普通小程序发布时采用全量发布即可,当小程序承载的功能越来越多,使用的用户数越来越多时,采用分阶段发布是一个非常好的控制风险的办法。
小程序码
很多场景下用户会通过扫码快速进入一个小程序,在小程序设计的初期,小程序平台提供的二维码的形式。我们发现用户在扫一个二维码时,他并不知道当前这次扫码会出现什么样的服务,因为二维码的背后有可能是公众号、小程序、网页服务、支付页面、添加好友等不同的服务。为了让用户在扫码之前就有一个明确的预期,因此微信设计了小程序码,如图5-3所示。
图5-3 “小程序数据助手”的小程序码
小程序码在样式上更具辨识度和视觉冲击力,相对于二维码来说,小程序主题的品牌形象更加清晰明显,可以帮助开发者更好地推广小程序。在发布小程序之后,小程序管理平台会提供对应的小程序码的预览和下载,开发者可以自行下载用于线上和线下的小程序服务推广。
运营数据
有两种方式可以方便的看到小程序的运营数据
方法一:
登录 小程序管理后台 - 数据分析
点击相应的 tab 可以看到相关的数据。
方法二:
使用小程序数据助手,在微信中方便的查看运营数据
目录结构
小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。
一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:
文件 | 必需 | 作用 |
---|---|---|
app.js | 是 | 小程序逻辑 |
app.json | 是 | 小程序公共配置 |
app.wxss | 否 | 小程序公共样式表 |
一个小程序页面由四个文件组成,分别是:
文件类型 | 必需 | 作用 |
---|---|---|
js | 是 | 页面逻辑 |
wxml | 是 | 页面结构 |
json | 否 | 页面配置 |
wxss | 否 | 页面样式表 |
注意:为了方便开发者减少配置项,描述页面的四个文件必须具有相同的路径与文件名。
允许上传的文件
在项目目录中,以下文件会经过编译,因此上传之后无法直接访问到:.js、app.json、.wxml、*.wxss(其中 wxml 和 wxss 文件仅针对在 app.json 中配置了的页面)。除此之外,只有后缀名在白名单内的文件可以被上传,不在白名单列表内文件在开发工具能被访问到,但无法被上传。具体白名单列表如下:
- wxs
- png
- jpg
- jpeg
- gif
- svg
- json
- cer
- mp3
- aac
- m4a
- mp4
- wav
- ogg
- silk
微信小程序 全局配置
全局配置
小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
完整配置项说明请参考小程序全局配置
以下是一个包含了部分常用配置选项的 app.json :
{
"pages": [
"pages/index/index",
"pages/logs/index"
],
"window": {
"navigationBarTitleText": "Demo"
},
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
}, {
"pagePath": "pages/logs/index",
"text": "日志"
}]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000
},
"debug": true,
"navigateToMiniProgramAppIdList": [
"wxe5f52902cf4de896"
]
}
完整配置项说明请参考小程序全局配置
微信小程序 页面配置
页面配置
每一个小程序页面也可以使用同名 .json 文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json 的 window 中相同的配置项。
完整配置项说明请参考小程序页面配置
例如:
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
}
微信小程序 sitemap配置
微信现已开放小程序内搜索,开发者可以通过 sitemap.json 配置,或者管理后台页面收录开关来配置其小程序页面是否允许微信索引。当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索词条触发该索引时,小程序的页面将可能展示在搜索结果中。 爬虫访问小程序内页面时,会携带特定的 user-agent:mpcrawler 及场景值:1129。需要注意的是,若小程序爬虫发现的页面数据和真实用户的呈现不一致,那么该页面将不会进入索引中。
具体配置说明
- 页面收录设置:可对整个小程序的索引进行关闭,小程序管理后台-功能-页面内容接入-页面收录开关;详情
- sitemap 配置:可对特定页面的索引进行关闭
sitemap 配置
小程序根目录下的 sitemap.json 文件用来配置小程序及其页面是否允许被微信索引。
完整配置项说明请参考小程序 sitemap 配置
例1:
{
"rules":[{
"action": "allow",
"page": "*"
}]
}
所有页面都会被微信索引(默认情况)
例2:
{
"rules":[{
"action": "disallow",
"page": "path/to/page"
}]
}
配置 path/to/page 页面不被索引,其余页面允许被索引
例3:
{
"rules":[{
"action": "allow",
"page": "path/to/page"
}, {
"action": "disallow",
"page": "*"
}]
}
配置 path/to/page 页面被索引,其余页面不被索引
例4:
{
"rules":[{
"action": "allow",
"page": "path/to/page",
"params": ["a", "b"],
"matching": "inclusive"
}, {
"action": "allow",
"page": "*"
}]
}
包含 a 和 b 参数的 path/to/page 页面会被微信优先索引,其他页面都会被索引,例如:
- path/to/page?a=1&b=2 => 优先被索引
- path/to/page?a=1&b=2&c=3 => 优先被索引
- path/to/page => 被索引
- path/to/page?a=1 => 被索引
- 其他页面都会被索引
例5:
{
"rules":[{
"action": "allow",
"page": "path/to/page",
"params": ["a", "b"],
"matching": "inclusive"
}, {
"action": "disallow",
"page": "*"
}, {
"action": "allow",
"page": "*"
}]
}
- path/to/page?a=1&b=2 => 优先被索引
- path/to/page?a=1&b=2&c=3 => 优先被索引
- path/to/page => 不被索引
- path/to/page?a=1 => 不被索引
- 其他页面由于命中第二条规则,所以不会被索引
- 由于优先级的问题,第三条规则是没有意义的
注:没有 sitemap.json 则默认所有页面都能被索引
注:{"action": "allow", "page": "*"} 是优先级最低的默认规则,未显式指明 "disallow" 的都默认被索引
如何调试
当在小程序项目中设置了 sitemap 的配置文件(默认为 sitemap.json)时,便可在开发者工具控制台上显示当前页面是否被索引的调试信息( 最新版本的开发者工具支持索引提示)
注:sitemap 的索引提示是默认开启的,如需要关闭 sitemap 的索引提示,可在小程序项目配置文件 project.config.json 的 setting 中配置字段 checkSiteMap 为 false
微信小程序 注册小程序
注册小程序
每个小程序都需要在 app.js 中调用 App 方法注册小程序实例,绑定生命周期回调函数、错误监听和页面不存在监听函数等。
详细的参数含义和使用请参考 App 参考文档 。
// app.js
App({
onLaunch (options) {
// Do something initial when launch.
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
},
globalData: 'I am global data'
})
整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 实例,获取App上的数据或调用开发者注册在 App 上的函数。
// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data
微信小程序 小程序APP
App(Object object)
注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。
App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。
参数
Object object
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
onLaunch | function | 否 | 生命周期回调——监听小程序初始化。 | ||
onShow | function | 否 | 生命周期回调——监听小程序启动或切前台。 | ||
onHide | function | 否 | 生命周期回调——监听小程序切后台。 | ||
onError | function | 否 | 错误监听函数。 | ||
onPageNotFound | function | 否 | 页面不存在监听函数。 | 1.9.90 | |
onUnhandledRejection | function | 否 | 未处理的 Promise 拒绝事件监听函数。 | 2.10.0 | |
onThemeChange | function | 否 | 监听系统主题变化 | 2.11.0 | |
其他 | any | 否 | 开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问 |
关于小程序前后台的定义和小程序的运行机制,请参考运行机制章节。
示例代码
App({
onLaunch (options) {
// Do something initial when launch.
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
},
globalData: 'I am global data'
})
onLaunch(Object object)
小程序初始化完成时触发,全局只触发一次。参数也可以使用 wx.getLaunchOptionsSync 获取。
参数:与 wx.getLaunchOptionsSync 一致
onShow(Object object)
小程序启动,或从后台进入前台显示时触发。也可以使用 wx.onAppShow 绑定监听。
参数:与 wx.onAppShow 一致
onHide()
小程序从前台进入后台时触发。也可以使用 wx.onAppHide 绑定监听。
onError(String error)
小程序发生脚本错误或 API 调用报错时触发。也可以使用 wx.onError 绑定监听。
参数:与 wx.onError 一致
onPageNotFound(Object object)
基础库 1.9.90 开始支持,低版本需做兼容处理。
小程序要打开的页面不存在时触发。也可以使用 wx.onPageNotFound 绑定监听。注意事项请参考 wx.onPageNotFound。
参数:与 wx.onPageNotFound 一致
示例代码:
App({
onPageNotFound(res) {
wx.redirectTo({
url: 'pages/...'
}) // 如果是 tabbar 页面,请使用 wx.switchTab
}
})
onUnhandledRejection(Object object)
基础库 2.10.0 开始支持,低版本需做兼容处理。
小程序有未处理的 Promise 拒绝时触发。也可以使用 wx.onUnhandledRejection 绑定监听。注意事项请参考 wx.onUnhandledRejection。
参数:与 wx.onUnhandledRejection 一致
onThemeChange(Object object)
基础库 2.11.0 开始支持,低版本需做兼容处理。
系统切换主题时触发。也可以使用 wx.onThemeChange 绑定监听。
参数:与 wx.onThemeChange 一致
AppObject getApp(Object object)
获取到小程序全局唯一的 App 实例。
参数
Object object
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
allowDefault | boolean | false | 否 | 在 App 未定义时返回默认实现。当App被调用时,默认实现中定义的属性会被覆盖合并到App中。一般用于独立分包 |
2.2.4 |
示例代码
// other.js
var appInstance = getApp()
console.log(appInstance.globalData) // I am global data
注意
- 不要在定义于 App() 内的函数中,或调用 App 前调用 getApp() ,使用 this 就可以拿到 app 实例。
- 通过 getApp() 获取实例之后,不要私自调用生命周期函数。
微信小程序 注册页面
注册页面
对于小程序中的每个页面,都需要在页面对应的 js 文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。
使用 Page 构造器注册页面
简单的页面可以使用 Page() 进行构造。
代码示例:
//index.js
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
// 页面创建时执行
},
onShow: function() {
// 页面出现在前台时执行
},
onReady: function() {
// 页面首次渲染完毕时执行
},
onHide: function() {
// 页面从前台变为后台时执行
},
onUnload: function() {
// 页面销毁时执行
},
onPullDownRefresh: function() {
// 触发下拉刷新时执行
},
onReachBottom: function() {
// 页面触底时执行
},
onShareAppMessage: function () {
// 页面被用户分享时执行
},
onPageScroll: function() {
// 页面滚动时执行
},
onResize: function() {
// 页面尺寸变化时执行
},
onTabItemTap(item) {
// tab 点击时执行
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// 事件响应函数
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
// 自由数据
customData: {
hi: 'MINA'
}
})
详细的参数含义和使用请参考 Page 参考文档 。
在页面中使用 behaviors
基础库 2.9.2 开始支持,低版本需做兼容处理。
页面可以引用 behaviors 。 behaviors 可以用来让多个页面有相同的数据字段和方法。
// my-behavior.js
module.exports = Behavior({
data: {
sharedText: 'This is a piece of data shared between pages.'
},
methods: {
sharedMethod: function() {
this.data.sharedText === 'This is a piece of data shared between pages.'
}
}
})
// page-a.js
var myBehavior = require('./my-behavior.js')
Page({
behaviors: [myBehavior],
onLoad: function() {
this.data.sharedText === 'This is a piece of data shared between pages.'
}
})
具体用法参见 behaviors 。
使用 Component 构造器构造页面
基础库 1.6.3 开始支持,低版本需做兼容处理。
Page 构造器适用于简单的页面。但对于复杂的页面, Page 构造器可能并不好用。
此时,可以使用 Component 构造器来构造页面。 Component 构造器的主要区别是:方法需要放在 methods: { } 里面。
代码示例:
Component({
data: {
text: "This is page data."
},
methods: {
onLoad: function(options) {
// 页面创建时执行
},
onPullDownRefresh: function() {
// 下拉刷新时执行
},
// 事件响应函数
viewTap: function() {
// ...
}
}
})
这种创建方式非常类似于 自定义组件 ,可以像自定义组件一样使用 behaviors 等高级特性。
微信小程序 页面
Page(Object object)
注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。
参数
Object object
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
data | Object | 页面的初始数据 | ||
onLoad | function | 生命周期回调—监听页面加载 | ||
onShow | function | 生命周期回调—监听页面显示 | ||
onReady | function | 生命周期回调—监听页面初次渲染完成 | ||
onHide | function | 生命周期回调—监听页面隐藏 | ||
onUnload | function | 生命周期回调—监听页面卸载 | ||
onPullDownRefresh | function | 监听用户下拉动作 | ||
onReachBottom | function | 页面上拉触底事件的处理函数 | ||
onShareAppMessage | function | 用户点击右上角转发 | ||
onShareTimeline | function | 用户点击右上角转发到朋友圈 | ||
onAddToFavorites | function | 用户点击右上角收藏 | ||
onPageScroll | function | 页面滚动触发事件的处理函数 | ||
onResize | function | 页面尺寸改变时触发,详见 响应显示区域变化 | ||
onTabItemTap | function | 当前是 tab 页时,点击 tab 时触发 | ||
其他 | any | 开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问 |
示例代码
//index.js
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
// Do some initialize when page load.
},
onShow: function() {
// Do something when page show.
},
onReady: function() {
// Do something when page ready.
},
onHide: function() {
// Do something when page hide.
},
onUnload: function() {
// Do something when page close.
},
onPullDownRefresh: function() {
// Do something when pull down.
},
onReachBottom: function() {
// Do something when page reach bottom.
},
onShareAppMessage: function () {
// return custom share data when user share.
},
onPageScroll: function() {
// Do something when page scroll
},
onResize: function() {
// Do something when page resize
},
onTabItemTap(item) {
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// Event handler.
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
customData: {
hi: 'MINA'
}
})
微信小程序 Component构造器
Component(Object object)
创建自定义组件,接受一个 Object 类型的参数。
参数
Object object
定义段 | 类型 | 是否必填 | 描述 | 最低版本 |
---|---|---|---|---|
properties | Object Map | 否 | 组件的对外属性,是属性名到属性设置的映射表 | |
data | Object | 否 | 组件的内部数据,和 properties 一同用于组件的模板渲染 |
|
observers | Object | 否 | 组件数据字段监听器,用于监听 properties 和 data 的变化,参见 数据监听器 | 2.6.1 |
methods | Object | 否 | 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 组件间通信与事件 | |
behaviors | String Array | 否 | 类似于mixins和traits的组件间代码复用机制,参见 behaviors | |
created | Function | 否 | 组件生命周期函数-在组件实例刚刚被创建时执行,注意此时不能调用 setData ) |
|
attached | Function | 否 | 组件生命周期函数-在组件实例进入页面节点树时执行) | |
ready | Function | 否 | 组件生命周期函数-在组件布局完成后执行) | |
moved | Function | 否 | 组件生命周期函数-在组件实例被移动到节点树另一个位置时执行) | |
detached | Function | 否 | 组件生命周期函数-在组件实例被从页面节点树移除时执行) | |
relations | Object | 否 | 组件间关系定义,参见 组件间关系 | |
externalClasses | String Array | 否 | 组件接受的外部样式类,参见 外部样式类 | |
options | Object Map | 否 | 一些选项(文档中介绍相关特性时会涉及具体的选项设置,这里暂不列举) | |
lifetimes | Object | 否 | 组件生命周期声明对象,参见 组件生命周期 | 2.2.3 |
pageLifetimes | Object | 否 | 组件所在页面的生命周期声明对象,参见 组件生命周期 | 2.2.3 |
definitionFilter | Function | 否 | 定义段过滤器,用于自定义组件扩展,参见 自定义组件扩展 | 2.2.3 |
生成的组件实例可以在组件的方法、生命周期函数和属性 observer 中通过 this 访问。组件包含一些通用属性和方法。
属性名 | 类型 | 描述 |
---|---|---|
is | String | 组件的文件路径 |
id | String | 节点id |
dataset | String | 节点dataset |
data | Object | 组件数据,包括内部数据和属性值 |
properties | Object | 组件数据,包括内部数据和属性值(与 data 一致) |
方法名 | 参数 | 描述 | 最低版本 |
---|---|---|---|
setData | Object newData |
设置data并执行视图层渲染 | |
hasBehavior | Object behavior |
检查组件是否具有 behavior (检查时会递归检查被直接或间接引入的所有behavior) |
|
triggerEvent | String name , Object detail , Object options |
触发事件,参见 组件间通信与事件 | |
createSelectorQuery | 创建一个 SelectorQuery 对象,选择器选取范围为这个组件实例内 | ||
createIntersectionObserver | 创建一个 IntersectionObserver 对象,选择器选取范围为这个组件实例内 | ||
createMediaQueryObserver | 创建一个 MediaQueryObserver 对象 | 2.11.1 | |
selectComponent | String selector |
使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象(会被 wx://component-export 影响) |
|
selectAllComponents | String selector |
使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组(会被 wx://component-export 影响) |
|
selectOwnerComponent | 选取当前组件节点所在的组件实例(即组件的引用者),返回它的组件实例对象(会被 wx://component-export 影响) |
2.8.2 | |
getRelationNodes | String relationKey |
获取这个关系所对应的所有关联节点,参见 组件间关系 | |
groupSetData | Function callback |
立刻执行 callback ,其中的多个 setData 之间不会触发界面绘制(只有某些特殊场景中需要,如用于在不同组件同时 setData 时进行界面绘制同步) |
2.4.0 |
getTabBar | 返回当前页面的 custom-tab-bar 的组件实例,详见自定义 tabBar | 2.6.2 | |
getPageId | 返回页面标识符(一个字符串),可以用来判断几个自定义组件实例是不是在同一个页面内 | 2.7.1 | |
animate | String selector , Array keyframes , Number duration , Function callback |
执行关键帧动画,详见动画 | 2.9.0 |
clearAnimation | String selector , Object options , Function callback |
清除关键帧动画,详见动画 | 2.9.0 |
代码示例:
在开发者工具中预览效果
Component({
behaviors: [],
// 属性定义(详情参见下文)
properties: {
myProperty: { // 属性名
type: String,
value: ''
},
myProperty2: String // 简化的定义方式
},
data: {}, // 私有数据,可用于模板渲染
lifetimes: {
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function () { },
moved: function () { },
detached: function () { },
},
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function () { }, // 此处attached的声明会被lifetimes字段中的声明覆盖
ready: function() { },
pageLifetimes: {
// 组件所在页面的生命周期函数
show: function () { },
hide: function () { },
resize: function () { },
},
methods: {
onMyButtonTap: function(){
this.setData({
// 更新属性和数据的方法与更新页面数据的方法类似
})
},
// 内部方法建议以下划线开头
_myPrivateMethod: function(){
// 这里将 data.A[0].B 设为 'myPrivateData'
this.setData({
'A[0].B': 'myPrivateData'
})
},
_propertyChange: function(newVal, oldVal) {
}
}
})
注意:在 properties 定义段中,属性名采用驼峰写法(propertyName);在 wxml 中,指定属性值时则对应使用连字符写法(component-tag-name property-name="attr value"),应用于数据绑定时采用驼峰写法(attr="")。
微信小程序 页面生命周期
生命周期
以下内容你不需要立马完全弄明白,不过以后它会有帮助。
下图说明了页面 Page 实例的生命周期。
微信小程序 页面路由
页面路由
在小程序中所有页面的路由全部由框架进行管理。
页面栈
框架以栈的形式维护了当前的所有页面。 当发生路由切换的时候,页面栈的表现如下:
路由方式 | 页面栈表现 |
---|---|
初始化 | 新页面入栈 |
打开新页面 | 新页面入栈 |
页面重定向 | 当前页面出栈,新页面入栈 |
页面返回 | 页面不断出栈,直到目标返回页 |
Tab 切换 | 页面全部出栈,只留下新的 Tab 页面 |
重加载 | 页面全部出栈,只留下新的页面 |
开发者可以使用 getCurrentPages()
函数获取当前页面栈。
getCurrentPages()
函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
页面栈示例:页面栈遵循先进后出的规则,当前也在最上面。
路由方式
对于路由的触发方式以及页面生命周期函数如下:
路由方式 | 触发时机 | 路由前页面 | 路由后页面 |
---|---|---|---|
初始化 | 小程序打开的第一个页面 | onLoad, onShow | |
打开新页面 | 调用 API wx.navigateTo 使用组件 <navigator open-type="navigateTo"/> |
onHide | onLoad, onShow |
页面重定向 | 调用 API wx.redirectTo 使用组件 <navigator open-type="redirectTo"/> |
onUnload | onLoad, onShow |
页面返回 | 调用 API wx.navigateBack 使用组件 <navigator open-type="navigateBack"> 用户按左上角返回按钮 |
onUnload | onShow |
Tab 切换 | 调用 API wx.switchTab 使用组件 <navigator open-type="switchTab"/> 用户切换 Tab |
各种情况请参考下表 | |
重启动 | 调用 API wx.reLaunch 使用组件 <navigator open-type="reLaunch"/> |
onUnload | onLoad, onShow |
Tab 切换对应的生命周期(以 A、B 页面为 Tabbar
页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例):
当前页面 | 路由后页面 | 触发的生命周期(按顺序) |
---|---|---|
A | A | Nothing happend |
A | B | A.onHide(), B.onLoad(), B.onShow() |
A | B(再次打开) | A.onHide(), B.onShow() |
C | A | C.onUnload(), A.onShow() |
C | B | C.onUnload(), B.onLoad(), B.onShow() |
D | B | D.onUnload(), C.onUnload(), B.onLoad(), B.onShow() |
D(从转发进入) | A | D.onUnload(), A.onLoad(), A.onShow() |
D(从转发进入) | B | D.onUnload(), B.onLoad(), B.onShow() |
Tips:
navigateTo
,redirectTo
只能打开非tabBar
页面。switchTab
只能打开tabBar
页面。reLaunch
可以打开任意页面。- 页面底部的
tabBar
由页面决定,即只要是定义为tabBar
的页面,底部都有tabBar
。 - 调用页面路由带的参数可以在目标页面的
onLoad
中获取。
微信小程序 模块化
模块化
可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。
注意:
- exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。所以更推荐开发者采用 module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。
- 小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中,或者使用小程序支持的 npm 功能。
// common.js
function sayHello(name) {
console.log(`Hello ${name} !`)
}
function sayGoodbye(name) {
console.log(`Goodbye ${name} !`)
}
module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye
在需要使用这些模块的文件中,使用 require 将公共代码引入
var common = require('common.js')
Page({
helloMINA: function() {
common.sayHello('MINA')
},
goodbyeMINA: function() {
common.sayGoodbye('MINA')
}
})
文件作用域
在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。
通过全局函数 getApp 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置,如:
// app.js
App({
globalData: 1
})
// a.js
// The localValue can only be used in file a.js.
var localValue = 'a'
// Get the app instance.
var app = getApp()
// Get the global data and change it.
app.globalData++
// b.js
// You can redefine localValue in file b.js, without interference with the localValue in a.js.
var localValue = 'b'
// If a.js it run before b.js, now the globalData shoule be 2.
console.log(getApp().globalData)
微信小程序 API
API
小程序开发框架提供丰富的微信原生 API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。详细介绍请参考 API 文档。
通常,在小程序 API 有以下几种类型:
事件监听 API
我们约定,以 on 开头的 API 用来监听某个事件是否触发,如:wx.onSocketOpen,wx.onCompassChange 等。
这类 API 接受一个回调函数作为参数,当事件触发时会调用这个回调函数,并将相关数据以参数形式传入。
代码示例
wx.onCompassChange(function (res) {
console.log(res.direction)
})
同步 API
我们约定,以 Sync 结尾的 API 都是同步 API, 如 wx.setStorageSync,wx.getSystemInfoSync 等。此外,也有一些其他的同步 API,如 wx.createWorker,wx.getBackgroundAudioManager 等,详情参见 API 文档中的说明。
同步 API 的执行结果可以通过函数返回值直接获取,如果执行出错会抛出异常。
代码示例
try {
wx.setStorageSync('key', 'value')
} catch (e) {
console.error(e)
}
异步 API
大多数 API 都是异步 API,如 wx.request,wx.login 等。这类 API 接口通常都接受一个 Object 类型的参数,这个参数都支持按需指定以下字段来接收接口调用结果:
Object 参数说明
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
success | function | 否 | 接口调用成功的回调函数 |
fail | function | 否 | 接口调用失败的回调函数 |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
其他 | Any | - | 接口定义的其他参数 |
回调函数的参数
success,fail,complete 函数调用时会传入一个 Object 类型参数,包含以下字段:
属性 | 类型 | 说明 |
---|---|---|
errMsg | string | 错误信息,如果调用成功返回 ${apiName}:ok |
errCode | number | 错误码,仅部分 API 支持,具体含义请参考对应 API 文档,成功时为 0 。 |
其他 | Any | 接口返回的其他数据 |
异步 API 的执行结果需要通过 Object 类型的参数中传入的对应回调函数获取。部分异步 API 也会有返回值,可以用来实现更丰富的功能,如 wx.request,wx.connectSocket 等。
代码示例
wx.login({
success(res) {
console.log(res.code)
}
})
异步 API 返回 Promise
基础库 2.10.2 版本起,异步 API 支持 callback & promise 两种调用方式。当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 promise,否则仍按回调方式执行,无返回值。
注意事项
- 部分接口如 downloadFile, request, uploadFile, connectSocket, createCamera(小游戏)本身就有返回值, 它们的 promisify 需要开发者自行封装。
- 当没有回调参数时,异步接口返回 promise。此时若函数调用失败进入 fail 逻辑, 会报错提示 Uncaught (in promise),开发者可通过 catch 来进行捕获。
- wx.onUnhandledRejection 可以监听未处理的 Promise 拒绝事件。
代码示例
// callback 形式调用
wx.chooseImage({
success(res) {
console.log('res:', res)
}
})
// promise 形式调用
wx.chooseImage().then(res => console.log('res: ', res))
微信小程序 API
API
框架提供丰富的微信原生API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。
说明:
- wx.on开头的API是监听某个事件发生的API接口,接受一个CALLBACK函数作为参数。当该事件触发时,会调用CALLBACK函数。
- 如未特殊约定,其他API接口都接受一个OBJECT作为参数。
- OBJECT中可以指定success,fail,complete来接收接口调用结果。
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
success | Function | 否 | 接口调用成功的回调函数 |
fail | Function | 否 | 接口调用失败的回调函数 |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
API列表:
网络API列表:
API | 说明 |
---|---|
wx.request | 发起网络请求 |
wx.uploadFile | 上传文件 |
wx.downloadFile | 下载文件 |
wx.connectSocket | 创建WebSocket连接 |
wx.onSocketOpen | 监听WebSocket打开 |
wx.onSocketError | 监听WebSocket错误 |
wx.sendSocketMessage | 发送WebSocket消息 |
wx.onSocketMessage | 接受WebSocket消息 |
wx.closeSocket | 关闭WebSocket连接 |
wx.onSocketClose | 监听WebSocket关闭 |
媒体API列表:
API | 说明 |
---|---|
wx.chooseImage | 从相册选择图片,或者拍照 |
wx.previewImage | 预览图片 |
wx.startRecord | 开始录音 |
wx.stopRecord | 结束录音 |
wx.playVoice | 播放语音 |
wx.pauseVoice | 暂停播放语音 |
wx.stopVoice | 结束播放语音 |
wx.getBackgroundAudioPlayerState | 获取音乐播放状态 |
wx.playBackgroundAudio | 播放音乐 |
wx.pauseBackgroundAudio | 暂停播放音乐 |
wx.seekBackgroundAudio | 控制音乐播放进度 |
wx.stopBackgroundAudio | 停止播放音乐 |
wx.onBackgroundAudioPlay | 监听音乐开始播放 |
wx.onBackgroundAudioPause | 监听音乐暂停 |
wx.onBackgroundAudioStop | 监听音乐结束 |
wx.chooseVideo | 从相册选择视频,或者拍摄 |
文件 API 列表:
API | 说明 |
---|---|
wx.saveFile | 保存文件 |
wx.getSavedFileList | 获取已保存的文件列表 |
wx.getSavedFileInfo | 获取已保存的文件信息 |
wx.removeSavedFile | 删除已保存的文件信息 |
wx.openDocument | 打开文件 |
数据 API 列表:
API | 说明 |
---|---|
wx.getStorage | 获取本地数据缓存 |
wx.getStorageSync | 获取本地数据缓存 |
wx.setStorage | 设置本地数据缓存 |
wx.setStorageSync | 设置本地数据缓存 |
wx.getStorageInfo | 获取本地缓存的相关信息 |
wx.getStorageInfoSync | 获取本地缓存的相关信息 |
wx.removeStorage | 删除本地缓存内容 |
wx.removeStorageSync | 删除本地缓存内容 |
wx.clearStorage | 清理本地数据缓存 |
wx.clearStorageSync | 清理本地数据缓存 |
位置 API 列表:
API | 说明 |
---|---|
wx.getLocation | 获取当前位置 |
wx.chooseLocation | 打开地图选择位置 |
wx.openLocation | 打开内置地图 |
wx.createMapContext | 地图组件控制 |
设备 API 列表:
API | 说明 |
---|---|
wx.getNetworkType | 获取网络类型 |
wx.onNetworkStatusChange | 监听网络状态变化 |
wx.getSystemInfo | 获取系统信息 |
wx.getSystemInfoSync | 获取系统信息 |
wx.onAccelerometerChange | 监听加速度数据 |
wx.startAccelerometer | 开始监听加速度数据 |
wx.stopAccelerometer | 停止监听加速度数据 |
wx.onCompassChange | 监听罗盘数据 |
wx.startCompass | 开始监听罗盘数据 |
wx.stopCompass | 停止监听罗盘数据 |
wx.setClipboardData | 设置剪贴板内容 |
wx.getClipboardData | 获取剪贴板内容 |
wx.makePhoneCall | 拨打电话 |
wx.scanCode | 扫码 |
界面 API 列表:
API | 说明 |
---|---|
wx.showToast | 显示提示框 |
wx.showLoading | 显示加载提示框 |
wx.hideToast | 隐藏提示框 |
wx.hideLoading | 隐藏提示框 |
wx.showModal | 显示模态弹窗 |
wx.showActionSheet | 显示菜单列表 |
wx.setNavigationBarTitle | 设置当前页面标题 |
wx.showNavigationBarLoading | 显示导航条加载动画 |
wx.hideNavigationBarLoading | 隐藏导航条加载动画 |
wx.navigateTo | 新窗口打开页面 |
wx.redirectTo | 原窗口打开页面 |
wx.switchTab | 切换到 tabbar 页面 |
wx.navigateBack | 退回上一个页面 |
wx.createAnimation | 动画 |
wx.createCanvasContext | 创建绘图上下文 |
wx.drawCanvas | 绘图 |
wx.stopPullDownRefresh | 停止下拉刷新动画 |
WXML节点信息 API 列表:
API | 说明 |
---|---|
wx.createSelectorQuery | 创建查询请求 |
selectorQuery.select | 根据选择器选择单个节点 |
selectorQuery.selectAll | 根据选择器选择全部节点 |
selectorQuery.selectViewport | 选择显示区域 |
nodesRef.boundingClientRect | 获取布局位置和尺寸 |
nodesRef.scrollOffset | 获取滚动位置 |
nodesRef.fields | 获取任意字段 |
selectorQuery.exec | 执行查询请求 |
开放接口:
API | 说明 |
---|---|
wx.login | 登录 |
wx.getUserInfo | 获取用户信息 |
wx.chooseAddress | 获取用户收货地址 |
wx.requestPayment | 发起微信支付 |
wx.addCard | 添加卡券 |
wx.openCard | 打开卡券 |
微信视图层
小程序 WXML
WXML
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
要完整了解 WXML 语法,请参考WXML 语法参考。
用以下一些简单的例子来看看 WXML 具有什么能力:
数据绑定
<!--wxml-->
<view> {{message}} </view>
// page.js
Page({
data: {
message: 'Hello MINA!'
}
})
列表渲染
<!--wxml-->
<view wx:for="{{array}}"> {{item}} </view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5]
}
})
条件渲染
<!--wxml-->
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> MINA </view>
// page.js
Page({
data: {
view: 'MINA'
}
})
模板
<!--wxml-->
<template name="staffName">
<view>
FirstName: {{firstName}}, LastName: {{lastName}}
</view>
</template>
<template is="staffName" data="{{...staffA}}"></template>
<template is="staffName" data="{{...staffB}}"></template>
<template is="staffName" data="{{...staffC}}"></template>
// page.js
Page({
data: {
staffA: {firstName: 'Hulk', lastName: 'Hu'},
staffB: {firstName: 'Shang', lastName: 'You'},
staffC: {firstName: 'Gideon', lastName: 'Lin'}
}
})
引用
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
具体的能力以及使用方式在以下章节查看:
微信小程序 WXSS
WXSS
WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。
WXSS 用来决定 WXML 的组件应该怎么显示。
为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。
与 CSS 相比,WXSS 扩展的特性有:
- 尺寸单位
- 样式导入
尺寸单位
- rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 | rpx换算px (屏幕宽度/750) | px换算rpx (750/屏幕宽度) |
---|---|---|
iPhone5 | 1rpx = 0.42px | 1px = 2.34rpx |
iPhone6 | 1rpx = 0.5px | 1px = 2rpx |
iPhone6 Plus | 1rpx = 0.552px | 1px = 1.81rpx |
建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。
注意: 在较小的屏幕上不可避免的会有一些毛刺,请在开发时尽量避免这种情况。
样式导入
使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。
示例代码:
/** common.wxss **/
.small-p {
padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {
padding:15px;
}
内联样式
框架组件上支持使用 style、class 属性来控制组件的样式。
- style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
<view style="color:{{color}};" />
- class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。
<view class="normal_view" />
选择器
目前支持的选择器有:
选择器 | 样例 | 样例描述 |
---|---|---|
.class | .intro |
选择所有拥有 class="intro" 的组件 |
#id | #firstname |
选择拥有 id="firstname" 的组件 |
element | view |
选择所有 view 组件 |
element, element | view, checkbox |
选择所有文档的 view 组件和所有的 checkbox 组件 |
::after | view::after |
在 view 组件后边插入内容 |
::before | view::before |
在 view 组件前边插入内容 |
全局样式与局部样式
定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
微信小程序 WXS
WXS
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
注意
- WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
- WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
- WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。
- WXS 函数不能作为组件的事件回调。
- 由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
以下是一些使用 WXS 的简单示例,要完整了解 WXS 语法,请参考WXS 语法参考。
页面渲染
<!--wxml-->
<wxs module="m1">
var msg = "hello world";
module.exports.message = msg;
</wxs>
<view> {{m1.message}} </view>
页面输出:
hello world
数据处理
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5, 1, 2, 3, 4]
}
})
<!--wxml-->
<!-- 下面的 getMax 函数,接受一个数组,且返回数组中最大的元素的值 -->
<wxs module="m1">
var getMax = function(array) {
var max = undefined;
for (var i = 0; i < array.length; ++i) {
max = max === undefined ?
array[i] :
(max >= array[i] ? max : array[i]);
}
return max;
}
module.exports.getMax = getMax;
</wxs>
<!-- 调用 wxs 里面的 getMax 函数,参数为 page.js 里面的 array -->
<view> {{m1.getMax(array)}} </view>
页面输出:
5
微信小程序 事件系统
事件
什么是事件
- 事件是视图层到逻辑层的通讯方式。
- 事件可以将用户的行为反馈到逻辑层进行处理。
- 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
- 事件对象可以携带额外信息,如 id, dataset, touches。
事件的使用方式
- 在组件中绑定一个事件处理函数。
如bindtap,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。
<button id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </button>
- 在相应的Page定义中写上相应的事件处理函数,参数是event。
Page({
tapName: function(event) {
console.log(event)
}
})
使用WXS函数响应事件
基础库 2.4.4 开始支持,低版本需做兼容处理。
从基础库版本2.4.4开始,支持使用WXS函数绑定事件,WXS函数接受2个参数,第一个是event,在原有的event的基础上加了event.instance对象,第二个参数是ownerInstance,和event.instance一样是一个ComponentDescriptor对象。具体使用如下:
- 在组件中绑定和注册事件处理的WXS函数。
<wxs module="wxs" src="./test.wxs"></wxs>
<view id="tapTest" data-hi="WeChat" bindtap="{{wxs.tapName}}"> Click me! </view>
**注:绑定的WXS函数必须用{{}}括起来**
- test.wxs文件实现tapName函数
function tapName(event, ownerInstance) {
console.log('tap wechat', JSON.stringify(event))
}
module.exports = {
tapName: tapName
}
ownerInstance包含了一些方法,可以设置组件的样式和class,具体包含的方法以及为什么要用WXS函数响应事件。
事件详解
事件分类
事件分为冒泡事件和非冒泡事件:
- 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
- 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
WXML的冒泡事件列表:
类型 | 触发条件 | 最低版本 |
---|---|---|
touchstart | 手指触摸动作开始 | |
touchmove | 手指触摸后移动 | |
touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 | |
touchend | 手指触摸动作结束 | |
tap | 手指触摸后马上离开 | |
longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发 | 1.5.0 |
longtap | 手指触摸后,超过350ms再离开(推荐使用longpress事件代替) | |
transitionend | 会在 WXSS transition 或 wx.createAnimation 动画结束后触发 | |
animationstart | 会在一个 WXSS animation 动画开始时触发 | |
animationiteration | 会在一个 WXSS animation 一次迭代结束时触发 | |
animationend | 会在一个 WXSS animation 动画完成时触发 | |
touchforcechange | 在支持 3D Touch 的 iPhone 设备,重按时会触发 | 1.9.90 |
注:除上表之外的其他组件自定义事件如无特殊声明都是非冒泡事件,如 form 的submit事件,input 的input事件,scroll-view 的scroll事件,(详见各个组件)
普通事件绑定
事件绑定的写法类似于组件的属性,如:
<view bindtap="handleTap">
Click here!
</view>
如果用户点击这个 view ,则页面的 handleTap 会被调用。
事件绑定函数可以是一个数据绑定,如:
<view bindtap="{{ handlerName }}">
Click here!
</view>
此时,页面的 this.data.handlerName 必须是一个字符串,指定事件处理函数名;如果它是个空字符串,则这个绑定会失效(可以利用这个特性来暂时禁用一些事件)。
自基础库版本 1.5.0 起,在大多数组件和自定义组件中, bind 后可以紧跟一个冒号,其含义不变,如 bind:tap 。基础库版本 2.8.1 起,在所有组件中开始提供这个支持。
事件对象
如无特殊说明,当组件触发事件时,逻辑层绑定该事件的处理函数会收到一个事件对象。
BaseEvent 基础事件对象属性列表:
属性 | 类型 | 说明 | 基础库版本 |
---|---|---|---|
type | String | 事件类型 | |
timeStamp | Integer | 事件生成时的时间戳 | |
target | Object | 触发事件的组件的一些属性值集合 | |
currentTarget | Object | 当前组件的一些属性值集合 | |
mark | Object | 事件标记数据 | 2.7.1 |
CustomEvent 自定义事件对象属性列表(继承 BaseEvent):
属性 | 类型 | 说明 |
---|---|---|
detail | Object | 额外的信息 |
TouchEvent 触摸事件对象属性列表(继承 BaseEvent):
属性 | 类型 | 说明 |
---|---|---|
touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
特殊事件: canvas 中的触摸事件不可冒泡,所以没有 currentTarget。
微信小程序 简单双向绑定
简易双向绑定
基础库 2.9.3 开始支持,低版本需做兼容处理。
双向绑定语法
在 WXML 中,普通的属性的绑定是单向的。例如:
<input value="{{value}}" />
如果使用 this.setData({ value: 'leaf' })
来更新 value
,this.data.value
和输入框的中显示的值都会被更新为 leaf
;但如果用户修改了输入框里的值,却不会同时改变 this.data.value
。
如果需要在用户输入的同时改变 this.data.value
,需要借助简易双向绑定机制。此时,可以在对应项目之前加入 model:
前缀:
<input model:value="{{value}}" />
这样,如果输入框的值被改变了, this.data.value
也会同时改变。同时, WXML 中所有绑定了 value
的位置也会被一同更新, 数据监听器 也会被正常触发。
用于双向绑定的表达式有如下限制:
1.只能是一个单一字段的绑定,如
<input model:value="值为 {{value}}" />
<input model:value="{{ a + b }}" />
都是非法的;
2.目前,尚不能 data 路径,如
<input model:value="{{ a.b }}" />
这样的表达式目前暂不支持。
在自定义组件中传递双向绑定
双向绑定同样可以使用在自定义组件上。如下的自定义组件:
// custom-component.js
Component({
properties: {
myValue: String
}
})
<!-- custom-component.wxml -->
<input model:value="{{myValue}}" />
这个自定义组件将自身的 myValue
属性双向绑定到了组件内输入框的 value
属性上。这样,如果页面这样使用这个组件:
<custom-component model:my-value="{{pageValue}}" />
当输入框的值变更时,自定义组件的 myValue
属性会同时变更,这样,页面的 this.data.pageValue
也会同时变更,页面 WXML 中所有绑定了 pageValue
的位置也会被一同更新。
在自定义组件中触发双向绑定更新
自定义组件还可以自己触发双向绑定更新,做法就是:使用 setData 设置自身的属性。例如:
// custom-component.js
Component({
properties: {
myValue: String
},
methods: {
update: function() {
// 更新 myValue
this.setData({
myValue: 'leaf'
})
}
}
})
如果页面这样使用这个组件:
<custom-component model:my-value="{{pageValue}}" />
当组件使用 setData
更新 myValue
时,页面的 this.data.pageValue
也会同时变更,页面 WXML 中所有绑定了 pageValue
的位置也会被一同更新。
微信小程序 基础组件
基础组件
框架为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发。详细介绍请参考组件文档。
什么是组件:
- 组件是视图层的基本组成单元。
- 组件自带一些功能与微信风格一致的样式。
- 一个组件通常包括 开始标签 和 结束标签,属性 用来修饰这个组件,内容 在两个标签之内。
<tagname property="value">
Content goes here ...
</tagname>
注意:所有组件与属性都是小写,以连字符-连接
属性类型
类型 | 描述 | 注解 |
---|---|---|
Boolean | 布尔值 | 组件写上该属性,不管是什么值都被当作 true ;只有组件上没有该属性时,属性值才为false 。如果属性值为变量,变量的值会被转换为Boolean类型 |
Number | 数字 | 1 , 2.5 |
String | 字符串 | "string" |
Array | 数组 | [ 1, "string" ] |
Object | 对象 | { key: value } |
EventHandler | 事件处理函数名 | "handlerName" 是 Page 中定义的事件处理函数名 |
Any | 任意属性 |
公共属性
所有组件都有以下属性:
属性名 | 类型 | 描述 | 注解 |
---|---|---|---|
id | String | 组件的唯一标示 | 保持整个页面唯一 |
class | String | 组件的样式类 | 在对应的 WXSS 中定义的样式类 |
style | String | 组件的内联样式 | 可以动态设置的内联样式 |
hidden | Boolean | 组件是否显示 | 所有组件默认显示 |
data-* | Any | 自定义属性 | 组件上触发的事件时,会发送给事件处理函数 |
bind* / catch* | EventHandler | 组件的事件 | 详见事件 |
特殊属性
几乎所有组件都有各自定义的属性,可以对该组件的功能或样式进行修饰,请参考各个组件的定义。
微信小程序 获取界面上的节点信息
获取界面上的节点信息
WXML节点信息
节点信息查询 API 可以用于获取节点属性、样式、在界面上的位置等信息。
最常见的用法是使用这个接口来查询某个节点的当前位置,以及界面的滚动位置。
示例代码:
const query = wx.createSelectorQuery()
query.select('#the-id').boundingClientRect(function(res){
res.top // #the-id 节点的上边界坐标(相对于显示区域)
})
query.selectViewport().scrollOffset(function(res){
res.scrollTop // 显示区域的竖直滚动位置
})
query.exec()
上述示例中, #the-id 是一个节点选择器,与 CSS 的选择器相近但略有区别,请参见 SelectorQuery.select 的相关说明。
在自定义组件或包含自定义组件的页面中,推荐使用 this.createSelectorQuery 来代替 wx.createSelectorQuery ,这样可以确保在正确的范围内选择节点。
WXML节点布局相交状态
节点布局相交状态 API 可用于监听两个或多个组件节点在布局位置上的相交状态。这一组API常常可以用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见。
这一组API涉及的主要概念如下。
- 参照节点:监听的参照节点,取它的布局区域作为参照区域。如果有多个参照节点,则会取它们布局区域的 交集 作为参照区域。页面显示区域也可作为参照区域之一。
- 目标节点:监听的目标,默认只能是一个节点(使用 selectAll 选项时,可以同时监听多个节点)。
- 相交区域:目标节点的布局区域与参照区域的相交区域。
- 相交比例:相交区域占参照区域的比例。
- 阈值:相交比例如果达到阈值,则会触发监听器的回调函数。阈值可以有多个。
以下示例代码可以在目标节点(用选择器 .target-class 指定)每次进入或离开页面显示区域时,触发回调函数。
示例代码:
Page({
onLoad: function(){
wx.createIntersectionObserver().relativeToViewport().observe('.target-class', (res) => {
res.id // 目标节点 id
res.dataset // 目标节点 dataset
res.intersectionRatio // 相交区域占目标节点的布局区域的比例
res.intersectionRect // 相交区域
res.intersectionRect.left // 相交区域的左边界坐标
res.intersectionRect.top // 相交区域的上边界坐标
res.intersectionRect.width // 相交区域的宽度
res.intersectionRect.height // 相交区域的高度
})
}
})
以下示例代码可以在目标节点(用选择器 .target-class 指定)与参照节点(用选择器 .relative-class 指定)在页面显示区域内相交或相离,且相交或相离程度达到目标节点布局区域的20%和50%时,触发回调函数。
示例代码:
Page({
onLoad: function(){
wx.createIntersectionObserver(this, {
thresholds: [0.2, 0.5]
}).relativeTo('.relative-class').relativeToViewport().observe('.target-class', (res) => {
res.intersectionRatio // 相交区域占目标节点的布局区域的比例
res.intersectionRect // 相交区域
res.intersectionRect.left // 相交区域的左边界坐标
res.intersectionRect.top // 相交区域的上边界坐标
res.intersectionRect.width // 相交区域的宽度
res.intersectionRect.height // 相交区域的高度
})
}
})
注意:与页面显示区域的相交区域并不准确代表用户可见的区域,因为参与计算的区域是“布局区域”,布局区域可能会在绘制时被其他节点裁剪隐藏(如遇祖先节点中 overflow 样式为 hidden 的节点)或遮盖(如遇 fixed 定位的节点)。
微信小程序 响应显示区域变化
响应显示区域变化
显示区域尺寸
显示区域指小程序界面中可以自由布局展示的区域。在默认情况下,小程序显示区域的尺寸自页面初始化起就不会发生变化。但以下两种方式都可以改变这一默认行为。
在手机上启用屏幕旋转支持
从小程序基础库版本 2.4.0 开始,小程序在手机上支持屏幕旋转。使小程序中的页面支持屏幕旋转的方法是:在 app.json 的 window 段中设置 "pageOrientation": "auto" ,或在页面 json 文件中配置 "pageOrientation": "auto" 。
以下是在单个页面 json 文件中启用屏幕旋转的示例。
代码示例:
{
"pageOrientation": "auto"
}
如果页面添加了上述声明,则在屏幕旋转时,这个页面将随之旋转,显示区域尺寸也会随着屏幕旋转而变化。
从小程序基础库版本 2.5.0 开始, pageOrientation 还可以被设置为 landscape ,表示固定为横屏显示。
在 iPad 上启用屏幕旋转支持
从小程序基础库版本 2.3.0 开始,在 iPad 上运行的小程序可以支持屏幕旋转。使小程序支持 iPad 屏幕旋转的方法是:在 app.json 中添加 "resizable": true 。
代码示例:
{
"resizable": true
}
如果小程序添加了上述声明,则在屏幕旋转时,小程序将随之旋转,显示区域尺寸也会随着屏幕旋转而变化。注意:在 iPad 上不能单独配置某个页面是否支持屏幕旋转。
Media Query
有时,对于不同尺寸的显示区域,页面的布局会有所差异。此时可以使用 media query 来解决大多数问题。
代码示例:
.my-class {
width: 40px;
}
@media (min-width: 480px) {
/* 仅在 480px 或更宽的屏幕上生效的样式规则 */
.my-class {
width: 200px;
}
}
在 WXML 中,可以使用 match-media 组件来根据 media query 匹配状态展示、隐藏节点。
此外,可以在页面或者自定义组件 JS 中使用 this.createMediaQueryObserver() 方法来创建一个 MediaQueryObserver 对象,用于监听指定的 media query 的匹配状态。
屏幕旋转事件
有时,仅仅使用 media query 无法控制一些精细的布局变化。此时可以使用 js 作为辅助。
在 js 中读取页面的显示区域尺寸,可以使用 selectorQuery.selectViewport 。
页面尺寸发生改变的事件,可以使用页面的 onResize 来监听。对于自定义组件,可以使用 resize 生命周期来监听。回调函数中将返回显示区域的尺寸信息。(从基础库版本 2.4.0 开始支持。)
代码示例:
Page({
onResize(res) {
res.size.windowWidth // 新的显示区域宽度
res.size.windowHeight // 新的显示区域高度
}
})
Component({
pageLifetimes: {
resize(res) {
res.size.windowWidth // 新的显示区域宽度
res.size.windowHeight // 新的显示区域高度
}
}
})
此外,还可以使用 wx.onWindowResize 来监听(但这不是推荐的方式)。
微信小程序 动画
动画
界面动画的常见方式
在小程序中,通常可以使用 CSS 渐变 和 CSS 动画 来创建简易的界面动画。
动画过程中,可以使用 bindtransitionend bindanimationstart bindanimationiteration bindanimationend 来监听动画事件。
事件名 | 含义 |
---|---|
transitionend | CSS 渐变结束或 wx.createAnimation 结束一个阶段 |
animationstart | CSS 动画开始 |
animationiteration | CSS 动画结束一个阶段 |
animationend | CSS 动画结束 |
注意:这几个事件都不是冒泡事件,需要绑定在真正发生了动画的节点上才会生效。
同时,还可以使用 wx.createAnimation 接口来动态创建简易的动画效果。(新版小程序基础库中推荐使用下述的关键帧动画接口代替。)
关键帧动画
基础库 2.9.0 开始支持,低版本需做兼容处理。
从小程序基础库 2.9.0 开始支持一种更友好的动画创建方式,用于代替旧的 wx.createAnimation 。它具有更好的性能和更可控的接口。
在页面或自定义组件中,当需要进行关键帧动画时,可以使用 this.animate 接口:
this.animate(selector, keyframes, duration, callback)
参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
selector | String | 是 | 选择器(同 SelectorQuery.select 的选择器格式) | |
keyframes | Array | 是 | 关键帧信息 | |
duration | Number | 是 | 动画持续时长(毫秒为单位) | |
callback | function | 否 | 动画完成后的回调函数 |
keyframes 中对象的结构
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
offset | Number | 否 | 关键帧的偏移,范围[0-1] | |
ease | String | linear | 否 | 动画缓动函数 |
transformOrigin | String | 否 | 基点位置,即 CSS transform-origin | |
backgroundColor | String | 否 | 背景颜色,即 CSS background-color | |
bottom | Number/String | 否 | 底边位置,即 CSS bottom | |
height | Number/String | 否 | 高度,即 CSS height | |
left | Number/String | 否 | 左边位置,即 CSS left | |
width | Number/String | 否 | 宽度,即 CSS width | |
opacity | Number | 否 | 不透明度,即 CSS opacity | |
right | Number | 否 | 右边位置,即 CSS right | |
top | Number/String | 否 | 顶边位置,即 CSS top | |
matrix | Array | 否 | 变换矩阵,即 CSS transform matrix | |
matrix3d | Array | 否 | 三维变换矩阵,即 CSS transform matrix3d | |
rotate | Number | 否 | 旋转,即 CSS transform rotate | |
rotate3d | Array | 否 | 三维旋转,即 CSS transform rotate3d | |
rotateX | Number | 否 | X 方向旋转,即 CSS transform rotateX | |
rotateY | Number | 否 | Y 方向旋转,即 CSS transform rotateY | |
rotateZ | Number | 否 | Z 方向旋转,即 CSS transform rotateZ | |
scale | Array | 否 | 缩放,即 CSS transform scale | |
scale3d | Array | 否 | 三维缩放,即 CSS transform scale3d | |
scaleX | Number | 否 | X 方向缩放,即 CSS transform scaleX | |
scaleY | Number | 否 | Y 方向缩放,即 CSS transform scaleY | |
scaleZ | Number | 否 | Z 方向缩放,即 CSS transform scaleZ | |
skew | Array | 否 | 倾斜,即 CSS transform skew | |
skewX | Number | 否 | X 方向倾斜,即 CSS transform skewX | |
skewY | Number | 否 | Y 方向倾斜,即 CSS transform skewY | |
translate | Array | 否 | 位移,即 CSS transform translate | |
translate3d | Array | 否 | 三维位移,即 CSS transform translate3d | |
translateX | Number | 否 | X 方向位移,即 CSS transform translateX | |
translateY | Number | 否 | Y 方向位移,即 CSS transform translateY | |
translateZ | Number | 否 | Z 方向位移,即 CSS transform translateZ |
示例代码
在开发者工具中预览效果
this.animate('#container', [
{ opacity: 1.0, rotate: 0, backgroundColor: '#FF0000' },
{ opacity: 0.5, rotate: 45, backgroundColor: '#00FF00'},
{ opacity: 0.0, rotate: 90, backgroundColor: '#FF0000' },
], 5000, function () {
this.clearAnimation('#container', { opacity: true, rotate: true }, function () {
console.log("清除了#container上的opacity和rotate属性")
})
}.bind(this))
this.animate('.block', [
{ scale: [1, 1], rotate: 0, ease: 'ease-out' },
{ scale: [1.5, 1.5], rotate: 45, ease: 'ease-in', offset: 0.9},
{ scale: [2, 2], rotate: 90 },
], 5000, function () {
this.clearAnimation('.block', function () {
console.log("清除了.block上的所有动画属性")
})
}.bind(this))
调用 animate API 后会在节点上新增一些样式属性覆盖掉原有的对应样式。如果需要清除这些样式,可在该节点上的动画全部执行完毕后使用 this.clearAnimation 清除这些属性。
this.clearAnimation(selector, options, callback)
参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
selector | String | 是 | 选择器(同 SelectorQuery.select 的选择器格式) | |
options | Object | 否 | 需要清除的属性,不填写则全部清除 | |
callback | Function | 否 | 清除完成后的回调函数 |
滚动驱动的动画
我们发现,根据滚动位置而不断改变动画的进度是一种比较常见的场景,这类动画可以让人感觉到界面交互很连贯自然,体验更好。因此,从小程序基础库 2.9.0 开始支持一种由滚动驱动的动画机制。
基于上述的关键帧动画接口,新增一个 ScrollTimeline 的参数,用来绑定滚动元素(目前只支持 scroll-view)。接口定义如下:
this.animate(selector, keyframes, duration, ScrollTimeline)
ScrollTimeline 中对象的结构
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
scrollSource | String | 是 | 指定滚动元素的选择器(只支持 scroll-view),该元素滚动时会驱动动画的进度 | |
orientation | String | vertical | 否 | 指定滚动的方向。有效值为 horizontal 或 vertical |
startScrollOffset | Number | 是 | 指定开始驱动动画进度的滚动偏移量,单位 px | |
endScrollOffset | Number | 是 | 指定停止驱动动画进度的滚动偏移量,单位 px | |
timeRange | Number | 是 | 起始和结束的滚动范围映射的时间长度,该时间可用于与关键帧动画里的时间 (duration) 相匹配,单位 ms |
示例代码
在开发者工具中预览效果
this.animate('.avatar', [{
borderRadius: '0',
borderColor: 'red',
transform: 'scale(1) translateY(-20px)',
offset: 0,
}, {
borderRadius: '25%',
borderColor: 'blue',
transform: 'scale(.65) translateY(-20px)',
offset: .5,
}, {
borderRadius: '50%',
borderColor: 'blue',
transform: `scale(.3) translateY(-20px)`,
offset: 1
}], 2000, {
scrollSource: '#scroller',
timeRange: 2000,
startScrollOffset: 0,
endScrollOffset: 85,
})
this.animate('.search_input', [{
opacity: '0',
width: '0%',
}, {
opacity: '1',
width: '100%',
}], 1000, {
scrollSource: '#scroller',
timeRange: 1000,
startScrollOffset: 120,
endScrollOffset: 252
})
高级的动画方式
在一些复杂场景下,上述的动画方法可能并不适用。
WXS 响应事件 的方式可以通过使用 WXS 来响应事件的方法来动态调整节点的 style 属性。通过不断改变 style 属性的值可以做到动画效果。同时,这种方式也可以根据用户的触摸事件来动态地生成动画。
连续使用 setData 来改变界面的方法也可以达到动画的效果。这样可以任意地改变界面,但通常会产生较大的延迟或卡顿,甚至导致小程序僵死。此时可以通过将页面的 setData 改为 自定义组件 中的 setData 来提升性能。下面的例子是使用 setData 来实现秒表动画的示例。
微信小程序 初始渲染缓存
初始渲染缓存工作原理
小程序页面的初始化分为两个部分。
- 逻辑层初始化:载入必需的小程序代码、初始化页面 this 对象(也包括它涉及到的所有自定义组件的 this 对象)、将相关数据发送给视图层。
- 视图层初始化:载入必需的小程序代码,然后等待逻辑层初始化完毕并接收逻辑层发送的数据,最后渲染页面。
在启动页面时,尤其是小程序冷启动、进入第一个页面时,逻辑层初始化的时间较长。在页面初始化过程中,用户将看到小程序的标准载入画面(冷启动时)或可能看到轻微的白屏现象(页面跳转过程中)。
启用初始渲染缓存,可以使视图层不需要等待逻辑层初始化完毕,而直接提前将页面初始 data 的渲染结果展示给用户,这可以使得页面对用户可见的时间大大提前。它的工作原理如下:
- 在小程序页面第一次被打开后,将页面初始数据渲染结果记录下来,写入一个持久化的缓存区域(缓存可长时间保留,但可能因为小程序更新、基础库更新、储存空间回收等原因被清除);
- 在这个页面被第二次打开时,检查缓存中是否还存有这个页面上一次初始数据的渲染结果,如果有,就直接将渲染结果展示出来;
- 如果展示了缓存中的渲染结果,这个页面暂时还不能响应用户事件,等到逻辑层初始化完毕后才能响应用户事件。
利用初始渲染缓存,可以:
- 快速展示出页面中永远不会变的部分,如导航栏;
- 预先展示一个骨架页,提升用户体验;
- 展示自定义的加载提示;
- 提前展示广告,等等。
支持的组件
在初始渲染缓存阶段中,复杂组件不能被展示或不能响应交互。
目前支持的内置组件:
- <view />
- <text />
- <button />
- <image />
- <scroll-view />
- <rich-text />
自定义组件本身可以被展示(但它们里面用到的内置组件也遵循上述限制)。
静态初始渲染缓存
若想启用初始渲染缓存,最简单的方法是在页面的 json 文件中添加配置项 "initialRenderingCache": "static" :
{
"initialRenderingCache": "static"
}
如果想要对所有页面启用,可以在 app.json 的 window 配置段中添加这个配置:
{
"window": {
"initialRenderingCache": "static"
}
}
添加这个配置项之后,在手机中预览小程序首页,然后杀死小程序再次进入,就会通过初始渲染缓存来渲染首页。
注意:这种情况下,初始渲染缓存记录的是页面 data 应用在页面 WXML 上的结果,不包含任何 setData 的结果。
例如,如果想要在页面中展示出“正在加载”几个字,这几个字受到 loading 数据字段控制:
<view wx:if="{{loading}}">正在加载</view>
这种情况下, loading 应当在 data 中指定为 true ,如:
// 正确的做法
Page({
data: {
loading: true
}
})
而不能通过 setData 将 loading 置为 true :
// 错误的做法!不要这么做!
Page({
data: {},
onLoad: function() {
this.setData({
loading: true
})
}
})
换而言之,这种做法只包含页面 data 的渲染结果,即页面的纯静态成分。
在初始渲染缓存中添加动态内容
有些场景中,只是页面 data 的渲染结果会比较局限。有时会想要额外展示一些可变的内容,如展示的广告图片 URL 等。
这种情况下可以使用“动态”初始渲染缓存的方式。首先,配置 "initialRenderingCache": "dynamic" :
{
"initialRenderingCache": "dynamic"
}
此时,初始渲染缓存不会被自动启用,还需要在页面中调用 this.setInitialRenderingCache(dynamicData) 才能启用。其中, dynamicData 是一组数据,与 data 一起参与页面 WXML 渲染。
Page({
data: {
loading: true
},
onReady: function() {
this.setInitialRenderingCache({
loadingHint: '正在加载' // 这一部分数据将被应用于界面上,相当于在初始 data 基础上额外进行一次 setData
})
}
})
<view wx:if="{{loading}}">{{loadingHint}}</view>
从原理上说,在动态生成初始渲染缓存的方式下,页面会在后台使用动态数据重新渲染一次,因而开销相对较大。因而要尽量避免频繁调用 this.setInitialRenderingCache ,如果在一个页面内多次调用,仅最后一次调用生效。
注意:
- this.setInitialRenderingCache 调用时机不能早于 Page 的 onReady 或 Component 的 ready 生命周期,否则可能对性能有负面影响。
- 如果想禁用初始渲染缓存,调用 this.setInitialRenderingCache(null) 。
微信小程序 运行环境
小程序的运行环境
微信小程序运行在多种平台上:iOS(iPhone/iPad)微信客户端、Android 微信客户端、PC 微信客户端、Mac 微信客户端和用于调试的微信开发者工具。
各平台脚本执行环境以及用于渲染非原生组件的环境是各不相同的:
- 在 iOS 上,小程序逻辑层的 javascript 代码运行在 JavaScriptCore 中,视图层是由 WKWebView 来渲染的,环境有 iOS 12、iOS 13 等;
- 在 Android 上,小程序逻辑层的 javascript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Mobile Chrome 内核来渲染的;
- 在 开发工具上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium Webview 来渲染的。
平台差异
尽管各运行环境是十分相似的,但是还是有些许区别:
- JavaScript 语法和 API 支持不一致:语法上开发者可以通过开启 ES6 转 ES5 的功能来规避(详情);此外,小程序基础库内置了必要的Polyfill,来弥补API的差异(详情)。
- WXSS 渲染表现不一致:尽管可以通过开启样式补全来规避大部分的问题,还是建议开发者需要在 iOS 和 Android 上分别检查小程序的真实表现。
开发者工具仅供调试使用,最终的表现以客户端为准。
微信小程序 JavaScript支持情况
JavaScript 支持情况
运行限制
基于安全考虑,小程序中不支持动态执行 JS 代码,即:
- 不支持使用 eval 执行 JS 代码
- 不支持使用 new Function 创建函数
微信小程序 运行机制
小程序运行机制
前台/后台状态
小程序启动后,界面被展示给用户,此时小程序处于前台状态。
当用户点击右上角胶囊按钮关闭小程序,或者按了设备 Home 键离开微信时,小程序并没有完全终止运行,而是进入了后台状态,小程序还可以运行一小段时间。
当用户再次进入微信或再次打开小程序,小程序又会从后台进入前台。但如果用户很久没有再进入小程序,或者系统资源紧张,小程序可能被销毁,即完全终止运行。
小程序启动
这样,小程序启动可以分为两种情况,一种是冷启动,一种是热启动。
- 冷启动:如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动,即冷启动。
- 热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态,这个过程就是热启动。
小程序销毁时机
通常,只有当小程序进入后台一定时间,或者系统资源占用过高,才会被销毁。具体而言包括以下几种情形:
- 当小程序进入后台,可以维持一小段时间的运行状态,如果这段时间内都未进入前台,小程序会被销毁。
- 当小程序占用系统资源过高,可能会被系统销毁或被微信客户端主动回收。在 iOS 上,当微信客户端在一定时间间隔内连续收到系统内存告警时,会根据一定的策略,主动销毁小程序,并提示用户 「运行内存不足,请重新打开该小程序」。具体策略会持续进行调整优化。建议小程序在必要时使用 wx.onMemoryWarning 监听内存告警事件,进行必要的内存清理。
微信小程序 更新机制
小程序更新机制
未启动时更新
开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本。微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会静默更新到新版本。总的来说,开发者在后台发布新版本之后,无法立刻影响到所有现网用户,但最差情况下,也在发布之后 24 小时之内下发新版本信息到用户。用户下次打开时会先更新最新版本再打开。
启动时更新
小程序每次冷启动时,都会检查是否有更新版本,如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。
如果需要马上应用最新版本,可以使用 wx.getUpdateManager API 进行处理。
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
// 请求完新版本信息的回调
console.log(res.hasUpdate)
})
updateManager.onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(function () {
// 新版本下载失败
})
微信小程序 开发插件
开发插件
开发插件前,请阅读了解《小程序插件接入指南》了解开通流程及开放范围,并开通插件功能。如果未开通插件功能,将无法上传插件。
创建插件项目
插件类型的项目可以在开发者工具中直接创建。
新建插件类型的项目后,如果创建示例项目,则项目中将包含三个目录:
- plugin 目录:插件代码目录。
- miniprogram 目录:放置一个小程序,用于调试插件。
- doc 目录:用于放置插件开发文档。
miniprogram 目录内容可以当成普通小程序来编写,用于插件调试、预览和审核。下面的内容主要介绍 plugin 中的插件代码及 doc 中的插件开发文档。
我们提供了一个可以直接在微信开发者工具中查看的完整插件示例,开发者可以和本文互相对照以便理解。请注意:
- 由于插件需要 appid 才能工作,请填入一个 appid;
- 由于当前代码片段的限制,打开该示例后请 手动将 appid 填写到 miniprogram/app.json 中(如下图)使示例正常运行。
插件目录结构
一个插件可以包含若干个自定义组件、页面,和一组 js 接口。插件的目录内容如下:
plugin
├── components
│ ├── hello-component.js // 插件提供的自定义组件(可以有多个)
│ ├── hello-component.json
│ ├── hello-component.wxml
│ └── hello-component.wxss
├── pages
│ ├── hello-page.js // 插件提供的页面(可以有多个,自小程序基础库版本 2.1.0 开始支持)
│ ├── hello-page.json
│ ├── hello-page.wxml
│ └── hello-page.wxss
├── index.js // 插件的 js 接口
└── plugin.json // 插件配置文件
插件配置文件
向使用者小程序开放的所有自定义组件、页面和 js 接口都必须在插件配置文件 plugin.json 列出,格式如下:
代码示例:
{
"publicComponents": {
"hello-component": "components/hello-component"
},
"pages": {
"hello-page": "pages/hello-page"
},
"main": "index.js"
}
这个配置文件将向使用者小程序开放一个自定义组件 hello-component,一个页面 hello-page 和 index.js 下导出的所有 js 接口。
进行插件开发
请注意:在插件开发中,只有部分接口可以直接调用;另外还有部分能力(如 获取用户信息 和 发起支付 等)可以通过插件功能页的方式使用。
自定义组件
插件可以定义若干个自定义组件,这些自定义组件都可以在插件内相互引用。但提供给使用者小程序使用的自定义组件必须在配置文件的 publicComponents 段中列出(参考上文)。
除去接口限制以外,自定义组件的编写和组织方式与一般的自定义组件相同,每个自定义组件由 wxml, wxss, js 和 json 四个文件组成。具体可以参考自定义组件的文档。
页面
插件从小程序基础库版本 2.1.0 开始支持页面。插件可以定义若干个插件页面,可以从本插件的自定义组件、其他页面中跳转,或从使用者小程序中跳转。所有页面必须在配置文件的 pages 段中列出(参考上文)。
除去接口限制以外,插件的页面编写和组织方式与一般的页面相同,每个页面由 wxml, wxss, js 和 json 四个文件组成。具体可以参考其他关于页面的文档。
插件执行页面跳转的时候,可以使用 navigator 组件。当插件跳转到自身页面时, url 应设置为这样的形式:plugin-private://PLUGIN_APPID/PATH/TO/PAGE 。需要跳转到其他插件时,也可以这样设置 url 。
代码示例:
<navigator url="plugin-private://wxidxxxxxxxxxxxxxx/pages/hello-page">
Go to pages/hello-page!
</navigator>
自基础库版本 2.2.2 开始,在插件自身的页面中,插件还可以调用 wx.navigateTo 来进行页面跳转, url 格式与使用 navigator 组件时相仿。
接口
插件可以在接口文件(在配置文件中指定,详情见上文)中 export 一些 js 接口,供插件的使用者调用,如:
代码示例:
module.exports = {
hello: function() {
console.log('Hello plugin!')
}
}
获取小程序导出
从基础库 2.11.1 起,在插件中有全局函数 requireMiniProgram,可以获取由使用者小程序导出的内容。
例如,使用者小程序做了如下导出:
// 使用者小程序
module.exports = {
greeting() {
return 'Greetings from Wechat MiniProgram!';
}
}
那么在插件中,可以这样获得内容:
// 插件
const miniProgramExports = requireMiniProgram();
miniProgramExports.greeting(); // 'Greetings from Wechat MiniProgram!'
预览、上传和发布
插件可以像小程序一样预览和上传,但插件没有体验版。
插件会同时有多个线上版本,由使用插件的小程序决定具体使用的版本号。
手机预览和提审插件时,会使用一个特殊的小程序来套用项目中 miniprogram 文件夹下的小程序,从而预览插件。
- (建议的方式)如果当前开发者有测试号,则会使用这个测试号;在测试号的设置页中可以看到测试号的 appid 、 appsecret 并设置域名列表。
- 否则,将使用“插件开发助手”,它具有一个特定的 appid 。
在开发版小程序中测试
通常情况下,可以将 miniprogram 下的代码当做使用插件的小程序代码,来进行插件的调试和测试。
但有时,需要将插件的代码放在实际运行的小程序中进行调试、测试。此时,可以使用开发版的小程序直接引用开发版插件。方法如下:
- 在开发者工具的插件项目中上传插件,此时,在上传成功的通知信息中将包含这次上传获得的插件开发版 ID (一个英文、数字组成的随机字符串);
- 点击开发者工具右下角的通知按钮,可以打开通知栏,看到新生成的 ID ;
- 在使用这个插件的任意小程序项目中,可以将插件 version 设置为 "version": "dev-[开发版ID]" 的形式,如 "version": "dev-abcdef0123456789abcdef0123456789" ;
- 这样就会引用到这次上传的开发版插件;
- 注意,再次上传插件时, ID 可能会改变。
如果开发版小程序引用了开发版插件,此时这个小程序就不能上传发布了。必须要将插件版本设为正式版本之后,小程序才可以正常上传、发布。
插件开发文档
在使用者小程序使用插件时,插件代码并不可见。因此,除了插件代码,我们还支持插件开发者上传一份插件开发文档。这份开发文档将展示在插件详情页,供其他开发者在浏览插件和使用插件时进行阅读和参考。插件开发者应在插件开发文档中对插件提供的自定义组件、页面、接口等进行必要的描述和解释,方便使用者小程序正确使用插件。
插件开发文档必须放置在插件项目根目录中的 doc 目录下,目录结构如下:
doc
├── README.md // 插件文档,应为 markdown 格式
└── picture.jpg // 其他资源文件,仅支持图片
其中,README.md 的编写有一定的 限制条件,具体来说:
- 引用到的图片资源不能是网络图片,且必须放在这个目录下;
- 文档中的链接只能链接到:微信开发者社区(developers.weixin.qq.com)微信公众平台(mp.weixin.qq.com)GitHub(github.com)
编辑 README.md 之后,可以在开发者工具左侧资源管理器的文件栏中右键单击 README.md,并选择上传文档。发布上传文档后,文档不会立刻发布。此时可以使用帐号和密码登录 管理后台 ,在 小程序插件 > 基本设置 中预览、发布插件文档。
其他注意事项
插件间互相调用
插件不能直接引用其他插件。但如果小程序引用了多个插件,插件之间是可以互相调用的。
一个插件调用另一个插件的方法,与插件调用自身的方法类似。可以使用 plugin-private://APPID 访问插件的自定义组件、页面(暂不能使用 plugin:// )。
对于 js 接口,可使用 requirePlugin ,但目前尚不能在文件一开头就使用 requirePlugin ,因为被依赖的插件可能还没有初始化,请考虑在更晚的时机调用 requirePlugin ,如接口被实际调用时、组件 attached 时。(未来会修复这个问题。)
插件请求签名
插件在使用 wx.request 等 API 发送网络请求时,将会额外携带一个签名 HostSign ,用于验证请求来源于小程序插件。这个签名位于请求头中,形如:
X-WECHAT-HOSTSIGN: {"noncestr":"NONCESTR", "timestamp":"TIMESTAMP", "signature":"SIGNATURE"}
其中, NONCESTR 是一个随机字符串, TIMESTAMP 是生成这个随机字符串和 SIGNATURE 的 UNIX 时间戳。它们是用于计算签名 SIGNATRUE 的参数,签名算法为:
SIGNATURE = sha1([APPID, NONCESTR, TIMESTAMP, TOKEN].sort().join(''))
其中,APPID 是 所在小程序 的 AppId (可以从请求头的 referrer 中获得);TOKEN 是插件 Token,可以在小程序插件基本设置中找到。
网络请求的 referer 格式固定为 https://servicewechat.com/{appid}/{version}/page-frame.html,其中 {appid} 为小程序的 appid,{version} 为小程序的版本号,版本号为 0 表示为开发版、体验版以及审核版本,版本号为 devtools 表示为开发者工具,其余为正式版本。
插件开发者可以在服务器上按以下步骤校验签名:
- sort 对 APPID NONCESTR TIMESTAMP TOKEN 四个值表示成字符串形式,按照字典序排序(同 JavaScript 数组的 sort 方法);
- join 将排好序的四个字符串直接连接在一起;
- 对连接结果使用 sha1 算法,其结果即 SIGNATURE 。
微信小程序 使用插件
使用插件
添加插件
在使用插件前,首先要在小程序管理后台的“设置-第三方服务-插件管理”中添加插件。开发者可登录小程序管理后台,通过 appid 查找插件并添加。如果插件无需申请,添加后可直接使用;否则需要申请并等待插件开发者通过后,方可在小程序中使用相应的插件。
引入插件代码包
使用插件前,使用者要在 app.json 中声明需要使用的插件,例如:
代码示例:
{
"plugins": {
"myPlugin": {
"version": "1.0.0",
"provider": "wxidxxxxxxxxxxxxxxxx"
}
}
}
如上例所示, plugins 定义段中可以包含多个插件声明,每个插件声明以一个使用者自定义的插件引用名作为标识,并指明插件的 appid 和需要使用的版本号。其中,引用名(如上例中的 myPlugin)由使用者自定义,无需和插件开发者保持一致或与开发者协调。在后续的插件使用中,该引用名将被用于表示该插件。
在分包内引入插件代码包
如果插件只在一个分包内用到,可以将插件仅放在这个分包内,例如:
{
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
],
"plugins": {
"myPlugin": {
"version": "1.0.0",
"provider": "wxidxxxxxxxxxxxxxxxx"
}
}
}
]
}
在分包内使用插件有如下限制:
- 仅能在这个分包内使用该插件;
- 同一个插件不能被多个分包同时引用;
- 如果基础库版本低于 2.9.0 ,不能从分包外的页面直接跳入分包内的插件页面,需要先跳入分包内的非插件页面、再跳入同一分包内的插件页面。
使用插件
使用插件时,插件的代码对于使用者来说是不可见的。为了正确使用插件,使用者应查看插件详情页面中的“开发文档”一节,阅读由插件开发者提供的插件开发文档,通过文档来明确插件提供的自定义组件、页面名称及提供的 js 接口规范等。
自定义组件
使用插件提供的自定义组件,和使用普通自定义组件的方式相仿。在 json 文件定义需要引入的自定义组件时,使用 plugin:// 协议指明插件的引用名和自定义组件名,例如:
代码示例:
{
"usingComponents": {
"hello-component": "plugin://myPlugin/hello-component"
}
}
出于对插件的保护,插件提供的自定义组件在使用上有一定的限制:
- 默认情况下,页面中的 this.selectComponent 接口无法获得插件的自定义组件实例对象;
- wx.createSelectorQuery 等接口的 >>> 选择器无法选入插件内部。
页面
插件的页面从小程序基础库版本 2.1.0 开始支持。
需要跳转到插件页面时,url 使用 plugin:// 前缀,形如 plugin://PLUGIN_NAME/PLUGIN_PAGE, 如:
代码示例:
<navigator url="plugin://myPlugin/hello-page">
Go to pages/hello-page!
</navigator>
js 接口
使用插件的 js 接口时,可以使用 requirePlugin 方法。例如,插件提供一个名为 hello 的方法和一个名为 world 的变量,则可以像下面这样调用:
var myPluginInterface = requirePlugin('myPlugin');
myPluginInterface.hello();
var myWorld = myPluginInterface.world;
导出到插件
从基础库 2.11.1 起,使用插件的小程序可以导出一些内容,供插件获取。具体来说,在声明使用插件时,可以通过 export 字段来指定一个文件,如:
{
"myPlugin": {
"version": "1.0.0",
"provider": "wxidxxxxxxxxxxxxxxxx",
"export": "index.js"
}
}
则该文件(上面的例子里是 index.js)导出的内容可以被这个插件用全局函数获得。例如,在上面的文件中,使用插件的小程序做了如下导出:
// index.js
module.exports = { whoami: 'Wechat MiniProgram' }
那么插件就可以获得上面导出的内容:
// plugin
requireMiniProgram().whoami // 'Wechat MiniProgram'
具体导出什么内容,可以阅读插件开发文档,和插件的开发者做好约定。
当插件在分包中时,这个特性也可以使用,但指定的文件的路径是相对于分包的。例如在 root: packageA 的分包中指定了 export: exports/plugin.js,那么被指定的文件在文件系统上应该是 /packageA/exports/plugin.js。
使用的多个插件的导出互不影响,两个插件可以导出同一个文件,也可以是不同的文件。但导出同一个文件时,如果一个插件对导出内容做了修改,那么另一个插件也会被影响,请注意这一点。
请谨慎导出 wx 对象或某个具体的 wx API,这将使插件可以以使用者小程序的身份调用 API。
微信小程序 插件调用API的限制
插件调用 API 的限制
插件可以调用的 API 与小程序不同,主要有两个区别:
- 插件的请求域名列表与小程序相互独立;
- 一些 API 不允许插件调用(这些函数不存在于 wx 对象下)。
有些接口虽然在插件中不能使用,但可以通过插件功能页来达到目的,请参考插件功能页。
目前,允许插件调用的 API 及其对应版本要求如下:
插件使用组件的限制
在插件开发中,以下组件不能在插件页面中使用:
-
开放能力(open-type)为以下之一的 button:
- contact(打开客服会话)
- getPhoneNumber(获取用户手机号)
- getUserInfo(获取用户信息)
- open-data
- web-view
以下组件的使用对基础库版本有要求:
- navigator 需要基础库版本 2.1.0
- live-player 和 live-pusher 需要基础库版本 2.3.0
插件功能页
插件功能页从小程序基础库版本 2.1.0 开始支持。
某些接口不能在插件中直接调用(如 wx.login),但插件开发者可以使用插件功能页的方式来实现功能。目前,插件功能页包括:
- 获取用户信息,包括 openid 和昵称等(相当于 wx.login 和 wx.getUserInfo 的功能),详见用户信息功能页;
- 支付(相当于 wx.requestPayment),详见支付功能页;
- 获取收货地址(相当于 wx.chooseAddress),详见收货地址功能页。
要使用插件功能页,需要先激活功能页特性,配置对应的功能页函数,再使用 functional-page-navigator 组件跳转到插件功能页,从而实现对应的功能。详情请参考下文。
插件所有者小程序
开始开发之前,我们需要知道,插件功能页是指 插件所有者小程序 中的一个特殊页面。
插件所有者小程序,指的是与插件 AppID 相同的小程序。例如,“小程序示例”小程序开发了一个“小程序示例插件”,那么无论这个插件被哪个小程序使用,这个插件的 插件所有者小程序 都是“小程序示例”。下文中会继续使用 插件所有者小程序 这个说法。
插件所有者小程序开发方法
通常,在开始使用插件功能页的时候,需要开启两个开发者工具窗口,其中一个打开插件项目,另一个打开插件所有者小程序的小程序项目。例如,一个打开“小程序示例插件”项目,另一个打开“小程序示例”项目。
这两个窗口,前者用于编辑插件,后者用于编辑插件所有者小程序。下文中所有需要编辑插件所有者小程序的内容,都是在后者中进行。
激活功能页特性
要在插件中调用插件功能页,需要先激活插件所有者小程序的功能页特性。具体来说,在插件所有者小程序的 app.json 文件中添加 functionalPages 定义段,并令其值为 true ,例如:
代码示例:
{
"functionalPages": {
"independent": true
}
}
目前,兼容旧式写法:
{
"functionalPages": true
}
旧式写法将在未来将被移除支持,未来将不能编译上传。
这两种写法的区别在于,新式的写法 "independent": true 会使得插件功能页的代码独立于其他代码,这意味着插件功能页可以被独立下载、加载,具有更好的性能表现。 但也同时使得插件功能页目录 functional-pages/ (支付功能页会使用其中的文件)不能 require 这个目录以外的文件(反之亦然:这个目录以外的文件也不能调用这个目录内的)。
注意,新增或改变这个字段时,需要这个小程序发布新版本,才能在正式环境中使用插件功能页。
跳转到功能页
功能页不能使用 wx.navigateTo 来进行跳转,而是需要一个名为 functional-page-navigator 的组件。以获取用户信息为例,可以在插件中放置如下的 functional-page-navigator:
代码示例:
<functional-page-navigator name="loginAndGetUserInfo" args="" version="develop" bind:success="loginSuccess">
<button>登录到插件</button>
</functional-page-navigator>
用户在点击这个 navigator 时,会自动跳转到插件所有者小程序的对应功能页。功能页会提示用户进行登录或其他相应的操作。操作结果会以组件事件的方式返回。
functional-page-navigator 的参数和详细使用方法可以参考组件说明 。
从小程序基础库版本 2.4.0 开始,支持插件所有者小程序跳转到自己的功能页。在基础库版本低于 2.4.0 时,点击跳转到自己的功能页的 functional-page-navigator 将没有任何反应。
真机开发测试的常规步骤
目前,功能页的跳转目前不支持在开发者工具中调试,请在真机上测试。初次进行真机开发测试时,通常步骤如下:
- 在开发者工具上打开插件所有者小程序项目,并点击“预览”;
- 用测试用的真机扫一下预览二维码,此时会进入插件所有者小程序,进入后就可以直接退出这个小程序;
- 在开发者工具上打开插件项目,将插件中 functional-page-navigator 中的 version 属性设置为 develop;
- 点击预览可以生成插件预览二维码,用测试用的真机扫码即可预览功能页;如果更改了插件代码,重新生成并扫描插件的预览二维码即可;
- 如果过了一段时间之后,跳转功能页时出现“开发版已过期”这样的提示,从第1步开始重试一次。
注意:functional-page-navigator 的 version=develop 仅用于调试,因此在插件提审前,需要:
- 确保已发布设置了 "functionalPages": true 的插件所有者小程序;
- 确保所有的 functional-page-navigator 组件属性设置为 version="release" 。
微信小程序 网络
网络
在小程序/小游戏中使用网络相关的 API 时,需要注意下列问题,请开发者提前了解。
1. 服务器域名配置
每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信。包括普通 HTTPS 请求(wx.request)、上传文件(wx.uploadFile)、下载文件( wx.downloadFile) 和 WebSocket 通信(wx.connectSocket)。
从基础库 2.4.0 开始,网络接口允许与局域网 IP 通信,但要注意 不允许与本机 IP 通信。
从 2.7.0 开始,提供了 UDP 通信(wx.createUDPSocket)。
配置流程
服务器域名请在 「小程序后台-开发-开发设置-服务器域名」 中进行配置,配置时需要注意:
- 域名只支持 https (wx.request、wx.uploadFile、wx.downloadFile) 和 wss (wx.connectSocket) 协议;
- 域名不能使用 IP 地址(小程序的局域网 IP 除外)或 localhost;
- 可以配置端口,如 https://myserver.com:8080,但是配置后只能向 https://myserver.com:8080 发起请求。如果向 https://myserver.com、https://myserver.com:9091 等 URL 请求则会失败。
- 如果不配置端口。如 https://myserver.com,那么请求的 URL 中也不能包含端口,甚至是默认的 443 端口也不可以。如果向 https://myserver.com:443 请求则会失败。
- 域名必须经过 ICP 备案;
- 出于安全考虑,api.weixin.qq.com 不能被配置为服务器域名,相关API也不能在小程序内调用。 开发者应将 AppSecret 保存到后台服务器中,通过服务器使用 getAccessToken 接口获取 access_token,并调用相关 API;
- 对于每个接口,分别可以配置最多 20 个域名。
2. 网络请求
超时时间
- 默认超时时间和最大超时时间都是 60s;
- 超时时间可以在 app.json 或 game.json 中通过 networktimeout 配置。
使用限制
- 网络请求的 referer header 不可设置。其格式固定为 https://servicewechat.com/{appid}/{version}/page-frame.html,其中 {appid} 为小程序的 appid,{version} 为小程序的版本号,版本号为 0 表示为开发版、体验版以及审核版本,版本号为 devtools 表示为开发者工具,其余为正式版本;
- wx.request、wx.uploadFile、wx.downloadFile 的最大并发限制是 10 个;
- wx.connectSocket 的最大并发限制是 5 个。
- 小程序进入后台运行后,如果 5s 内网络请求没有结束,会回调错误信息 fail interrupted;在回到前台之前,网络请求接口调用都会无法调用。
返回值编码
- 建议服务器返回值使用 UTF-8 编码。对于非 UTF-8 编码,小程序会尝试进行转换,但是会有转换失败的可能。
- 小程序会自动对 BOM 头进行过滤(只过滤一个BOM头)。
回调函数
- 只要成功接收到服务器返回,无论 statusCode 是多少,都会进入 success 回调。请开发者根据业务逻辑对返回值进行判断。
3. 常见问题
HTTPS 证书
小程序必须使用 HTTPS/WSS 发起网络请求。请求时系统会对服务器域名使用的 HTTPS 证书进行校验,如果校验失败,则请求不能成功发起。由于系统限制,不同平台对于证书要求的严格程度不同。为了保证小程序的兼容性,建议开发者按照最高标准进行证书配置,并使用相关工具检查现有证书是否符合要求。
对证书要求如下:
- HTTPS 证书必须有效;证书必须被系统信任,即根证书被已系统内置部署 SSL 证书的网站域名必须与证书颁发的域名一致证书必须在有效期内证书的信任链必需完整(需要服务器配置)
- iOS 不支持自签名证书;
- iOS 下证书必须满足苹果 App Transport Security (ATS) 的要求;
- TLS 必须支持 1.2 及以上版本。部分旧 Android 机型还未支持 TLS 1.2,请确保 HTTPS 服务器的 TLS 版本支持 1.2 及以下版本;
- 部分 CA 可能不被操作系统信任,请开发者在选择证书时注意小程序和各系统的相关通告。
证书有效性可以使用 openssl s_client -connect example.com:443 命令验证,也可以使用其他在线工具。
除了网络请求 API 外,小程序中其他 HTTPS 请求如果出现异常,也请按上述流程进行检查。如 https 的图片无法加载、音视频无法播放等。
跳过域名校验
在微信开发者工具中,可以临时开启 开发环境不校验请求域名、TLS版本及HTTPS证书 选项,跳过服务器域名的校验。此时,在微信开发者工具中及手机开启调试模式时,不会进行服务器域名的校验。
在服务器域名配置成功后,建议开发者关闭此选项进行开发,并在各平台下进行测试,以确认服务器域名配置正确。
如果手机上出现 “打开调试模式可以发出请求,关闭调试模式无法发出请求” 的现象,请确认是否跳过了域名校验,并确认服务器域名和证书配置是否正确。
局域网通信
基础库 2.4.0 提供了 wx.startLocalServiceDiscovery 等一系列 mDNS API,可以用来获取局域网内提供 mDNS 服务的设备的 IP。 wx.request/wx.connectSocket/wx.uploadFile/wx.downloadFile 的 url 参数允许为 ${IP}:${PORT}/${PATH} 的格式,当且仅当 IP 与手机 IP 处在同一网段且不与本机 IP 相同(一般来说,就是同一局域网,如连接在同一个 wifi 下)时,请求/连接才会成功。
在这种情况下,不会进行安全域的校验,不要求必须使用 https/wss,也可以使用 http/ws。
wx.request({
url: 'http://10.9.176.40:828'
// 省略其他参数
})
wx.connectSocket({
url: 'ws://10.9.176.42:828'
// 省略其他参数
})
基础库 2.7.0 开始,提供了 wx.createUDPSocket 接口用于进行 UDP 通信。通信规则同上,仅允许同一局域网下的非本机 IP。
微信小程序 存储
存储
每个微信小程序都可以有自己的本地缓存,可以通过 wx.setStorage/wx.setStorageSync、wx.getStorage/wx.getStorageSync、wx.clearStorage/wx.clearStorageSync,wx.removeStorage/wx.removeStorageSync 对本地缓存进行读写和清理。
隔离策略
同一个微信用户,同一个小程序 storage 上限为 10MB。storage 以用户维度隔离,同一台设备上,A 用户无法读取到 B 用户的数据;不同小程序之间也无法互相读写数据。
清理策略
本地缓存的清理时机跟代码包一样,只有在代码包被清理的时候本地缓存才会被清理。
微信小程序 文件系统
文件系统
文件系统是小程序提供的一套以小程序和用户维度隔离的存储以及一套相应的管理接口。通过 wx.getFileSystemManager() 可以获取到全局唯一的文件系统管理器,所有文件系统的管理操作通过 FileSystemManager 来调用。
var fs = wx.getFileSystemManager()
文件主要分为两大类:
- 代码包文件:代码包文件指的是在项目目录中添加的文件。
- 本地文件:通过调用接口本地产生,或通过网络下载下来,存储到本地的文件。
其中本地文件又分为三种:
- 本地临时文件:临时产生,随时会被回收的文件。不限制存储大小。
- 本地缓存文件:小程序通过接口把本地临时文件缓存后产生的文件,不能自定义目录和文件名。跟本地用户文件共计,普通小程序最多可存储 10MB,游戏类目的小程序最多可存储 50MB。
- 本地用户文件:小程序通过接口把本地临时文件缓存后产生的文件,允许自定义目录和文件名。跟本地缓存文件共计,普通小程序最多可存储 10MB,游戏类目的小程序最多可存储 50MB。
代码包文件
由于代码包文件大小限制,代码包文件适用于放置首次加载时需要的文件,对于内容较大或需要动态替换的文件,不推荐用添加到代码包中,推荐在小游戏启动之后再用下载接口下载到本地。
访问代码包文件
代码包文件的访问方式是从项目根目录开始写文件路径,不支持相对路径的写法。如:/a/b/c、a/b/c 都是合法的,./a/b/c ../a/b/c 则不合法。
修改代码包文件
代码包内的文件无法在运行后动态修改或删除,修改代码包文件需要重新发布版本。
本地文件
本地文件指的是小程序被用户添加到手机后,会有一块独立的文件存储区域,以用户维度隔离。即同一台手机,每个微信用户不能访问到其他登录用户的文件,同一个用户不同 appId 之间的文件也不能互相访问。
本地文件的文件路径均为以下格式:
{{协议名}}://文件路径
其中,协议名在 iOS/Android 客户端为 "wxfile",在开发者工具上为 "http",开发者无需关注这个差异,也不应在代码中去硬编码完整文件路径。
本地临时文件
本地临时文件只能通过调用特定接口产生,不能直接写入内容。本地临时文件产生后,仅在当前生命周期内有效,重启之后即不可用。因此,不可把本地临时文件路径存储起来下次使用。如果需要下次在使用,可通过 FileSystemManager.saveFile() 或 FileSystemManager.copyFile() 接口把本地临时文件转换成本地缓存文件或本地用户文件。
示例
wx.chooseImage({
success: function (res) {
var tempFilePaths = res.tempFilePaths // tempFilePaths 的每一项是一个本地临时文件路径
}
})
本地缓存文件
本地缓存文件只能通过调用特定接口产生,不能直接写入内容。本地缓存文件产生后,重启之后仍可用。本地缓存文件只能通过 FileSystemManager.saveFile() 接口将本地临时文件保存获得。
示例
fs.saveFile({
tempFilePath: '', // 传入一个本地临时文件路径
success(res) {
console.log(res.savedFilePath) // res.savedFilePath 为一个本地缓存文件路径
}
})
注意:本地缓存文件是最初的设计,1.7.0 版本开始,提供了功能更完整的本地用户文件,可以完全覆盖本地缓存文件的功能,如果不需要兼容低于 1.7.0 版本,可以不使用本地缓存文件。
本地用户文件
本地用户文件是从 1.7.0 版本开始新增的概念。我们提供了一个用户文件目录给开发者,开发者对这个目录有完全自由的读写权限。通过 wx.env.USER_DATA_PATH 可以获取到这个目录的路径。
示例
// 在本地用户文件目录下创建一个文件 hello.txt,写入内容 "hello, world"
const fs = wx.getFileSystemManager()
fs.writeFileSync(`${wx.env.USER_DATA_PATH}/hello.txt`, 'hello, world', 'utf8')
读写权限
接口、组件 | 读 | 写 |
---|---|---|
代码包文件 | 有 | 无 |
本地临时文件 | 有 | 无 |
本地缓存文件 | 有 | 无 |
本地用户文件 | 有 | 有 |
清理策略
- 本地临时文件只保证在小程序当前生命周期内,一旦小程序被关闭就可能被清理,即下次冷启动不保证可用。
- 本地缓存文件和本地用户文件的清理时机跟代码包一样,只有在代码包被清理的时会被清理。
微信小程序 画布
Canvas 画布
所有在 canvas 中的画图必须用 JavaScript 完成:
WXML:(我们在接下来的例子中如无特殊声明都会用这个 WXML 为模板,不再重复)
<canvas canvas-id="myCanvas" style="border: 1px solid;"/>
JS:(我们在接下来的例子中会将 JS 放在 onLoad 中)
const ctx = wx.createCanvasContext('myCanvas')
ctx.setFillStyle('red')
ctx.fillRect(10, 10, 150, 75)
ctx.draw()
第一步:创建一个 Canvas 绘图上下文
首先,我们需要创建一个 Canvas 绘图上下文 CanvasContext。
CanvasContext 是小程序内建的一个对象,有一些绘图的方法:
const ctx = wx.createCanvasContext('myCanvas')
第二步:使用 Canvas 绘图上下文进行绘图描述
接着,我们来描述要在 Canvas 中绘制什么内容。
设置绘图上下文的填充色为红色:
ctx.setFillStyle('red')
用 fillRect(x, y, width, height) 方法画一个矩形,填充为刚刚设置的红色:
ctx.fillRect(10, 10, 150, 75)
第三步:画图
告诉 canvas 组件你要将刚刚的描述绘制上去:
ctx.draw()
结果:
坐标系
canvas 是在一个二维的网格当中。左上角的坐标为(0, 0)。
在上一节,我们用了这个方法 fillRect(0, 0, 150, 75)。
它的含义为:从左上角(0, 0)开始,画一个150 x 75px 的矩形。
代码示例
我们可以在 canvas 中加上一些事件,来观测它的坐标系
<canvas canvas-id="myCanvas"
style="margin: 5px; border:1px solid #d3d3d3;"
bindtouchstart="start"
bindtouchmove="move"
bindtouchend="end"/>
<view hidden="{{hidden}}">
Coordinates: ({{x}}, {{y}})
</view>
Page({
data: {
x: 0,
y: 0,
hidden: true
},
start (e) {
this.setData({
hidden: false,
x: e.touches[0].x,
y: e.touches[0].y
})
},
move (e) {
this.setData({
x: e.touches[0].x,
y: e.touches[0].y
})
},
end (e) {
this.setData({
hidden: true
})
}
})
微信小程序 分包加载
分包加载
微信客户端 6.6.0,基础库 1.7.3 及以上版本开始支持。开发者工具请使用 1.01.1712150 及以上版本,可点此下载。
某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
- 整个小程序所有分包大小不超过 16M
- 单个分包/主包大小不能超过 2M
对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。
具体使用方法请参考:
1、使用分包
配置方法
假设支持分包的小程序目录结构如下:
├── app.js
├── app.json
├── app.wxss
├── packageA
│ └── pages
│ ├── cat
│ └── dog
├── packageB
│ └── pages
│ ├── apple
│ └── banana
├── pages
│ ├── index
│ └── logs
└── utils
开发者通过在 app.json subpackages 字段声明项目分包结构:
写成 subPackages 也支持。
{
"pages":[
"pages/index",
"pages/logs"
],
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/cat",
"pages/dog"
]
}, {
"root": "packageB",
"name": "pack2",
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
subpackages 中,每个分包的配置有以下几项:
字段 | 类型 | 说明 |
---|---|---|
root | String | 分包根目录 |
name | String | 分包别名,分包预下载时可以使用 |
pages | StringArray | 分包页面路径,相对与分包根目录 |
independent | Boolean | 分包是否是独立分包 |
打包原则
- 声明 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 内的资源
微信小程序 多线程Worker
多线程 Worker
一些异步处理的任务,可以放置于 Worker 中运行,待运行结束后,再把结果返回到小程序主线程。Worker 运行于一个单独的全局上下文与线程中,不能直接调用主线程的方法。
Worker 与主线程之间的数据传输,双方使用 Worker.postMessage() 来发送数据,Worker.onMessage() 来接收数据,传输的数据并不是直接共享,而是被复制的。
使用流程
1. 配置 Worker 信息
在 app.json 中可配置 Worker 代码放置的目录,目录下的代码将被打包成一个文件:
配置示例:
{
"workers": "workers"
}
2. 添加 Worker 代码文件
根据步骤 1 中的配置,在代码目录下新建以下两个入口文件:
workers/request/index.js
workers/request/utils.js
workers/response/index.js
添加后,目录结构如下:
├── app.js
├── app.json
├── project.config.json
└── workers
├── request
│ ├── index.js
│ └── utils.js
└── response
└── index.js
3. 编写 Worker 代码
在 workers/request/index.js 编写 Worker 响应代码
const utils = require('./utils')
// 在 Worker 线程执行上下文会全局暴露一个 worker 对象,直接调用 worker.onMeesage/postMessage 即可
worker.onMessage(function (res) {
console.log(res)
})
4. 在主线程中初始化 Worker
在主线程的代码 app.js 中初始化 Worker
const worker = wx.createWorker('workers/request/index.js') // 文件名指定 worker 的入口文件路径,绝对路径
5. 主线程向 Worker 发送消息
worker.postMessage({
msg: 'hello worker'
})
worker 对象的其它接口请看 worker接口说明
注意事项
- Worker 最大并发数量限制为 1 个,创建下一个前请用 Worker.terminate() 结束当前 Worker
- Worker 内代码只能 require 指定 Worker 路径内的文件,无法引用其它路径
- Worker 的入口文件由 wx.createWorker() 时指定,开发者可动态指定 Worker 入口文件
- Worker 内不支持 wx 系列的 API
- Workers 之间不支持发送消息
微信小程序 服务端能力
后端 API
小程序还提供了一系列在后端服务器使用 HTTPS 请求调用的 API,帮助开发者在后台完成各类数据分析、管理和查询等操作。如 getAccessToken,code2Session 等。
access_token
access_token 是小程序全局唯一后台接口调用凭据,调用绝大多数后台接口时都需使用。开发者可以通过 getAccessToken 接口获取并进行妥善保存。
为了 access_token 的安全性,后端 API 不能直接在小程序内通过 wx.request 调用,即 api.weixin.qq.com 不能被配置为服务器域名。开发者应在后端服务器使用getAccessToken获取 access_token,并调用相关 API;
请求参数说明
- 对于 GET 请求,请求参数应以 QueryString 的形式写在 URL 中。
- 对于 POST 请求,部分参数需以 QueryString 的形式写在 URL 中(一般只有 access_token,如有额外参数会在文档里的 URL 中体现),其他参数如无特殊说明均以 JSON 字符串格式写在 POST 请求的 body 中。
返回参数说明
注意:当API调用成功时,部分接口不会返回 errcode 和 errmsg,只有调用失败时才会返回。
消息推送
接入微信小程序消息推送服务,可以两种方式选择其一:
- 开发者服务器接收消息推送
- 云函数接收消息推送
开发者服务器接收消息推送
开发者需要按照如下步骤完成:
- 填写服务器配置
- 验证服务器地址的有效性
- 据接口文档实现业务逻辑,接收消息和事件
第一步:填写服务器配置
登录小程序后台后,在「开发」-「开发设置」-「消息推送」中,管理员扫码启用消息服务,填写服务器地址(URL)、令牌(Token) 和 消息加密密钥(EncodingAESKey)等信息。
- URL: 开发者用来接收微信消息和事件的接口 URL。开发者所填写的URL 必须以 http:// 或 https:// 开头,分别支持 80 端口和 443 端口。
- Token: 可由开发者可以任意填写,用作生成签名(该 Token 会和接口 URL 中包含的 Token 进行比对,从而验证安全性)。
- EncodingAESKey: 由开发者手动填写或随机生成,将用作消息体加解密密钥。
同时,开发者可选择消息加解密方式:明文模式(默认)、兼容模式和安全模式。可以选择消息数据格式:XML 格式(默认)或 JSON 格式。
微信小程序 周期性更新
周期性更新能够在用户未打开小程序的情况下,也能从服务器提前拉取数据,当用户打开小程序时可以更快地渲染页面,减少用户等待时间,增强在弱网条件下的可用性。
使用流程
1. 配置数据下载地址
登录小程序 MP 管理后台,进入设置 -> 开发设置 -> 数据周期性更新,点击开启,填写数据下载地址。
2. 设置 TOKEN
第一次启动小程序时,调用 wx.setBackgroundFetchToken() 设置一个 TOKEN 字符串,可以跟用户态相关,会在后续微信客户端向开发者服务器请求时带上,便于给后者校验请求合法性。
示例:
App({
onLaunch() {
wx.setBackgroundFetchToken({
token: 'xxx'
})
}
})
3. 微信客户端定期拉取数据
微信客户端会在一定的网络条件下,每隔 12 小时(以上一次成功更新的时间为准)向配置的数据下载地址发起一个 HTTP GET 请求,其中包含的 query 参数如下,数据获取到后会将整个 HTTP body 缓存到本地。
参数 | 类型 | 说明 |
---|---|---|
appid | String | 小程序标识 |
token | String | 前面设置的 TOKEN |
timestamp | Number | 时间戳,微信客户端发起请求的时间 |
query 参数会使用 urlencode 处理
开发者服务器接口返回的数据类型应为字符串,且大小应不超过 256KB,否则将无法缓存数据
4. 读取数据
用户启动小程序时,调用 wx.getBackgroundFetchData() 获取已缓存到本地的数据。
示例:
App({
onLaunch() {
wx.getBackgroundFetchData({
fetchType: 'periodic',
success(res) {
console.log(res.fetchedData) // 缓存数据
console.log(res.timeStamp) // 客户端拿到缓存数据的时间戳
}
})
}
})
调试方法
由于微信客户端每隔 12 个小时才会发起一次请求,调试周期性更新功能会显得不太方便。 因此为了方便调试周期性数据,工具提供了下面的调试能力给到开发者。
微信小程序 大屏适配指南
大屏适配指南
目前市面上的用户设备大致可分为小屏的手机端、中屏的平板、大屏的 PC 端三类,而在这三类设备中又会有细小的尺寸差别,也称作屏幕碎片化。
随着小程序能够在越来越多的设备终端上运行,开发者也应该针对不同的屏幕尺寸进行相应的适配。
按照一般的适配原则,结合小程序特点,通常在以下三种情况中需要进行适配:
1. 同一类设备下,尺寸有细微差别
使用小程序提供的 rpx 单位,在尺寸差别不大的情况下对页面布局进行等比缩放。
2. 在允许屏幕旋转的情况下,可分为横屏与竖屏
手机端设置 "pageOrientation": "auto" 或 iPad 上设置 "resizable": true 时会允许屏幕旋转,此时使用 Page 的 onResize 事件或者 wx.onWindowResize 方法可对该操作进行监听,进而判断是使用横屏还是竖屏布局。
3. 不同类设备或者能够自由拖拽窗口的 PC 小程序
小程序目前是基于 Webview 实现,利用CSS 媒体查询可实时监听屏幕尺寸大小,在不同的屏幕下展现不同的 UI 布局,结合Flex 弹性布局、Grid 网格布局便能实现更加响应式的适配方案。
matchMedia - 抽象式媒体查询
小程序基础库基于 window.matchMedia API 新增了一组过程式与定义式接口 match-media 。开发者可以通过 <match-media></match-media> 和 wx.createMediaQueryObserver 来显式地使用媒体查询能力,对于多端适配来说,它有以下优势:
- 开发者能够更方便、显式地使用 Media Query 能力,而不是耦合在 CSS 文件中,难以复用。
- 能够在 WXML 中结合数据绑定动态地使用,不仅能做到组件的显示或隐藏,在过程式 API 中可塑性更高,例如能够根据尺寸变化动态地添加 class 类名,改变样式。
- 能够嵌套式地使用 Media Query 组件,即能够满足局部组件布局样式的改变。
- 组件化之后,封装性更强,能够隔离样式、模版以及绑定在模版上的交互事件,还能够提供更高的可复用性。
- 浏览器内置 API ,能够在所有基于 Webview 的小程序上使用,兼容性良好。 match-media 具体使用方法可参考相关 API 文档。
4. 自适应布局
为了让开发者更好的自适应大屏,小程序提供了 row/col 组件 供开发者使用。
自适应的主要特性是:
- 整行最多只有 24 份,对于的排列会自动向下换行
- 每个尺寸设置并不会影响到其它尺寸的布局
设计指引与代码示例
关于如何在设计、用户体验上实现更好的多端适配小程序。
同时我们也提供了多端适配示例小程序 ,基于 row/col 组件 简单实现了常见的适配场景,例如:
微信小程序 蓝牙
蓝牙适配器模块生效周期为调用 wx.openBluetoothAdapter 至调用 wx.closeBluetoothAdapter 或小程序被销毁为止。
在小程序蓝牙适配器模块生效期间,开发者才能够正常调用蓝牙相关的小程序 API,并收到蓝牙模块相关的事件回调。
注意
- 由于系统限制,Android 上获取到的 deviceId 为设备 MAC 地址,iOS 上则为设备 uuid。因此 deviceId 不能硬编码到代码中。
- 目前不支持在开发者工具上进行蓝牙功能的调试,需要使用真机才能正常调用小程序蓝牙接口。
低功耗蓝牙(BLE)注意事项
- iOS 上对特征值的 read、write、notify操作,由于系统需要获取特征值实例,传入的 serviceId 与 characteristicId 必须由 wx.getBLEDeviceServices 与 wx.getBLEDeviceCharacteristics 中获取到后才能使用。建议双平台统一在建立连接后先执行 wx.getBLEDeviceServices 与 wx.getBLEDeviceCharacteristics 后再进行与蓝牙设备的数据交互。
微信小程序 NFC
NFC
支持 HCE(基于主机的卡模拟)模式,即将安卓手机模拟成实体智能卡。 支持 NFC 读写,即手机作为读卡器使用。
- 适用机型:支持 NFC 功能,且系统版本为 Android 5.0 及以上的手机
- 适用卡范围:符合ISO 14443-4 标准的 CPU 卡
- 支持 Reader/Writer(读取器/写入器)模式,即支持 NFC 设备读取和/或写入被动 NFC 标签和贴纸。
- 适用机型:支持 NFC 功能,且系统版本为 Android 5.0 及以上的手机
- 适用范围:支持NFC-A (ISO 14443-3A)/NFC-B (ISO 14443-3B)/NFC-F (JIS 6319-4)/NFC-V (ISO 15693)/ISO-DEP (ISO 14443-4)标准的读写(部分Android手机)支持MIFARE Classic/MIFARE Ultralight标签的读写支持对NDEF格式的NFC标签上的NDEF数据的读写
基本流程
以往NFC-A卡片写入apdu指令为例
- 调用wx.getNFCAdapter()获取NFC适配器实例
- 调用NFCAdapter.onDiscovered(function callback)注册贴卡监听回调
- 调用NFCAdapter.startDiscovery(Object object)开始监听贴卡
- 贴卡,onDiscovered回调根据onDiscovered回调res对象的techs字段匹配到卡片支持NFC-A标准通过NFCAdapter.getNfcA()获取NfcA实例
- 使用NfcA实例进行读写调用NfcA.connect()和NFC卡片建立连接调用NfcA.transceive(Object object)往NFC卡片写入apdu指令并接收卡片返回数据读写完毕,调用NfcA.close()断开连接
- 调用NFCAdapter.stopDiscovery(Object object)结束监听贴卡
微信小程序 Wi-Fi
Wi-Fi
在小程序中支持搜索周边的 Wi-Fi,同时可以针对指定 Wi-Fi,传入密码发起连接。
该系列接口为系统原生能力,如需查看「微信连Wi-Fi」能力及配置跳转小程序,请参考文档。
连接指定 Wi-Fi 接口调用时序:
- Android:startWifi —> connectWifi —> onWifiConnected
- iOS(仅iOS 11及以上版本支持):startWifi —> connectWifi —> onWifiConnected
连周边 Wi-Fi 接口调用时序:
- Android:startWifi —> getWifiList —> onGetWifiList —> connectWifi —> onWifiConnected
- iOS(iOS 11.0及11.1版本因系统原因暂不支持):startWifi —> getWifiList —> onGetWifiList —> setWifiList —> onWifiConnected
注意:
- Wi-Fi 相关接口暂不可用 wx.canIUse 接口判断。
- Android 6.0 以上版本,在没有打开定位开关的时候会导致设备不能正常获取周边的 Wi-Fi 信息。
微信小程序 用户信息·小程序登录
小程序登录
小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。
登录流程时序
说明:
- 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
- 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 和 会话密钥 session_key。
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
注意:
- 会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
- 临时登录凭证 code 只能使用一次
微信小程序 用户信息·UnionID机制说明
UnionID 机制说明
如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 UnionID 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 UnionID 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,UnionID是相同的。
UnionID获取途径
绑定了开发者帐号的小程序,可以通过以下途径获取 UnionID。
- 调用接口 wx.getUserInfo,从解密数据中获取 UnionID。注意本接口需要用户授权,请开发者妥善处理用户拒绝授权后的情况。
- 如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号。开发者可以直接通过 wx.login + code2Session 获取到该用户 UnionID,无须用户再次授权。
- 如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用。开发者也可以直接通过 wx.login + code2Session 获取到该用户 UnionID ,无须用户再次授权。
- 用户在小程序(暂不支持小游戏)中支付完成后,开发者可以直接通过getPaidUnionId接口获取该用户的 UnionID,无需用户授权。注意:本接口仅在用户支付完成后的5分钟内有效,请开发者妥善处理。
- 小程序端调用云函数时,如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号,可在云函数中通过 cloud.getWXContext 获取 UnionID。
- 小程序端调用云函数时,如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用,也可在云函数中通过 cloud.getWXContext 获取 UnionID。
微信小程序 用户信息·授权
授权
部分接口需要经过用户授权同意才能调用。我们把这些接口按使用范围分成多个 scope ,用户选择对 scope 来进行授权,当授权给一个 scope 之后,其对应的所有接口都可以直接使用。
此类接口调用时:
- 如果用户未接受或拒绝过此权限,会弹窗询问用户,用户点击同意后方可调用接口;
- 如果用户已授权,可以直接调用接口;
- 如果用户已拒绝授权,则不会出现弹窗,而是直接进入接口 fail 回调。请开发者兼容用户拒绝授权的场景。
获取用户授权设置
开发者可以使用 wx.getSetting 获取用户当前的授权状态。
打开设置界面
用户可以在小程序设置界面(「右上角」 - 「关于」 - 「右上角」 - 「设置」)中控制对该小程序的授权状态。
开发者可以调用 wx.openSetting 打开设置界面,引导用户开启授权。
提前发起授权请求
开发者可以使用 wx.authorize 在调用需授权 API 之前,提前向用户发起授权请求。
scope 列表
scope | 对应接口 | 描述 |
---|---|---|
scope.userInfo | wx.getUserInfo | 用户信息 |
scope.userLocation | wx.getLocation, wx.chooseLocation | 地理位置 |
scope.userLocationBackground | wx.startLocationUpdateBackground | 后台定位 |
scope.address | wx.chooseAddress | 通讯地址 |
scope.invoiceTitle | wx.chooseInvoiceTitle | 发票抬头 |
scope.invoice | wx.chooseInvoice | 获取发票 |
scope.werun | wx.getWeRunData | 微信运动步数 |
scope.record | wx.startRecord | 录音功能 |
scope.writePhotosAlbum | wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum | 保存到相册 |
scope.camera | camera 组件 | 摄像头 |
授权有效期
一旦用户明确同意或拒绝过授权,其授权关系会记录在后台,直到用户主动删除小程序。
最佳实践
在真正需要使用授权接口时,才向用户发起授权申请,并在授权申请中说明清楚要使用该功能的理由。
注意事项
- wx.authorize({scope: "scope.userInfo"}),不会弹出授权窗口,请使用 <button open-type="getUserInfo"/>
- 需要授权 scope.userLocation、scope.userLocationBackground 时必须配置地理位置用途说明。
微信小程序 用户信息·开放数据校验与解密
服务端获取开放数据
小程序可以通过各种前端接口获取微信提供的开放数据。考虑到开发者服务端也需要获取这些开放数据,微信提供了两种获取方式:
- 方式一:开发者后台校验与解密开放数据
- 方式二:云调用直接获取开放数据(云开发)
方式一:开发者后台校验与解密开放数据
微信会对这些开放数据做签名和加密处理。开发者后台拿到开放数据后可以对数据进行校验签名和解密,来保证数据不被篡改。
签名校验以及数据加解密涉及用户的会话密钥 session_key。 开发者应该事先通过 wx.login 登录流程获取会话密钥 session_key 并保存在服务器。为了数据不被篡改,开发者不应该把 session_key 传到小程序客户端等服务器外的环境。
数据签名校验
为了确保开放接口返回用户数据的安全性,微信会对明文数据进行签名。开发者可以根据业务需要对数据包进行签名校验,确保数据的完整性。
- 通过调用接口(如 wx.getUserInfo)获取数据时,接口会同时返回 rawData、signature,其中 signature = sha1( rawData + session_key )
- 开发者将 signature、rawData 发送到开发者服务器进行校验。服务器利用用户对应的 session_key 使用相同的算法计算出签名 signature2 ,比对 signature 与 signature2 即可校验数据的完整性。
如 wx.getUserInfo的数据校验:
接口返回的rawData:
{
"nickName": "Band",
"gender": 1,
"language": "zh_CN",
"city": "Guangzhou",
"province": "Guangdong",
"country": "CN",
"avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"
}
用户的 session-key:
HyVFkGl5F5OQWJZZaNzBBg==
用于签名的字符串为:
{"nickName":"Band","gender":1,"language":"zh_CN","city":"Guangzhou","province":"Guangdong","country":"CN","avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"}HyVFkGl5F5OQWJZZaNzBBg==
使用sha1得到的结果为
75e81ceda165f4ffa64f4068af58c64b8f54b88c
加密数据解密算法
接口如果涉及敏感数据(如wx.getUserInfo当中的 openId 和 unionId),接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据,需要对接口返回的加密数据(encryptedData) 进行对称解密。 解密算法如下:
- 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
- 对称解密的目标密文为 Base64_Decode(encryptedData)。
- 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
- 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
微信官方提供了多种编程语言的示例代码((点击下载)。每种语言类型的接口名字均一致。调用方式可以参照示例。
另外,为了应用能校验数据的有效性,会在敏感数据加上数据水印( watermark )
watermark参数说明:
参数 | 类型 | 说明 |
---|---|---|
appid | String | 敏感数据归属 appId,开发者可校验此参数与自身 appId 是否一致 |
timestamp | Int | 敏感数据获取的时间戳, 开发者可以用于数据时效性校验 |
如接口 wx.getUserInfo 敏感数据当中的 watermark:
{
"openId": "OPENID",
"nickName": "NICKNAME",
"gender": GENDER,
"city": "CITY",
"province": "PROVINCE",
"country": "COUNTRY",
"avatarUrl": "AVATARURL",
"unionId": "UNIONID",
"watermark":
{
"appid":"APPID",
"timestamp":TIMESTAMP
}
}
注:
- 解密后得到的json数据根据需求可能会增加新的字段,旧字段不会改变和删减,开发者需要预留足够的空间
会话密钥 session_key 有效性
开发者如果遇到因为 session_key 不正确而校验签名失败或解密失败,请关注下面几个与 session_key 有关的注意事项。
- wx.login 调用时,用户的 session_key 可能会被更新而致使旧 session_key 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 wx.login,并非每次调用都导致 session_key 刷新)。开发者应该在明确需要重新登录时才调用 wx.login,及时通过 auth.code2Session 接口更新服务器存储的 session_key。
- 微信不会把 session_key 的有效期告知开发者。我们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序,session_key 有效期越长。
- 开发者在 session_key 失效时,可以通过重新执行登录流程获取有效的 session_key。使用接口 wx.checkSession可以校验 session_key 是否有效,从而避免小程序反复执行登录流程。
- 当开发者在实现自定义登录态时,可以考虑以 session_key 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。
微信小程序 用户信息·获取手机号
获取手机号
获取微信用户绑定的手机号,需先调用wx.login接口。
因为需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用 button 组件的点击来触发。
注意:目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)。需谨慎使用,若用户举报较多或被发现在不必要场景下使用,微信有权永久回收该小程序的该接口权限。
使用方法
需要将 button 组件 open-type 的值设置为 getPhoneNumber,当用户点击并同意之后,可以通过 bindgetphonenumber 事件回调获取到微信服务器返回的加密数据, 然后在第三方服务端结合 session_key 以及 app_id 进行解密获取手机号。
注意
在回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。建议开发者提前进行 login;或者在回调中先使用 checkSession 进行登录态检查,避免 login 刷新登录态。
代码示例
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({
getPhoneNumber (e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv)
console.log(e.detail.encryptedData)
}
})
返回参数说明
参数 | 类型 | 说明 | 最低版本 |
---|---|---|---|
encryptedData | String | 包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法 | |
iv | String | 加密算法的初始向量,详细见加密数据解密算法 | |
cloudID | string | 敏感数据对应的云 ID,开通云开发的小程序才会返回,可通过云调用直接获取开放数据,详细见云调用直接获取开放数据 | 基础库 2.8.0 |
获取得到的开放数据为以下 json 结构:
{
"phoneNumber": "13580006666",
"purePhoneNumber": "13580006666",
"countryCode": "86",
"watermark":
{
"appid":"APPID",
"timestamp": TIMESTAMP
}
}
参数 | 类型 | 说明 |
---|---|---|
phoneNumber | String | 用户绑定的手机号(国外手机号会有区号) |
purePhoneNumber | String | 没有区号的手机号 |
countryCode | String | 区号 |
微信小程序 用户信息·生物认证
生物认证
小程序通过 SOTER 提供以下生物认证方式。
目前暂时只支持指纹识别认证。设备支持的生物认证方式可使用 wx.checkIsSupportSoterAuthentication 查询
调用流程
流程步骤说明
- 调用 wx.startSoterAuthentication,获取 resultJSON 和 resultJSONSignature
- (可选)签名校验。此处 resultJSONSignature 使用 SHA256withRSA/PSS 作为签名算法进行验签。此公式数学定义如下: bool 验签结果=verify(用于签名的原串,签名串,验证签名的公钥)
- 微信提供后台接口用于可信的密钥验签服务,微信将保证该接口返回的验签结果的正确性与可靠性,并且对于 Android root 情况下该接口具有上述特征(将返回是否保证root情况安全性)。
微信小程序 分享到朋友圈(Beta)
设置分享状态
小程序页面默认不可被分享到朋友圈,开发者需主动设置“分享到朋友圈”。页面允许被分享到朋友圈,需满足两个条件:
- 首先,页面需设置允许“发送给朋友”。具体参考 Page.onShareAppMessage 接口文档
- 满足条件 1 后,页面需设置允许“分享到朋友圈”,同时可自定义标题、分享图等。具体参考 Page.onShareTimeline 接口文档
满足上述两个条件的页面,可被分享到朋友圈。
单页模式
用户在朋友圈打开分享的小程序页面,并不会真正打开小程序,而是进入一个“小程序单页模式”的页面,“单页模式”有以下特点:
- “单页模式”下,页面顶部固定有导航栏,标题显示为当前页面 JSON 配置的标题。底部固定有操作栏,点击操作栏的“前往小程序”可打开小程序的当前页面。顶部导航栏与底部操作栏均不支持自定义样式。
- “单页模式”默认运行的是小程序页面内容,但由于页面固定有顶部导航栏与底部操作栏,很可能会影响小程序页面的布局。因此,请开发者特别注意适配“单页模式”的页面交互,以实现流畅完整的交互体验。
- “单页模式”下,一些组件或接口存在一定限制,详情见下文单页模式下的限制章节
页面适配
可通过判断场景值等于 1154 的方法来进行页面适配。另外,在单页模式下,可设置顶部导航栏与页面的相交状态,具体参考 navigationBarFit 配置。
还需留意的是,在单页模式下,wx.getSystemInfo 接口返回的 safeArea 为整个屏幕空间。
单页模式下的限制
小程序“单页模式”适用于纯内容展示场景,可实现的交互与接口能力有限,因此存在如下限制:
- 页面无登录态,与登录相关的接口,如 wx.login 均不可用;云开发资源需开启未登录访问方可在单页模式下使用,详见未登录模式。
- 不允许跳转到其它页面,包括任何跳小程序页面、跳其它小程序、跳微信原生页面
- 不允许横屏使用
- 若页面包含 tabBar,tabBar 不会渲染,包括自定义 tabBar
- 本地存储与小程序普通模式不共用
对于一些会产生交互的组件或接口,在点击后调用时,会弹 toast 提示“请前往小程序使用完整服务”。为达到良好的用户体验,请注意适配单页模式的接口能力,请勿大量使用被禁用的接口或组件。
禁用能力列表:
分类 | 功能点 |
---|---|
组件 | button open-type 、 camera 、 editor 、 form 、 functional-page-navigator 、 live-pusher 、 navigator 、 navigation-bar 、 official-account 、 open-data 、 web-view |
路由 | wx.redirectTo 、 wx.reLaunch 、 wx.navigateTo 、 wx.switchTab 、 wx.navigateBack |
界面 | 导航栏 、 Tab Bar |
网络 | mDNS 、 UDP 通信 |
数据缓存 | 周期性更新 |
媒体 | VoIP 、 wx.chooseMedia 、 wx.chooseImage 、 wx.saveImageToPhotosAlbum 、 wx.chooseVideo 、 wx.saveVideoToPhotosAlbum 、 wx.getVideoInfo 、 wx.compressVideo |
位置 | wx.openLocation 、 wx.chooseLocation 、 wx.startLocationUpdateBackground 、 wx.startLocationUpdate |
转发 | wx.getShareInfo 、 wx.showShareMenu 、 wx.hideShareMenu 、 wx.updateShareMenu |
文件 | wx.openDocument |
开放接口 | 登录 、 小程序跳转 、 用户信息 、 支付 、 授权 、 设置 、 收货地址 、 卡券 、 发票 、 生物认证 、 微信运动 、 微信红包 |
设备 | 蓝牙 、 iBeacon 、 Wi-Fi 、 NFC 、 联系人 、 剪贴板 、 电话 、 扫码 |
广告 | ad 、 wx.createRewardedVideoAd 、 wx.createInterstitialAd |
运营须知
分享朋友圈能力是为了满足纯内容场景的分享诉求,滥用于营销、诱导等行为将会被打击。
- 小程序提供的服务中,不得存在滥用分享违规行为。如强制用户分享行为;分享立即获得利益的诱导行为;以及通过明示或暗示的样式来达到诱导分享目的的行为等。详见《微信小程序平台运营规范》
- 在“单页模式”下,不得诱导或强制用户点击“打开小程序”,应在“单页模式”中尽可能呈现完整的内容
提示:
- 低版本微信客户端打开时,会进入一个升级提示页面
- 不支持在小程序页面内直接发起分享
- 自定义分享内容时不支持自定义页面路径
- 存在 web-view 组件的页面不支持发起分享
- 支持打开开发版、体验版,无权限人员进入时页面会提示无权限
微信小程序 转发
转发
获取更多转发信息
通常开发者希望转发出去的小程序被二次打开的时候能够获取到一些信息,例如群的标识。现在通过调用 wx.showShareMenu 并且设置 withShareTicket 为 true ,当用户将小程序转发到任一群聊之后,此转发卡片在群聊中被其他用户打开时,可以在 App.onLaunch 或 App.onShow 获取到一个 shareTicket。通过调用 wx.getShareInfo 接口传入此 shareTicket 可以获取到转发信息。
页面内发起转发
基础库 1.2.0 开始支持,低版本需做兼容处理。
通过给 button 组件设置属性 open-type="share",可以在用户点击按钮后触发 Page.onShareAppMessage 事件,相关组件:button。
使用指引
转发按钮,旨在帮助用户更流畅地与好友分享内容和服务。转发,应是用户自发的行为,且在需要时触手可及。开发者在使用时若遵从以下指引,会得到更佳的用户体验。
- 含义清晰:明确、一目了然的图形按钮,将为用户减少理解的时间。在我们的资源下载中心,你可以找到这样的按钮素材并直接使用。或者你可以根据自己业务的设计风格,灵活设计含义清晰的按钮的样式。当然,你也可以直接使用带文案的按钮,“转发给好友”,它也足够明确。
- 方便点击:按钮点击热区不宜过小,亦不宜过大。同时,转发按钮与其他按钮一样,热区也不宜过密,以免用户误操作。
- 按需出现:并非所有页面都适合放置转发按钮,涉及用户隐私的非公开内容,或可能打断用户完成当前操作体验的场景,该功能并不推荐使用。同时,由于转发过程中,我们将截取用户屏幕图像作为配图,因此,需要注意帮助用户屏蔽个人信息。
- 尊重意愿:理所当然,并非所有的用户,都喜欢与朋友分享你的小程序。因此,它不应该成为一个诱导或强制行为,如转发后才能解锁某项功能等。请注意,这类做法不仅不被推荐,还可能违反我们的《运营规范》,我们强烈建议你在使用前阅读这部分内容。
以上,我们陈列了最重要的几点,如果你有时间,可以完整浏览《设计指南》,相信会有更多的收获。
提示:
- 不自定义转发图片的情况下,默认会取当前页面,从顶部开始,高度为 80% 屏幕宽度的图像作为转发图片。
- 转发的调试支持请查看 普通转发的调试支持 和 带 shareTicket 的转发
- 只有转发到群聊中打开才可以获取到 shareTickets 返回值,单聊没有 shareTickets
- shareTicket 仅在当前小程序生命周期内有效
- 由于策略变动,小程序群相关能力进行调整,开发者可先使用 wx.getShareInfo 接口中的群 ID 进行功能开发。
- 微信7.0.12开始,支持群主转发小程序时同时把消息设为该群的群待办消息,群待办消息会以气泡形式出现在聊天窗口底部。默认每次转发一个群待办消息,都会生成一个待办消息气泡。通过 wx.updateShareMenu 接口修改toDoActivityId属性可以把多个待办消息聚合为同一个,即转发相同toDoActivityId的群待办消息,只会出现一个待办消息气泡。toDoActivityId需要在转发前通过 updatableMessage.createActivityId 接口创建。
动态消息
从基础库 2.4.0 开始,支持转发动态消息。动态消息对比普通消息,有以下特点:
- 消息发出去之后,开发者可以通过后台接口修改部分消息内容。
- 消息有对应的提醒按钮,用户点击提醒按钮可以订阅提醒,开发者可以通过后台修改消息状态并推送一次提醒消息给订阅了提醒的用户
消息属性
动态消息有状态、文字内容、文字颜色。
状态
消息有两个状态,分别有其对应的文字内容和颜色。其中状态 0 可以转移到状态 0 和 1,状态 1 无法再转移。
状态 | 文字内容 | 颜色 | 允许转移的状态 |
---|---|---|---|
0 | "成员正在加入,当前 {member_count}/{room_limit} 人" | #FA9D39 | 0, 1 |
1 | "已开始" | #CCCCCC | 无 |
状态参数
每个状态转移的时候可以携带参数,具体参数说明如下。
参数 | 类型 | 说明 |
---|---|---|
member_count | string | 状态 0 时有效,文字内容模板中 member_count 的值 |
room_limit | string | 状态 0 时有效,文字内容模板中 room_limit 的值 |
path | string | 状态 1 时有效,点击「进入」启动小程序时使用的路径。对于小游戏,没有页面的概念,可以用于传递查询字符串(query),如 "?foo=bar" |
version_type | string | 状态 1 时有效,点击「进入」启动小程序时使用的版本。有效参数值为:develop (开发版),trial (体验版),release (正式版) |
微信小程序 收藏
收藏
安卓 7.0.15 版本起支持,iOS 暂不支持
小程序菜单增加收藏功能,可收藏某个页面至收藏夹。点开小程序右上角胶囊,点击收藏按钮会触发 Page.onAddToFavorites 事件。
微信小程序 多人音视频对话
多人音视频对话
用于实现小程序内多人音视频对话的功能。
申请开通
小程序管理后台,「开发」-「接口设置」中自助开通该组件权限。相关接口 wx.joinVoIPChat 和组件 voip-room。
调用流程
开发者仅需提供房间唯一标识,即可加入到指定的房间。传入相同唯一标识的用户,会进到相同的房间。为了保证前端传入的 groupId 可信,wx.joinVoIPChat 接口要求传入签名。详见下文 签名算法。当加入视频房间时,可结合 voip-room 组件显示成员画面。
前端接口
- 创建/加入房间:wx.joinVoIPChat
- 离开房间:wx.exitVoIPChat
- 更新房间麦克风/耳机静音设置:wx.updateVoIPChatMuteConfig
- 监听房间成员变化:wx.onVoIPChatMembersChanged
- 监听房间成员通话状态变化:wx.onVoIPChatSpeakersChanged
- 监听通话中断:wx.onVoIPChatInterrupted
- 监听实时语音通话成员视频状态变化:wx.onOnVoIPVideoMembersChanged
签名算法
生成签名需要传入四个参数:
参数名 | 说明 |
---|---|
appId | 小游戏的 appId |
groupId | 游戏房间的唯一标识,由游戏自己保证唯一 |
nonceStr | 随机字符串,长度应小于 128 |
timeStamp | 生成这个随机字符串的 UNIX 时间戳(精确到秒) |
签名算法为:
signature = hmac_sha256([appId, groupId, nonceStr, timeStamp].sort().join(''), sessionKey)
具体来说,这个算法分为几个步骤:
- 对 appId groupId nonceStr timeStamp 四个值表示成字符串形式,按照字典序排序;
- 将排好序的四个字符串拼接在一起;
- 使用 session_key 作为 key,使用 hmac_sha256 算法对 2 中的结果字符串做计算,所得结果即为 signature
示例:
appId = 'wx20afc706a711eefc'
groupId = '1559129713_672975982'
nonceStr = '8AP6DT9ybtniUJfb'
timeStamp = '1559129714'
session_key = 'gDyVgzwa0mFz9uUP7M6GQQ=='
str = [appId, groupId, nonceStr, timeStamp].sort().join('') = '1559129713_67297598215591297148AP6DT9ybtniUJfbwx20afc706a711eefc'
signature = hmac_sha256('1559129713_67297598215591297148AP6DT9ybtniUJfbwx20afc706a711eefc', sessionKey) = 'b002b824688dd8593a6079e11d8c5e8734fbcb39a6d5906eb347bfbcad79c617'
使用云开发完成签名
在云开发中,无法获取 session_key,但提供了单独的函数 cloud.getVoIPSign 来计算签名。
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
const signature = cloud.getVoIPSign({
groupId: 'xxx',
timestamp: 123,
nonce: 'yyy'
})
return signature
}
人数限制
每个房间最多同时加入 10 个人。
频率限制
对于每个小程序,每天最多允许创建 100000 个房间。当所有人退出房间时,房间即被销毁。此时如果传入之前用过的 groupId 重新加入房间,会被计算为新开一个房间。
微信小程序 打开App
打开 App
此功能需要用户主动触发才能打开 APP,所以不由 API 来调用,需要用 open-type 的值设置为 launchApp 的 button 组件的点击来触发。
当小程序从 APP 分享消息卡片的场景打开(场景值 1036,APP 分享小程序文档 iOS / Android) 或从 APP 打开的场景打开时(场景值 1069),小程序会获得打开 APP 的能力,此时用户点击按钮可以打开分享该小程序卡片/拉起该小程序的 APP。即小程序不能打开任意 APP,只能 跳回 APP。
在一个小程序的生命周期内,只有在特定条件下,才具有打开 APP 的能力。
在基础库 < 2.5.1 的版本,这个能力的规则如下:
当小程序从 1069 场景打开时,可以打开 APP。
当小程序从非 1069 的打开时,会在小程序框架内部会管理的一个状态,为 true 则可以打开 APP,为 false 则不可以打开 APP。这个状态的维护遵循以下规则:
- 当小程序从 App 分享消息卡片(场景值1036)打开时,该状态置为 true。
- 当小程序从以下场景打开时,保持上一次打开小程序时打开 App 能力的状态:从其他小程序返回小程序(场景值1038)时(基础库 2.2.4 及以上版本支持)小程序从聊天顶部场景(场景值1089)中的「最近使用」内打开时长按小程序右上角菜单唤出最近使用历史(场景值1090)打开时
- 当小程序从非以上场景打开时,不具有打开 APP 的能力,该状态置为 false。
在基础库 >= 2.5.1 时,这个能力的规则如下:
当小程序从任意场景打开时,会在小程序框架内部会管理的一个状态,为 true 则可以打开 APP,为 false 则不可以打开 APP。这个状态的维护遵循以下规则:
- 当小程序从 App 分享消息卡片(场景值1036)或从 APP 打开的场景打开时(场景值 1069)打开时,该状态置为 true。
- 当小程序从以下场景打开时,保持上一次打开小程序时打开 App 能力的状态:从其他小程序返回小程序(场景值1038)时(基础库 2.2.4 及以上版本支持)小程序从聊天顶部场景(场景值1089)中的「最近使用」内打开时长按小程序右上角菜单唤出最近使用历史(场景值1090)打开时
- 当小程序从非以上场景打开时,不具有打开 APP 的能力,该状态置为 false。
使用方法
小程序端
需要将 button 组件 open-type 的值设置为 launchApp。如果需要在打开 APP 时向 APP 传递参数,可以设置 app-parameter 为要传递的参数。通过 binderror 可以监听打开 APP 的错误事件。
app 端
APP 需要接入 OpenSDK。 文档请参考 iOS / Android
Android 第三方 app 需要处理 ShowMessageFromWX.req 的微信回调,iOS 则需要将 appId 添加到第三方 app 工程所属的 plist 文件 URL types 字段。 app-parameter 的获取方法,参数解析请参考 Android SDKSample 中 WXEntryActivity 中的 onResp 方法以及 iOS SDKSample 中 WXApiDelegate 中的 onResp 方法。
代码示例
<button open-type="launchApp" app-parameter="wechat" binderror="launchAppError">打开APP</button>
Page({
launchAppError (e) {
console.log(e.detail.errMsg)
}
})
error 事件参数说明
值 | 说明 |
---|---|
invalid scene | 调用场景不正确,即此时的小程序不具备打开 APP 的能力。 |
微信小程序 消息·订阅消息
小程序订阅消息
功能介绍
消息能力是小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验。
- 订阅消息推送位置:服务通知
- 订阅消息下发条件:用户自主订阅
- 订阅消息卡片跳转能力:点击查看详情可跳转至该小程序的页面
使用说明
步骤一:获取模板 ID
在微信公众平台手动配置获取模板 ID:登录 https://mp.weixin.qq.com 获取模板,如果没有合适的模板,可以申请添加新模板,审核通过后可使用。
步骤二:获取下发权限
详见小程序端消息订阅接口 wx.requestSubscribeMessage
步骤三:调用接口下发订阅消息
详见服务端消息发送接口 subscribeMessage.send
微信小程序 消息·统一服务消息
统一服务消息
为便于开发者对用户进行服务消息触达,简化小程序和公众号模板消息下发流程,小程序提供统一的服务消息下发接口。
相关接口
微信小程序 消息·客服消息
客服消息
在页面使用客服消息
需要将 button 组件 open-type 的值设置为 contact,当用户点击后就会进入客服会话,如果用户在会话中点击了小程序消息,则会返回到小程序,开发者可以通过 bindcontact 事件回调获取到用户所点消息的页面路径 path 和对应的参数 query。
代码示例
<button open-type="contact" bindcontact="handleContact"></button>
Page({
handleContact (e) {
console.log(e.detail.path)
console.log(e.detail.query)
}
})
返回参数说明
参数 | 类型 | 说明 |
---|---|---|
path | String | 小程序消息指定的路径 |
query | Object | 小程序消息指定的查询参数 |
后台接入消息服务
用户向小程序客服发送消息、或者进入会话等情况时,开发者填写的服务器配置 URL (如果使用的是云开发,则是配置的云函数)将得到微信服务器推送过来的消息和事件,开发者可以依据自身业务逻辑进行响应。接入和使用方式请参考消息推送。
接收消息和事件
在页面中使用 <button open-type="contact" /> 可以显示进入客服会话按钮。
当用户在客服会话发送消息、或由某些特定的用户操作引发事件推送时,微信服务器会将消息或事件的数据包发送到开发者填写的 URL,如果使用的是云开发,则可以推送到指定的云函数(详情请参考消息推送)。开发者收到请求后可以使用 发送客服消息 接口进行异步回复。
各消息类型的推送JSON、XML数据包结构如下。
文本消息
用户在客服会话中发送文本消息时将产生如下数据包:
XML 格式
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1482048670</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
</xml>
JSON 格式
{
"ToUserName": "toUser",
"FromUserName": "fromUser",
"CreateTime": 1482048670,
"MsgType": "text",
"Content": "this is a test",
"MsgId": 1234567890123456
}
参数说明
参数 | 说明 |
---|---|
ToUserName | 小程序的原始ID |
FromUserName | 发送者的openid |
CreateTime | 消息创建时间(整型) |
MsgType | text |
Content | 文本消息内容 |
MsgId | 消息id,64位整型 |
图片消息
用户在客服会话中发送图片消息时将产生如下数据包:
XML 格式
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1482048670</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<PicUrl><![CDATA[this is a url]]></PicUrl>
<MediaId><![CDATA[media_id]]></MediaId>
<MsgId>1234567890123456</MsgId>
</xml>
JSON 格式
{
"ToUserName": "toUser",
"FromUserName": "fromUser",
"CreateTime": 1482048670,
"MsgType": "image",
"PicUrl": "this is a url",
"MediaId": "media_id",
"MsgId": 1234567890123456
}
参数说明
参数 | 说明 |
---|---|
ToUserName | 小程序的原始ID |
FromUserName | 发送者的openid |
CreateTime | 消息创建时间(整型) |
MsgType | image |
PicUrl | 图片链接(由系统生成) |
MediaId | 图片消息媒体id,可以调用[获取临时素材]((getTempMedia)接口拉取数据。 |
MsgId | 消息id,64位整型 |
小程序卡片消息
用户在客服会话中发送小程序卡片消息时将产生如下数据包:
XML 格式
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1482048670</CreateTime>
<MsgType><![CDATA[miniprogrampage]]></MsgType>
<MsgId>1234567890123456</MsgId>
<Title><![CDATA[Title]]></Title>
<AppId><![CDATA[AppId]]></AppId>
<PagePath><![CDATA[PagePath]]></PagePath>
<ThumbUrl><![CDATA[ThumbUrl]]></ThumbUrl>
<ThumbMediaId><![CDATA[ThumbMediaId]]></ThumbMediaId>
</xml>
JSON 格式
{
"ToUserName": "toUser",
"FromUserName": "fromUser",
"CreateTime": 1482048670,
"MsgType": "miniprogrampage",
"MsgId": 1234567890123456,
"Title":"title",
"AppId":"appid",
"PagePath":"path",
"ThumbUrl":"",
"ThumbMediaId":""
}
参数说明
参数 | 说明 |
---|---|
ToUserName | 小程序的原始ID |
FromUserName | 发送者的openid |
CreateTime | 消息创建时间(整型) |
MsgType | miniprogrampage |
MsgId | 消息id,64位整型 |
Title | 标题 |
AppId | 小程序appid |
PagePath | 小程序页面路径 |
ThumbUrl | 封面图片的临时cdn链接 |
ThumbMediaId | 封面图片的临时素材id |
微信小程序 消息·位置消息
为了让用户更便 捷地使用小程序的打车服务,我们在位置消息详情页的菜单中,新增了打车小程序入口。
- 打开聊天中的位置消息,点击详情页右下角绿色按钮,菜单中会展示符合条件的打车小程序,用户可以直接发起目的地为该位置的打车服务。
- 小程序的注册类目为“打车(网约车)”,且有用户最近使用的记录,才可以出现在该菜单中。
- 在此处点击打开小程序后,需要直接进入到发起打车页面。
1. 位置消息入口声明
开发者需要在全局配置app.json声明支持从位置消息入口进入小程序。
配置示例:
"entranceDeclare": {
"locationMessage": {
"path": "pages/index/index",
"query": "foo=bar"
}
}
配置项
属性 | 类型 | 必填 | 描述 | 最低版本 |
---|---|---|---|---|
entranceDeclare | Object | 否 | 入口声明信息 | 7.0.9 |
entranceDeclare参数列表
属性 | 类型 | 必填 | 描述 | 最低版本 |
---|---|---|---|---|
locationMessage | Object | 否 | 声明“位置消息”场景进入小程序的启动页面 | 7.0.9 |
locationMessage参数列表
属性 | 类型 | 必填 | 描述 | 最低版本 |
---|---|---|---|---|
path | string | 否 | 启动页路径,必须是在pages中已经定义 | 7.0.9 |
query | string | 否 | 启动页参数 | 7.0.9 |
2. 从启动参数获取位置信息
示例代码:
//app.js
App({
onLaunch: function (options){
console.log(options)
var scene = options.scene
if (scene == 1146) { // 位置消息场景值
var location = options.locationInfo
var x = location.latitude
var y = location.longitude
var name = location.name
}
},
})
Object 启动参数
属性 | 类型 | 描述 |
---|---|---|
scene | number | 启动小程序的场景值,“位置消息”的启动场景值为1146 |
locationInfo | Object | 特殊场景的启动信息 |
locationInfo 的结构
属性 | 类型 | 描述 |
---|---|---|
latitude | number | 纬度,范围为 -90~90,负数表示南纬 |
longtitude | number | 经度,范围为 -180~180,负数表示西经 |
name | string | POI名称 |
3. 工具调试
Nightly v1.02.1912062 版本已支持条件编译增加位置消息入口。选择场景值 1146: 位置消息中用小程序打车,传入POI点名称和经纬度信息后可用真机预览调试。
微信小程序 获取小程序码
获取小程序码
通过后台接口可以获取小程序任意页面的小程序码,扫描该小程序码可以直接进入小程序对应的页面,所有生成的小程序码永久有效,可放心使用。 我们推荐生成并使用小程序码,它具有更好的辨识度,且拥有展示“公众号关注组件”等高级能力。 生成的小程序码如下所示:
可以使用开发工具 1.02.1803130 及以后版本通过二维码编译功能调试所获得的二维码
为满足不同需求和场景,这里提供了两个接口,开发者可挑选适合自己的接口。
- 接口 A: 适用于需要的码数量较少的业务场景
- 生成小程序码,可接受 path 参数较长,生成个数受限,数量限制见 注意事项,请谨慎使用。
- 接口 B:适用于需要的码数量极多的业务场景
- 生成小程序码,可接受页面参数较短,生成个数不受限。
获取小程序二维码(不推荐使用)
通过后台接口可以获取小程序任意页面的小程序二维码,生成的小程序二维码如下所示:
- 接口 C:适用于需要的码数量较少的业务场景
- 生成二维码,可接受 path 参数较长,生成个数受限,数量限制见 注意事项。
获取小程序码(一物一码)
微信一物一码 支持生成小程序码。微信通过“一物一码”接口发放的二维码相比较普通链接二维码更安全、支持更小的印刷面积,支持跳转到指定小程序页面,且无数量限制。
注意事项
- 接口只能生成已发布的小程序的二维码
- 接口 A 加上接口 C,总共生成的码数量限制为 100,000,请谨慎调用。
- 接口 B 调用分钟频率受限(5000次/分钟),如需大量小程序码,建议预生成。
微信小程序 数据分析
数据分析接口
开发者通过数据分析接口,可获取到小程序的各项数据指标,便于进行数据存储和整理。数据分析详细功能介绍及指标解释参见数据分析文档。
相关接口
微信小程序 附近的小程序
附近的小程序
概述
附近的小程序 API,提供给需快速批量创建附近地点的小程序开发者使用,使用前请先调高附近地点额度。 调高附近地点额度申请方式如下:
下载 《调高地点额度申请表》,填写后发送至 placeofminiprogram@qq.com。
邮件主题为:“帐号名称”申请调高附近地点额度。审核通过后可调高额度。
管理接口
微信小程序 快递接口(商家查看)·文档说明
快递接口(商家必看)
1. 产品介绍
快递接口是微信官方为小程序提供的免费物流接口。接入后,你可使用本接口在多家快递公司获取电子面单单号等信息,再通过热敏打印机完成电子面单打印,即可将快件交给快递公司上门揽收。
2. 接入快递接口有什么好处
可批量生成电子面单本接口已对接多家快递公司下单接口,使用本接口可在各快递公司批量生成电子面单;
可回传物流轨迹给你经由快递接口下的单,微信会将物流轨迹返回给你,便于你实时掌握快件运输路径;
用户可收到物流通知经由快递接口下的单,微信官方会通过服务通知推送快件状态给用户,提升用户体验;
完全免费的官方接口快递接口为微信官方接口,统一对接多家物流公司,服务稳定,免费开放。
增加用户回流小程序入口接入快递接口后,用户可通过两个方式回访你的小程序:
3.目前支持的快递公司
4. 如何使用物流助手
前往微信公众平台→【物流助手】→【去接入】查看接入流程指引
步骤1:绑定签约的快递网点账号
在微信公众平台-小程序管理后台,点击【物流助手】→【去接入】→【去绑定】,选择和你签约过的物流公司,输入和网点签约时分配给你的账号密码,提交绑定;
绑定说明
(1) 若当前无账号密码,请先线下联系物流公司网点完成签约获得账号和密码,再进行绑定;(2) 上述绑定账号即为调用快递接口Api下单时,选择物流公司后需填写的Bizid;(3) 若事先没有和物流公司签约,准备发散单,则无需在该页面绑定物流公司,调用物流接口下单时填写现付的Bizid即可,下单成功后系统会通知快递员上门取件,运费现结。目前两家物流公司支持下散单,对应Bizid如下:
快递公司名称 | 快递公司ID | 现付的BizID |
---|---|---|
顺丰速运 | SF | SF_CASH |
德邦快递 | DB | DB_CASH |
步骤2:对接快递接口(商家必看)Api
(1)查看接口文档
(2)开发接口文档:你可自行开发或授权服务商开发,遇到问题可前往微信开放社区提问;
(3)测试下单:自行填写测试的收发货人信息和商品信息,看是否可成功调用本接口下单、成功生成电子面单、获取面单数据、打印面单和接收服务通知,全流程走通则说明接口已调通。
步骤3:打印电子面单
用快递接口Api下单后,可选择以下任一方式打印电子面单
- 使用微信物流助手对接的第三方打单软件打印面单,当前已支持的第三方打单软件为: 快递管家 点击获取对接指引更多第三方持续对接中,请期待
- 使用物流公司接口或收件员上门打印电子面单;
- 使用 getOrder 拉取电子面单 html,使用热敏打印机打印(可能存在格式兼容问题,需调试);
- 使用 getOrder 拉取电子面单的waybill_data,自行构造面单并打印(可能存在格式兼容问题,需调试);
- 安装使用微信打单PC软件:目前支持 Windows XP 及以上版本。点此下载
步骤4:快递员上门揽件
快递员上门揽件后,商家即可通过物流助手Api接收物流轨迹,微信会给用户推送已揽件、派件中、已签收/签收异常的服务通知,便于用户了解运单轨迹。
附录:快递接口流程图
微信小程序 快递接口(快递公司查看)
微信物流助手(快递侧)
物流助手,帮助有物流需求的开发者,快速高效对接多家物流公司。对接后用户可通过微信服务通知接收实时物流状态,提升用户体验。
产品优势
- 承接微信生态订单:通过微信统一接口,一次性服务微信生态内有寄件需求的商户。
- 提升用户回访:关键物流状态会通过微信服务通知发送给用户,用户点击后可回访快递公司小程序查看该订单的物流状态或进行后续操作。
接入说明
目前物流助手采用定向邀请方式接入物流公司。
接入准备
1. 小程序
用户收到轨迹更新消息后,可以间接跳转到快递小程序的轨迹详情页。至少需要提供两个页面:
- 快递轨迹详情页,路径可以参考pages/info/info?from=wx&no=12345678901234。微信做跳转时,会传入运单号。
- 快递投诉页面
2. 小程序事件服务
事件服务用于接收微信的推送,目前有审核商户、查询余额、下单、取消运单等事件。
3. 面单模板和示例
标注各个区域的尺寸、字号等。可参考模板示例
相关接口
相关事件
微信小程序 即时配送接口(商家查看)·概述
即时配送接口(商家查看)
1. 概述
即时配送接口,微信官方免费接口,旨在解决餐饮、生鲜、超市等小程序的外卖配送需求。接入后小程序商家可通过统一的接口获得多家配送公司的配送服务,提高经营效率。
2. 接入有什么好处
满足多品类配送需求可满足餐饮、生鲜、商超等多品类的配送需求
接口完全免费即时配送接口是官方提供的基础能力,完全免费开放
提升用户收货体验配送详情将通过微信服务通知下发给用户,提升收货体验。服务通知包括骑手已接单,骑手已取货、配送中,配送完成和配送异常四种状态
统一对接节约成本本接口已统一对接多家配送公司下单接口,可直接生成配送单
增加用户回访小程序入口配送详情的服务通知可跳转商家小程序,提升用户回访率
3. 支持的配送公司
4. 对接流程
前提:商家需先和配送公司已达成合作关系,签约了账号才可使用本接口下单。
例如:选择闪送下单,需事先和闪送沟通,在闪送创建一个合作账号以后,再来对接微信即时配送Api。
步骤1:登录微信公众平台,授权绑定配送公司的签约账号,流程拆解为:
(1)商家登录微信公众平台,点击右侧菜单【物流助手】——点击【即时配送】tab——去接入;(2)选择已经有合作账号的配送公司,如合作公司为闪送,跳转闪送的授权登录页面,输入在闪送的合作账号和密码后,授权登录;(3)合作的运力公司返回授权结果,商家后续即可使用该授权过的合作账号下单。
步骤2:对接即时配送Api(商家查看),预计需要2-3天
(1)查看接口文档(2)开发接口文档:你可自行开发或授权服务商开发,遇到问题可前往微信开放社区提问;
步骤3:测试联调
我们提供了稳定的沙盒环境供你开发过程进行调试,请先在沙盒环境调试完毕后再正式调用接口发单,测试指引需补充。
步骤4:上线发单
调试通过后即可上线,骑手接单后,你和用户均可接收配送详情的推送。
微信小程序 广告·Banner 广告
Banner 广告
小程序广告流量主操作指引:文档地址
开发者可以使用 ad 组件创建 Banner 广告组件,Banner 广告组件在创建后会自动拉取广告数据并显示。
广告尺寸设置
Banner 广告不允许直接设置样式属性,默认宽度为100%(width: 100%),高度会自动等比例计算,因此开发者可以设置广告外层组件的宽度调整广告的尺寸。 广告外层组件的宽度不允许小于300px,当宽度小于300px时,Banner 广告的宽度会强制调整为300px。
/* 外层组件的宽度可设置成100%或具体数值 */
.adContainer {
width: 100%;
}
<view class="adContainer">
<ad unit-id="xxxx"></ad>
</view>
广告事件监听
Banner 广告在创建后会自动拉取广告。开发者可以通过 ad 组件的 onload 和 onerror 事件监听广告拉取成功或失败,可以通过 onclose 事件监听广告被关闭。
<view class="adContainer">
<ad unit-id="xxxx" bindload="adLoad" binderror="adError" bindclose="adClose"></ad>
</view>
Page({
adLoad() {
console.log('Banner 广告加载成功')
},
adError(err) {
console.log('Banner 广告加载失败', err)
},
adClose() {
console.log('Banner 广告关闭')
}
})
广告定时刷新
开发者可以在创建 Banner 广告时传入 ad-intervals 参数实现广告的定时刷新,ad-intervals 参数为数字类型,单位为秒。注意:自动刷新的间隔不能低于30秒,因此 ad-intervals 的参数值必须大于或等于30。
<view class="adContainer">
<ad unit-id="xxxx" ad-intervals="30"></ad>
</view>
微信小程序 小程序搜索·优化指南
小程序搜索优化指南
爬虫访问小程序内页面时,会携带特定的 user-agent "mpcrawler" 及场景值:1129
判断请求是否来源于官方搜索爬虫的方法:
签名算法与小程序消息推送接口的签名算法一致。
参数在请求的header里设置,分别是: X-WXApp-Crawler-Timestamp X-WXApp-Crawler-Nonce X-WXApp-Crawler-Signature
签名流程如下: 1.将token、X-WXApp-Crawler-Timestamp、X-WXApp-Crawler-Nonce三个参数进行字典序排序 2.将三个参数字符串拼接成一个字符串进行sha1加密 3.开发者获得加密后的字符串可与X-WXApp-Crawler-Signature对比,标识该请求来源于微信
1. 小程序里跳转的页面 (url) 可被直接打开。
小程序页面内的跳转url是我们爬虫发现页面的重要来源,且搜索引擎召回的结果页面 (url) 是必须能直接打开,不依赖上下文状态的。 特别的:建议页面所需的参数都包含在url
2. 页面跳转优先采用navigator组件。
小程序提供了两种页面路由方式:a. navigator 组件b. 路由 API,包括 navigateTo / redirectTo / switchTab / navigateBack / reLaunch 建议使用 navigator 组件,若不得不使用API,可在爬虫访问时屏蔽针对点击设置的时间锁或变量锁。
3. 清晰简洁的页面参数。
结构清晰、简洁、参数有含义的 querystring 对抓取以及后续的分析都有很大帮助,但是将 JSON 数据作为参数的方式是比较糟糕的实现。
4. 必要的时候才请求用户进行授权、登录、绑定手机号等。
建议在必须的时候才要求用户授权(比如阅读文章可以匿名,而发表评论需要留名)。
5. 我们不收录 web-view 中的任何内容。
我们暂时做不到这一点,长期来看,我们可能也做不到。
6. 利用 sitemap 配置引导爬虫抓取,同时屏蔽无搜索价值的路径。
https://www.w3cschool.cn/weixinapp/weixinapp-cspq38rh.html
7. 设置一个清晰的标题和页面缩略图。
页面标题和缩略图对于我们理解页面和提高曝光转化有重要的作用。 通过 wx.setNavigationBarTitle 或 自定义转发内容 onShareAppMessage 对页面的标题和缩略图设置,另外也为 video、audio 组件补齐 poster / poster-for-crawler 属性。
8. 使用页面路径推送能力
可极大丰富微信可以收录的内容,进而提高小程序内容的曝光机会。请参考:
https://www.w3cschool.cn/weixinapp/weixinapp-it7838x9.html
微信小程序 小程序直播·接入说明
小程序直播
小程序直播是微信官方提供的商家经营工具。通过调用该组件,商家可以在小程序中实现直播互动与商品销售闭环。
按照下面的使用说明接入,在你的小程序中引入直播组件即可实现直播功能。使用过程中如遇到问题,可在小程序直播社区发帖交流。
使用方法说明
1. 【直播组件】如何引入
版本限制:微信客户端版本 7.0.7 及以上(基础库版本2.9.x及以上支持同层渲染)可以观看直播及使用直播间的功能,低版本刚进入直播间时会提示用户升级微信客户端版本(低版本只能观看直播,无法使用直播间的功能)。
支持在主包或分包内引入【直播组件】 live-player-plugin 代码包(注:直播组件不计入代码包体积),项目根目录的 app.json 引用,示例代码如下:
(1) 主包引入
"plugins": {
"live-player-plugin": {
"version": "1.1.4", // 注意填写该直播组件最新版本号,微信开发者工具调试时可获取最新版本号(复制时请去掉注释)
"provider": "wx2b03c6e691cd7370" // 必须填该直播组件appid,该示例值即为直播组件appid(复制时请去掉注释)
}
}
(2) 分包引入
"subpackages": [
{
"plugins": {
"live-player-plugin": {
"version": "1.1.4", // 注意该直播组件最新版本号,微信开发者工具调试时可获取最新版本号(复制时请去掉注释)
"provider": "wx2b03c6e691cd7370" // 必须填该直播组件appid,该示例值即为直播组件appid(复制时请去掉注释)
}
}
}
]
2. 【直播组件】如何使用
按第1步的方法把组件代码包配置引入后,即可直接通过链接地址跳转到直播组件页面(即为进直播间页面)链接地址需要带上直播房间 id;房间 id 可通过下面 获取直播房间列表 API 获取。
示例代码如下:
(1) 使用 navigator 组件跳转进入直播间
index.js
let roomId = [直播房间id] // 填写具体的房间号,可通过下面【获取直播房间列表】 API 获取
let customParams = encodeURIComponent(JSON.stringify({ path: 'pages/index/index', pid: 1 })) // 开发者在直播间页面路径上携带自定义参数(如示例中的path和pid参数),后续可以在分享卡片链接和跳转至商详页时获取,详见【获取自定义参数】、【直播间到商详页面携带参数】章节(上限600个字符,超过部分会被截断)
this.setData({
roomId,
customParams
})
index.wxml
<navigator url="plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id={{roomId}}&custom_params={{customParams}}"></navigator>
// 其中wx2b03c6e691cd7370是直播组件appid不能修改
(2) 使用 navigateTo 方法跳转进入直播间
index.js
let roomId = [直播房间id] // 填写具体的房间号,可通过下面【获取直播房间列表】 API 获取
let customParams = encodeURIComponent(JSON.stringify({ path: 'pages/index/index', pid: 1 })) // 开发者在直播间页面路径上携带自定义参数(如示例中的path和pid参数),后续可以在分享卡片链接和跳转至商详页时获取,详见【获取自定义参数】、【直播间到商详页面携带参数】章节(上限600个字符,超过部分会被截断)
wx.navigateTo({
url: `plugin-private://wx2b03c6e691cd7370/pages/live-player-plugin?room_id=${roomId}&custom_params=${customParams}`
})
// 其中wx2b03c6e691cd7370是直播组件appid不能修改
通过该链接可跳转到直播组件页面(当前页面入口仅开放‘live-player-plugin’)。
示例效果图如下:
直播组件和接口
【组件接口】
通过在主包/分包中引入直播组件,开发者可以很方便的实现订阅、获取直播状态、获取用户openid以及获取分享卡片链接参数等功能。
【服务端接口】
服务端接口包含直播间接口和商品管理接口。
- 直播间管理接口是小程序直播提供给开发者对直播间进行批量操作的接口能力。开发者可以批量创建直播间,获取回放源视频,获取直播间列表等。
- 商品管理接口是小程序直播提供给开发者对直播商品进行批量操作的接口能力。开发者可以对商品批量进行添加、提审、删除以及更新等操作。
类别 | 名称 | 功能说明 |
---|---|---|
组件接口 | 订阅组件 subscribe | 用户进入直播间内,可对一场未开播的直播进行单次订阅,开播时直播组件会自动下发开播提醒给用户 |
获取直播状态 getLiveStatus | 首次获取立马返回直播状态,往后间隔1分钟或更慢的频率去轮询获取直播状态 | |
获取用户openid参数getOpenid | 在直播组件版本 1.1.4 及以上版本通过该接口获取用户openid参数 | |
获取分享卡片链接参数getShareParams | 在直播组件版本 1.1.4 及以上版本通过该接口获取以下参数,开发者可以根据这些参数建立用户、直播间、商品之间的映射关系 | |
直播小窗控制参数 close_picture_in_picture_mode | 通过参数设置是否关闭小窗 | |
携带参数( 直播间到商详页面, 从群分享卡片返回直播间 | 直播组件版本 1.1.4 及以上支持携带以下参数,可用这些参数建立用户、直播间、商品之间的映射关系。 | |
服务端接口 | 创建直播间 | 该接口可直接创建直播间,创建成功后直播间将在直播间列表展示 |
后台获取直播房间列表 | 该接口可获取直播房间列表 | |
后台获取回放源视频 | 该接口可在直播结束后拿到回放源视频 | |
往指定直播间导入已入库商品 | 调用此接口往指定直播间导入已入库的商品 | |
商品添加并提审 | 调用此接口上传并提审需要直播的商品信息,审核通过后商品录入【小程序直播】商品库 | |
撤回商品审核 | 调用此接口,可撤回直播商品的提审申请,消耗的提审次数不返还 | |
重新提交商品审核 | 调用此接口可以对已撤回提审的商品再次发起提审申请 | |
删除商品 | 调用此接口,可删除【小程序直播】商品库中的商品,删除后直播间上架的该商品也将被同步删除,不可恢复 | |
更新商品 | 调用此接口可以更新商品信息,审核通过的商品仅允许更新价格类型与价格,审核中的商品不允许更新,未审核的商品允许更新所有字段, 只传入需要更新的字段 | |
获取商品状态 | 调用此接口可获取商品的信息与审核状态 | |
获取商品列表 | 调用此接口可获取商品列表 |
微信小程序 生码
生码
微信后台向业务方请求二维码源数据,前端可以根据源数据生成乘车码。
1、 请求参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
appid | string | Y | 小程序 |
appidmch_id | string | Y | 支付商户号 |
nonce_str | string | Y | 随机字符串 |
encrypted_data | string | Y | 使用AESCBCPKCS7PADDING |
iv | string | Y | 用于解密的IV(base64后) |
sign | string | Y | 1~5字段的签名 |
encrypted_data解密后的数据
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
openid | string | Y | 用户 |
idcard_id | string | Y | 第三方用户id(有注册环节则有) |
user_public_key | string | Y | 用户公钥,16进制格式,共130字节 |
2、 返回参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
errcode | int | Y | 0为成功 |
errmsg | string | N | 错误信息 |
nonce_str | string | Y | 原样带回 |
encrypted_data | string | Y | 使用AESCBCPKCS7PADDING |
encrypted_data解密后的数据
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
base64_svr_data | string | Y | 交通部乘车码标准1~15字段拼接的二进制流,base64后便于网络传输 |
3、 示例代码
请求:
{"appid":"test","mch_id":"123456","nonce_str":"abcdefg","encrypted_data":"jfiwajeofjiefef","iv":"afweifwefe"}
encrypted_data解密后:
{"openid":"1234","user_public_key":"123123","card_id":"2342343"}
返回:
{"errcode":0,"nonce_str":"abcdefg","encrypted_data":"jfiwajeofjiefef","iv":"afweifwefe"}
encrypted_data解密后的数据:
{"base64_svr_data":"xxafdafd"}
扫码支付
(1)支付回调接口
业务方调用微信扣费接口之后,接收扣费结果通知。
1、 请求参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
appid | string | Y | 小程序 |
appidmch_id | string | Y | 支付商户号 |
nonce_str | string | Y | 随机字符串 |
encrypted_data | string | Y | 使用AESCBCPKCS7PADDING |
iv | string | Y | 用于解密的IV |
sign | string | Y | 1~5字段的签名 |
解密后的参数如下:
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
openid | string | Y | 用户在小程序appid下的openid |
bank_type | string | Y | 支付类型 |
total_fee | int | Y | 支付总额,单位为分 |
trade_state | string | Y | 支付状态:SUCCESS/FAIL |
trade_msg | string | N | 支付失败时返回 |
transaction_id | string | Y | 微信支付单号 |
out_trade_no | string | Y | 乘车码业务方单号 |
attach | string | N | 扣费API的入参,原样带回 |
time_end | string | Y | 支付完成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010 |
qrcode | string | Y | 二维码 |
2、 返回参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
errcode | int | Y | 0为成功 |
errmsg | string | N | 错误信息 |
nonce_str | string | Y | 原样带回 |
3、 示例代码
{"appid":"test","mch_id":"123456","nonce_str":"abcdefg","encrypted_data":"jfiwajeofjiefef","iv":"afweifwefe"}
解密后数据:
{"openid":"fafwefawef","bank_type":"CFT","total_fee":100,"trade_state":"SUCCESS",...}
(2)微信扣费接口(微信API接口)
用于接收业务方依据扫码接口获取到的信息对用户进行免密扣费。
1、请求参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
qrcode | string | Y | 乘车码数据,需要base64 |
total_fee | int | Y | 支付总额,分为单位(优惠后) |
original_fee | int | Y | 支付总额,分为单位(优惠前) |
machine_ip | string | N | 扫码机接入IP |
machine_latitude | float | N | 扫码机GPS纬度 |
machine_longitude | float | N | 扫码机GPS经度 |
body | string | Y | 公交代扣/地铁代扣 |
start_time | string | Y | 上车/乘车时间,如20091225091010 |
end_time | string | N | 下车时间,格式同上,适用于二次刷码的场景 |
line_name | string | Y | 乘车线路 |
trade_scene | string | Y | METRO/BUS |
start_qrcode | string | N | 二次刷码时,传入首次刷码使用的二维码 |
out_order_no | string | N | 业务方自定义订单号,需要保证唯一 |
attach | string | N | 业务方自定义数据,对账单和查询接口会原样返回 |
2、 返回参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
errcode | int | 32Y | 返回码 |
errmsg | string | N | 返回信息 |
3、 示例代码
入参:
{"qrcode":"afefawefwef",....}
返回
{"errcode":0,....}
微信小程序 查询线路接口
查询线路接口
查询设置的公交/地铁线路。
1、请求参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
type | int | Y | 类型 0-地铁 1-公交 |
2、返回参数
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
errcode | int | Y | 错误码 |
errmsg | string | Y | 错误信息 |
results | object | N | 线路信息 |
其中results的内容如下:
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
line_list | away | Y | 线路信息 |
其中results.line_list的每一项内容如下:
参数名称 | 类型 | 必选 | 备注 |
---|---|---|---|
id | int | Y | 线路的唯一id |
start_station | string | Y | 起点站 |
end_station | string | Y | 终点站 |
line_name | string | Y | 线路名称 |