提交 9d4cd438 编写于 作者: DCloud_JSON's avatar DCloud_JSON

Merge branch 'master' of https://gitee.com/dcloud/unidocs-zh

const path = require('path');
const { slugify } = require('@vuepress/shared-utils')
const translatePlugin = require('./markdown/translate')
const headerPlugin = require('./markdown/header')
......@@ -74,6 +75,12 @@ const config = {
.use(require('./markdown/normallizeLink'))
}
},
chainWebpack(config, isServer) {
config.resolve.alias.set(
'@theme-config',
path.resolve(process.cwd(), 'docs/.vuepress/config')
)
},
plugins: [
["vuepress-plugin-juejin-style-copy", copyOptions]
]
......
......@@ -140,6 +140,11 @@ export default {
"state": 1,
"prefix": "群22"
},
{
"number": "599958679",
"state": 1,
"prefix": "群23"
},
{
"number": "672494800",
"state": 1,
......@@ -180,11 +185,6 @@ export default {
"state": 1,
"prefix": "群31"
},
{
"number": "166188631",
"state": 1,
"prefix": "群32"
},
{
"number": "498071674",
"state": 1,
......@@ -201,10 +201,11 @@ export default {
"prefix": "群35"
},
{
"number": "599958679",
"number": "166188631",
"state": 0,
"prefix": "23"
"prefix": "32"
}
],
joinQQGroupHref: 'https://qm.qq.com/cgi-bin/qm/qr?k=JpUEAl4qkVGeAihWvgbzHRUoeZ_xBF5S&jump_from=webapi'
joinQQGroupHref: 'https://qm.qq.com/cgi-bin/qm/qr?k=LXbfShA9QaL21SAH6Wi-W69w8baKLDCU&jump_from=webapi'
}
......@@ -5,6 +5,7 @@ var website_ZH_host = 'uniapp.dcloud.net.cn'
var website_EN_host = 'en.uniapp.dcloud.io'
var website_ZH = 'https://' + website_ZH_host;
var website_EN = 'https://' + website_EN_host;
var _hmt = _hmt || [];
// window.__UNI_DOCS_ZH_KEY__ = 'unidocs-zh-language'
......
......@@ -48,6 +48,7 @@ mapContext
- 在组件中,必须在 `mounted` 中调用。
- nvue没有`$getAppMap()`,请使用`createMapContext`
- `uni-app`中使用原生地图无需提供占位div,得到`$getAppMap()`后直接js使用即可。
- `openMapApp` iOS 暂不支持,后续补充
**getCenterLocation 的 OBJECT 参数列表**
......@@ -252,7 +253,7 @@ mapContext
示例代码
```
```js
MapContext.on('markerClusterCreate', (res) => {})
MapContext.on('markerClusterClick', (res) => {})
```
......@@ -262,7 +263,7 @@ mapContext
缩小地图可看到多个 marker 合并为 1 个并显示聚合数量,放大地图后恢复
```
```html
<template>
<view class="content">
<map id="map" class="map" :show-location="true" :latitude="latitude" :longitude="longitude"></map>
......
......@@ -80,7 +80,7 @@ var animation = uni.createAnimation({
|scale|sx,[sy]|一个参数时,表示在X轴、Y轴同时缩放sx倍数;两个参数时表示在X轴缩放sx倍数,在Y轴缩放sy倍数|
|scaleX|sx|在X轴缩放sx倍数|
|scaleY|sy|在Y轴缩放sy倍数|
|scaleZ|sz|在Z轴缩放sy倍数|
|scaleZ|sz|在Z轴缩放sz倍数|
|scale3d|(sx,sy,sz)|在X轴缩放sx倍数,在Y轴缩放sy倍数,在Z轴缩放sz倍数|
偏移:
......@@ -89,8 +89,8 @@ var animation = uni.createAnimation({
|---|---|---|
|translate|tx,[ty]|一个参数时,表示在X轴偏移tx,单位px;两个参数时,表示在X轴偏移tx,在Y轴偏移ty,单位px。|
|translateX|tx|在X轴偏移tx,单位px|
|translateY|ty|在Y轴偏移tx,单位px|
|translateZ|tz|在Z轴偏移tx,单位px|
|translateY|ty|在Y轴偏移ty,单位px|
|translateZ|tz|在Z轴偏移tz,单位px|
|translate3d|(tx,ty,tz)|在X轴偏移tx,在Y轴偏移ty,在Z轴偏移tz,单位px|
倾斜:
......
......@@ -7,4 +7,3 @@
* [uni.scss](collocation/uni-scss.md)
* [App.vue](collocation/App.md)
* [main.js](collocation/main.md)
* [plugin.json 生成小程序插件](collocation/miniprogram-plugin.md)
## 互动广告
## 简介
互动广告是DCloud联合三方服务商为开发者提供新的广告场景增值服务。开发者在App中放置入口,用户点击入口参与权益化、趣味性的活动。
**平台差异说明**
|App |H5 |微信小程序 |支付宝小程序 |百度小程序 |字节跳动小程序 |QQ小程序 |快应用 |360小程序|快手小程序 |京东小程序 |
|:-: |:-: |:-: |:-: |:-: |:-: |:-: |:-: |:-: |:-: |:-: |
|√(3.5.5+) |√(3.5.5+) |√(3.5.5+) |x |x |x |x |x |x |x |x |
**开通配置广告**
[开通广告步骤详情](https://uniapp.dcloud.net.cn/uni-ad.html#start)
## 语法
`<ad-interactive></ad-interactive>`
**属性说明**
|属性名 |类型 |说明 |
|:- |:- |:- |
|adpid |String |广告位id |
|open-page-path |String |点击广告后打开的页面路径,[详见](#openpagepath)|
|v-slot:default="{data, loading, error}"| |作用域插槽,[详见](#vslot) |
|@load |EventHandle|加载成功事件 |
|@error |EventHandle|加载失败事件 |
### `v-slot:default="{data, loading, error}"` 属性说明@vslot
|属性名 |类型 |说明 |
|:- |:- |:- |
|data |Object |广告位数据, {imgUrl } |
|loading|Boolean|加载状态 |
|error |Object |加载错误, {errCode, errMsg}|
### 简单示例
```html
<template>
<view>
<!-- 用户点击组件后将打开广告页面,参见属性 open-page-path -->
<ad-interactive adpid="1000000001" v-slot:default="{data, loading, error}" open-page-path="/pages/ad-interactive-webview/ad-interactive-webview">
<view v-if="data">
<!-- 可以自定义此图片,组件提供了默认素材,通过 uni-ad 后台配置 -->
<image :src="data.imgUrl" style="width: 128px; height: 72px;"></image>
</view>
</ad-interactive>
</view>
</template>
```
注意:需要添加依赖页面 [open-page-path](#openpagepath)
### 完整示例
```html
<template>
<view class="content">
<!-- 用户点击组件后将打开广告页面,参见属性 open-page-path -->
<ad-interactive adpid="1000000001" v-slot:default="{data, loading, error}" @load="onadload" @error="onaderror" open-page-path="/pages/ad-interactive-webview/ad-interactive-webview">
<view v-if="loading">Loading</view>
<view v-if="data">
<!-- 可以自定义此图片,组件提供了默认素材,通过 uni-ad 后台配置 -->
<image :src="data.imgUrl" style="width: 128px; height: 72px;"></image>
</view>
<view v-if="error">{{error.errMsg}}</view>
</ad-interactive>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
onadload(e) {
console.log('广告数据加载成功');
},
onaderror(e) {
// 广告加载失败
console.log("onaderror", e.errCode, e.errMsg);
}
}
}
</script>
```
### open-page-path 页面代码@openpagepath
组件的 `open-page-path` 属性所需页面,点击广告后将打开此页面
在项目的pages目录上右键,新增 `ad-interactive-webview.vue` 页面,并复制替换为下面代码
```html
<template>
<web-view :src="url"></web-view>
</template>
<script>
export default {
data() {
return {
url: ''
}
},
onLoad(options) {
if (options && options.url) {
this.url = decodeURIComponent(options.url);
}
}
}
</script>
```
## 接入步骤
1. 开通并[申请](https://uniapp.dcloud.net.cn/)广告位
3. 在需要展示广告的地方放入 `<ad-interactive></ad-interactive>` 组件代码,此广告可作为悬浮红包使用,设置组件样式 fixed 定位即可
4. 在项目中新增 [ad-interactive-webview](#openpagepath) 页面
运行到微信小程序时需要添加request合法域名和业务域名白名单
1. 登陆 [微信公众平台](https://mp.weixin.qq.com/),左侧栏找到 `开发管理` 并点击 开发设置->服务器域名
2. 新增 `request合法域名`: `https://wxac1.dcloud.net.cn`
3. 新增 `业务域名`: `https://engine.dcad01.com`
......@@ -89,7 +89,7 @@ HBuilderX 中打开配有引用图标指示的文件,会打开原始地址。
import {test} from '@/uni_modules/xx-yy/js_sdk/test.js'
```
- 如果要使用uni_modules中的页面,[见下](?id=pages-init)
- 如果要使用uni_modules中的页面,[见下](#pages-init)
#### 安装uni_modules插件依赖
......
......@@ -6,6 +6,8 @@
全局安装vue-cli
> 目前仍推荐使用 vue-cli 4.x,对于 vue-cli 5.x / Webpack 5 的支持情况参考 [#3723](https://github.com/dcloudio/uni-app/issues/3723)
```shell
npm install -g @vue/cli@4
```
......@@ -127,22 +129,94 @@ HBuilderX 2.7.10+ 版支持
2. build 模式会将代码进行压缩,体积更小更适合发布为正式版应用;
3. 进行 [环境判断](/worktile/running-env?id=判断平台) 时,dev 模式 process.env.NODE_ENV 的值为 development,build 模式 process.env.NODE_ENV 的值为 production。
## 使用cli创建项目和使用HBuilderX可视化界面创建项目有什么区别
## cli创建项目和HBuilderX可视化界面创建项目的区别@clidiff
- cli创建的项目,是传统的node项目结构。工程代码在src目录下,编译器在项目下,编译结果在dist目录下。
- HBuilderX可视化创建的项目,是一种免node开发概念。工程代码在项目目录下,编译器在HBuilderX目录下而不是项目下,编译结果在项目的unpackage目录下。
有些习惯了cli的开发者,使用HBuilderX可视化模式时不适应。讲解下它们的差别以及为什么HBuilderX提供了多种方式。
### cli创建的项目,也可以拖入HBuilderX编辑
首先HBuilderX作为通用编辑器,兼容传统的cli方式开发。不止uni-app的cli,其他框架的cli也可以拖入HBuilderX。
也就是HBuilderX里可以使用可视化界面创建项目,也可以使用cli命令行创建项目,都可以达到和uni-app更好协作的目的。比如pages.json跳转和提示、manifest可视化界面、条件编译、rpx等css单位...众多 for uni-app 的优化都可以使用。
这些是HBuilderX的特点,和项目结构无关。
### 如想用其他ide开发uni-app,只能使用cli模式
很好理解。因为其他ide没有内置uni-app的编译器,所以其他ide开发uni-app,只能把编译器安装在项目下,也就是cli创建的项目格式。
cli项目可以使用多种ide开发,但ide之间有区别:
- HBuilderX为uni-app做了大量优化,其他ide搭配uni-app使用也可以用,但没有为uni-app优化过
- 其他ide没有uni-app的app和uniCloud的运行、调试工具。这些工具在HBuilderX里。如开发app和uniCloud,必须使用HBuilderX。
### 可视化方式的区别
HBuilderX可视化创建、运行、发布项目,底层调用的也是npm的run、build等命令。只是编译器不在项目下,而是在HBuilderX的目录下。
### 为什么要提供HBuilderX可视化模式
1. 为了提升易用性,较低门槛
很多开发者对node不熟悉、对命令行有心理抵触。不要想当然认为所有开发者都会node,HBuilder有几百万开发者,其中掌握node的开发者连一半都占不到。
2. npm、github网络经常出问题
使用cli创建项目时,cli需要从npm安装,预置的项目模板选择从github下载,这些经常因为网络问题卡壳。可视化创建项目不存在这个问题。
3. 每个uni-app项目下都有一套编译器太麻烦
一个HBuilderX的开发者有非常多个uni-app项目,如果每个项目下放一套编译器,会有很多不合理:
- 创建项目会非常慢
- 非常占用磁盘空间(uni-app的编译器有数万个文件)
- 升级麻烦,兼容性问题多。cli项目下的编译器不会跟随HBuilderX升级而升级,只能开发者手敲npm命令升级。当HBuilderX升级后,有的uni-app项目的编译器未升级,有的升级了,报错时开发者很容易懵圈,给DCloud报bug时DCloud也懵圈。让ide版本、编译器版本、uni-app运行时这3者的版本保持一致,会减少非常多的问题。
把编译器内置到HBuilderX中,开发者创建项目时只需关心自己的业务代码,工程结构干净清爽。
各家小程序也都是这么做的,编译器在小程序开发工具里,创建项目时不会在项目下带一套编译器(小程序也是要把wxml等编译为js的)。
4. less、scss、ts等编译器的自动安装
- 如果使用cli项目,那么less、scss、ts等编译器需要自己手动敲npm命令安装。由于DCloud官方不会和每种预编译器的每个版本都做兼容性测试,如果你使用了较低的预编译器版本,可能会无法正常运行,这需要你自己排查
- 如果使用HBuilderX可视化创建项目,这些编译器会按需自动安装,并且是DCloud官方测试过版本兼容性的。开发者只需在你的代码中使用这些预编译技术,剩下的HBuilderX会自动搞定。
5. 可视化更高效
HBuilderX提供的免node开发,除了易用,还更高效。
- 新建项目:`Ctrl+N`
- 运行项目:`Ctrl+R`
- 发行项目:`Ctrl+U`
这比启动终端,移动焦点到终端窗口,敲命令快多了。
在uni-app中,终端命令比传统web开发要多、要长,还要敲运行平台参数的,选择你要运行到web还是app或某家小程序。
综上,
如果你习惯node,也能接受和管理好每个项目下一套编译器的方式,清楚上述利弊,那你可以选择cli创建项目。
至于ide,肯定还是HBuilderX搭配uni-app开发更高效。
如果你习惯其他ide,开发uni-app低效也无所谓,那也可以用其他ide。但注意至少运行调试app和uniCloud时,还得把HBuilderX开着,就像开着微信小程序工具调试那样。
在DCloud内部,uni-app和HBuilderX是不同的团队。
- 对于uni-app来说,它面对所有ide一视同仁。它兼容node生态,支持d.ts语法提示
- 对于HBuilderX来说,uni-app是一等公民。HBuilderX为uni-app做了很多优化
#### 编译器的区别
### 其他注意事项
* ``cli`` 创建的项目,编译器安装在项目下。并且不会跟随HBuilderX升级。如需升级编译器,可以使用 [@dcloudio/uvm](https://www.npmjs.com/package/@dcloudio/uvm) 管理编译器的版本,如 ```npx @dcloudio/uvm```
* HBuilderX可视化界面创建的项目,编译器在HBuilderX的安装目录下的plugin目录,随着HBuilderX的升级会自动升级编译器。
* 已经使用``cli``创建的项目,如果想继续在HBuilderX里使用,可以把工程拖到HBuilderX中。注意如果是把整个项目拖入HBuilderX,则编译时走的是项目下的编译器。如果是把src目录拖入到HBuilderX中,则走的是HBuilderX安装目录下plugin目录下的编译器。
* ``cli``版如果想安装less、scss、ts等编译器,需自己手动npm安装。在HBuilderX的插件管理界面安装无效,那个只作用于HBuilderX创建的项目。
#### 开发工具的区别
* ``cli``创建的项目,内置了d.ts,同其他常规npm库一样,可在[vscode](https://ask.dcloud.net.cn/article/36286)[webstorm](https://ask.dcloud.net.cn/article/36307)等支持d.ts的开发工具里正常开发并有语法提示。
* 使用HBuilderX创建的项目不带d.ts,HBuilderX内置了uni-app语法提示库。如需把HBuilderX创建的项目在其他编辑器打开并且补充d.ts,可以在项目下先执行 ``npm init``,然后``npm i @types/uni-app -D``,来补充d.ts。
* 但vscode等其他开发工具,在vue或uni-app领域,开发效率比不过HBuilderX。详见:[https://ask.dcloud.net.cn/article/35451](https://ask.dcloud.net.cn/article/35451)
* HBuilderX创建的项目,一样可以使用npm,参考:[NPM 支持](/tutorial/page-script?id=npm支持)
* vscode等其他开发工具,在vue或uni-app领域,开发效率比不过HBuilderX。详见:[https://ask.dcloud.net.cn/article/35451](https://ask.dcloud.net.cn/article/35451)
* 发布App时,仍然需要使用HBuilderX。其他开发工具无法发布App,但可以发布H5、各种小程序。如需开发App,可以先在HBuilderX里运行起来,然后在其他编辑器里修改保存代码,代码修改后会自动同步到手机基座。
* 如果使用``cli``创建项目,那下载HBuilderX时只需下载23.31M的标准版即可。因为编译器已经安装到项目下了。
* 如果使用``cli``创建项目,HBuilderX插件列表中的uni-app编译器可以不安装
*`cli` 使用有疑问,欢迎扫码加入 uni-app 微信交流群讨论:
<br/><img src="https://img.cdn.aliyun.dcloud.net.cn/guide/uniapp/wx-barcode.png" width="250"/>
注意:HBuilderX创建的项目,一样可以使用npm,参考:[NPM 支持](/tutorial/page-script?id=npm支持)
......@@ -10,19 +10,17 @@
HBuilderX是通用的前端开发工具,但为`uni-app`做了特别强化。
下载后默认不包含`uni-app`插件,在运行或发行`uni-app`时,会提示安装`uni-app`插件,插件下载完成后方可使用。
## 创建uni-app
在点击工具栏里的文件 -> 新建 -> 项目:
在点击工具栏里的文件 -> 新建 -> 项目(快捷键`Ctrl+N`
<div align=center>
<img src="https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/b925a1c0-4f19-11eb-97b7-0dc4655d6e68.png"/>
</div>
选择`uni-app`类型,输入工程名,选择模板,点击创建,即可成功创建。
uni-app自带的模板有 Hello uni-app ,是官方的组件和API示例。还有一个重要模板是 uni ui项目模板,日常开发推荐使用该模板,已内置大量常用组件。
uni-app自带的模板有 默认的空项目模板、Hello uni-app 官方组件和API示例,还有一个重要模板是 uni ui项目模板,日常开发推荐使用该模板,已内置大量常用组件。
<div align=center>
<img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-a90b5f95-90ba-4d30-a6a7-cd4d057327db/d0cba1a3-c0cc-4095-a105-a4fea51857fe.jpg"/>
......@@ -31,9 +29,9 @@ uni-app自带的模板有 Hello uni-app ,是官方的组件和API示例。还
开发者也可以使用`cli`方式创建项目,另见[文档](https://uniapp.dcloud.io/quickstart-cli.html)
差别是:HBuilderX创建的项目根目录就是源码,可直接编辑。dist在unpackage目录下。uni-app的编译器在HBuilderX的插件目录下,跟随HBuilderX升级而一起升级。
差别是:HBuilderX创建的项目根目录就是源码,可直接编辑。uni-app的编译器在HBuilderX的插件目录下,跟随HBuilderX升级而一起升级。
而cli创建的项目,源码在src下。uni-app的编译器也安装在项目下,不会跟随HBuilderX版本升级而升级,需要自己手动npm update。
如果开发者习惯于node模式的项目,对HBuilderX可视化方式感到困惑,可另行参考文档:[## cli创建项目和HBuilderX可视化界面创建项目的区别](quickstart-cli.md#clidiff)
## 运行uni-app
......@@ -79,7 +77,7 @@ uni-app自带的模板有 Hello uni-app ,是官方的组件和API示例。还
* 支付宝/百度/字节跳动/360小程序工具,不支持直接指定项目启动并运行。因此开发工具启动后,请将 HBuilderX 控制台中提示的项目路径,在相应小程序开发者工具中打开。
* 如果自动启动小程序开发工具失败,请手动启动小程序开发工具并将 HBuilderX 控制台提示的项目路径,打开项目。
运行的快捷键是`Ctrl+r`
运行的快捷键是`Ctrl+R`
HBuilderX 还提供了快捷运行菜单,可以按数字快速选择要运行的设备:
<div align=center>
......
......@@ -3,7 +3,7 @@
建议第二步,通过[快速上手](https://uniapp.dcloud.io/quickstart-hx),亲身体验下uni-app。
建议第三步,看完[《uni-app官方教程》](https://ke.qq.com/course/3169971),出品人:DCloud,课时:共3节。
[a]({{ $themeConfig.domainName }})
#### 如果你熟悉h5,但不熟悉vue和小程序
1. 看完这篇[白话uni-app](http://ask.dcloud.net.cn/article/35657)
2. DCloud与vue合作,在[vue.js官网](https://cn.vuejs.org/v2/guide/)提供了免费视频教程,也可以直达教程地址:[https://learning.dcloud.io](https://learning.dcloud.io)
......
......@@ -109,7 +109,8 @@
* [前端安全专题](/tutorial/web-security.md)
* 小程序专题
* [组件与WXS](/tutorial/miniprogram-subject.md)
* [小程序插件](/tutorial/mp-weixin-plugin.md)
* [使用小程序插件](/tutorial/mp-weixin-plugin.md)
* [开发小程序插件](/tutorial/mp-weixin-plugin-dev.md)
* [一键上传微信平台](/tutorial/build/publish-mp-weixin-cli.md)
* 运行和调试
* [概述](run-and-debug.md)
......
......@@ -13,7 +13,7 @@
+ 不要将自定义基座提交平台审核。调试模式下不会处理合规问题。需要注意!
+ APP没有配置隐私与政策提示框。请认真阅读[Android平台隐私与政策提示框配置方法](https://ask.dcloud.net.cn/article/36937)配置你APP的隐私弹窗。
+ 配置隐私弹窗时一定要配置使用`template`模式。否则无法上架应用市场。应用内部自己实现的隐私弹窗也不行。一定要使用uni提供的隐私弹窗并使用`template`模式切记!
```
```json
//androidPrivacy.json
{
"version": "1",
......
......@@ -26,7 +26,7 @@
### X5内核能解决什么问题:
1. x5适配了rom的自定义主题字体,与原生字体保持一致。不会出现一个界面部分字体为原生字体、部分字体为webview字体的问题。之前系统webview在部分手机上不能适配rom自定义主题的字体
1. x5适配了rom的自定义主题字体,与原生字体保持一致。不会出现一个界面部分字体为原生字体、部分字体为webview字体的问题。之前系统webview在部分手机上不能适配rom自定义主题的字体。(注意:部分设备可能需要重新系统或不支持自定义主题字体)
2. 系统的webview有浏览器兼容问题,低端Android的webview有很多新语法都不支持。使用x5可以拉齐webview内核。对于5+App和wap2app,可以全部拉齐。对于uni-app,由于uni-app自带js引擎,在js和组件层面本身就不存在浏览器兼容问题,只有vue页面的css涉及浏览器兼容问题。如果你想使用比如sticky等新css语法,此时可通过x5拉齐。如果开发者比较注意,不使用太新的语法的话,其实此时x5在这方面没有用处
3. x5内核自带的video实现强于html的video,支持视频格式更多。(这个只能用于5+app和wap2app的html里的自带video,以及uni-app的web-view组件里的video。uni-app默认的video组件本身就是原生的,和x5无关)
4. 远程web页面防劫持是x5内核的一大亮点
......
......@@ -24,11 +24,17 @@ dSYM文件内容为:
因此统计平台也需要开发者上传 dsym 文件。
##### HBuilderX中云端打包配置生成符号表文件
#### HBuilderX中云端打包配置生成符号表文件
> HBuilderX3.2.23+版本新增支持云端打包支持生成iOS符号表 dsym 文件
> HBuilderX3.5.0+版本生成iOS符号表 dsym 文件配置项调整到原生App-云打包窗口
在HBuilderX中云端打包打开项目的manifest.json文件,在“App常用其它设置”界面中的勾选“生成iOS符号表(dsym)文件”:
在HBuilderX中菜单项 “发行” -> “原生App-云打包” 界面勾选“生成iOS符号表(dsym)文件”:
![](https://native-res.dcloud.net.cn/images/hx/dist/ios-dsym.png)
> HBuilderX 从 3.2.23 至 3.4.18 版本 在项目的 manifest.json 可视化界面中配置生成iOS符号表 dsym 文件
在HBuilderX中打开项目的manifest.json文件,在“App常用其它设置”界面中的勾选“生成iOS符号表(dsym)文件”:
![](https://img-cdn-aliyun.dcloud.net.cn/client/doc/ios/dsym-hx.png)
......
......@@ -173,7 +173,5 @@ plus.payment.getChannels((providers) => {
console.log("支付失败: " + JSON.stringify(e));
})
});
```
> 本文档意在介绍如何把uni-app项目编译为小程序插件,如果想了解如何在uni-app中引用和使用小程序插件,另见文档:[使用小程序插件](/tutorial/mp-weixin-plugin)
> 本文档意在介绍如何把uni-app项目编译为小程序插件,如果想了解如何在uni-app中引用和使用小程序插件,另见文档:[使用小程序插件](mp-weixin-plugin.md)
小程序插件规范由小程序厂商定义,插件是对一组 js 接口、自定义组件或页面的封装,用于嵌入到小程序中使用。
......
> 本文档意在介绍如何在uni-app中引用和使用小程序插件,如果想了解如何把uni-app项目编译为小程序插件,另见文档:[发布为小程序插件](/collocation/miniprogram-plugin)
> 本文档意在介绍如何在uni-app中引用和使用小程序插件,如果想了解如何把uni-app项目编译为小程序插件,另见文档:[发布为小程序插件](mp-weixin-plugin-dev.md)
#### 什么是小程序插件
#### 什么是小程序插件 @mp-plugin
小程序插件不同于小程序自定义组件。
......@@ -17,7 +17,7 @@
- [百度小程序动态库](https://smartprogram.baidu.com/docs/develop/framework/dynamiclib_use/)
- [QQ小程序插件](https://q.qq.com/wiki/develop/miniprogram/frame/plugins/)
#### 在uni-app中引入插件
#### 在uni-app中引入插件代码包 @import-mp-plugin
`manifest.json`中的各平台对应的字段内声明使用的插件,具体配置参照所用插件的开发文档
......@@ -60,7 +60,9 @@
- `HBuilder X 3.2.13+` 支持 `export` 字段,即小程序导出到插件。目前仅 微信小程序 和 支付宝小程序 支持
#### 在页面中使用
#### 在页面中使用插件 @page-import-mp-plugin
> 使用插件提供的自定义组件,和使用普通自定义组件的方式相仿。在 json 文件定义需要引入的自定义组件时,使用 plugin:// 协议指明插件的引用名和自定义组件名
在页面内使用插件内包含的组件需要在`pages.json`内对应页面的`style`节点下配置对应平台的`usingComponents``usingSwanComponents`,示例如下:
......@@ -107,7 +109,23 @@
```
#### 在分包内引入插件代码包
页面上使用。代码示例:
```html
<!-- 微信小程序和支付宝小程序 -->
<navigator url="plugin://myPlugin/hello-component">
Go to pages/hello-page!
</navigator>
<!-- 百度小程序 -->
<view class="container">
<view>下面这个自定义组件来自于动态库</view>
<!-- 这里的 'my-special-list' 就是本页面中对于此自定义组件的别名 -->
<my-special-list />
</view>
```
#### 在分包内引入插件代码包 @subpackages-import-mp-plugin
支付宝小程序、百度小程序不支持在分包内引入插件。此外如果项目使用了分包,在支付宝小程序内不可使用插件。本节内容仅针对微信小程序。
......@@ -137,7 +155,7 @@
* 不能从分包外的页面直接跳入分包内的插件页面,需要先跳入分包内的非插件页面、再跳入同一分包内的插件页面。
#### 可能遇到的问题
#### 可能遇到的问题 @mp-plugin-issue
* 某些插件可能会需要一些权限才能正常运行,请在`manifest.json`中的`mp-weixin`内配置`permission`[详见](https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#permission)
* 微信开发工具提示 “插件版本不存在”,可能是插件开发文档示例代码中使用的版本已经不存在,请在声明插件处更改版本
......
......@@ -326,19 +326,19 @@
## nvue 里使用 BindingX
## nvue 里使用 BindingX@bindingx
`uni-app` 是逻辑层和视图层分离的。此时会产生两层通信成本。比如拖动视图层的元素,如果在逻辑层不停接收事件,因为通信损耗会产生不顺滑的体验。
[BindingX](https://alibaba.github.io/bindingx/) 是weex提供的一种预描述交互语法。由原生解析BindingX规则,按此规则处理视图层的交互和动效。不再实时去js逻辑层运行和通信。
BindingX类似一种强化版的css,运行性能高,但没有js那样足够强的编程灵活性。
BindingX是一种规则,解析快,但没有js那样足够强的编程灵活性。
`uni-app` 内置了 BindingX,可在 `nvue` 中使用 BindingX 完成复杂的动画效果。
- 从HBuilderX 2.3.4起,`uni-app` 编译模式可直接引用 `uni.requireNativePlugin('bindingx')` 模块,weex 模式还需使用 npm 方式引用。
- BindingX demo示例可参考 BindingX 示例里 vue 的相关示例,将实验田里的 vue 代码拷贝到 `nvue` 文件里即可。
- BindingX demo示例可参考 BindingX 示例里 vue 的相关示例,将相关 vue 代码拷贝到 `nvue` 文件里即可。
##### 注意
......
## renderjs
`renderjs`是一个运行在视图层的js。它比[WXS](/tutorial/miniprogram-subject.html#wxs)更加强大。它只支持app-vue和h5
`renderjs`是一个运行在视图层的js。它比[WXS](miniprogram-subject.md#wxs)更加强大。它只支持app-vue和web
`renderjs`的主要作用有2个:
- 大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力
- 在视图层操作dom,运行for web的js库
1. 大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力
2. 在视图层操作dom,运行 for web 的 js库
**平台差异说明**
......@@ -11,6 +11,10 @@
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|√(2.5.5+,仅支持vue)|√|x|x|x|x|x|
- nvue的视图层是原生的,无法运行js。但提供了bindingx技术来解决通信阻塞。[详见](nvue-api.md#bindingx)
- 微信小程序下替代方案是wxs,这是微信提供的一个裁剪版renderjs。[详见](miniprogram-subject.md#wxs)
- web下不存在逻辑层和视图层的通信阻塞,也可以直接操作dom,所以在web端使用renderjs主要是为了跨端复用代码。如果只开发web端,没有必要使用renderjs。
### 使用方式
设置 script 节点的 lang 为 renderjs
......@@ -34,13 +38,14 @@
### 功能详解
- 大幅降低逻辑层和视图层的通讯损耗,提供高性能视图交互能力
逻辑层和视图层分离有很多好处,但也有一个副作用是在造成了两层之间通信阻塞。尤其是小程序和App的Android端阻塞问题影响了高性能应用的制作。
uni-app的app端逻辑层和视图层是分离的,这种机制有很多好处,但也有一个副作用是在造成了两层之间通信阻塞。尤其是App的Android端阻塞问题影响了高性能应用的制作。
`renderjs`运行在视图层,可以直接操作视图层的元素,避免通信折损。
在hello uni-app的canvas示例中,App端使用了`renderjs`,由运行在视图层的`renderjs`直接操作视图层的canvas,实现了远超微信小程序的流畅canvas动画示例。具体在[hello uni-app](https://m3w.cn/uniapp)示例中体验,对比App端和小程序端的性能差异。
- 在视图层操作dom,运行for web的js库
官方不建议在uni-app里操作dom,但如果你不开发小程序,想使用一些操作了dom、window的库,其实可以使用`renderjs`来解决。
在app-vue环境下,视图层由webview渲染,而`renderjs`运行在视图层,自然可以操作dom和window。
......@@ -56,6 +61,7 @@
* 不要直接引用大型类库,推荐通过动态创建 script 方式引用。
* 可以使用 vue 组件的生命周期不可以使用 App、Page 的生命周期
* 视图层和逻辑层通讯方式与 [WXS](/tutorial/miniprogram-subject.html#wxs) 一致,另外可以通过 this.$ownerInstance 获取当前组件的 ComponentDescriptor 实例。
* 注意逻辑层给数据时最好一次性给到渲染层,而不是不停从逻辑层向渲染层发消息,那样还是会产生逻辑层和视图层的多次通信,还是会卡
* 观测更新的数据在视图层可以直接访问到。
* APP 端视图层的页面引用资源的路径相对于根目录计算,例如:./static/test.js。
* APP 端可以使用 dom、bom API,不可直接访问逻辑层数据,不可以使用 uni 相关接口(如:uni.request)
......
## 介绍
**uts 是什么**
uts 是一门跨平台的、高性能的、强类型的现代编程语言。它可以被翻译为不同平台的原生编程语言。如:JavaScript、Kotlin、Swift 等。
uts 采用了与 ts 基本一致的语法规范,支持绝大部分 ES6 API。因此前端工程师可以快速的掌握 uts 开发
## 快速入门
### 基本语法
#### 声明
uts 有两种声明方式
1. let
声明一个可重新赋值的变量。语法 `let [变量名] : [类型] = 值;`。
> 相当于 TypeScript 中的 let,kotlin 中的 var
```ts
let str = "hello"; // 声明一个字符串变量
str = "hello world"; // 重新赋值
```
2. const
声明一个只读常量,只能为其赋值一次。语法 `const [变量名] : [类型] = 值;`。
> 相当于 TypeScript 中的 const, kotlin 中的 val
```ts
const str = "hello"; // 声明一个字符串变量
str = "hello world"; // 报错,不允许重新赋值
```
#### 变量
在 uts 中,使用变量名需要遵守一定的规则。
- 变量名称可以包含数字和字母。
- 除了下划线 \_ 外,不能包含其他特殊字符,包括空格。
- 变量名不能以数字开头。
> 注意:与 TypeScript 不同的是,uts 不允许以 $ 开头命名变量
#### 操作符
##### 赋值运算符(Assignment operators)
| 名字 | 简写的操作符 | 含义 |
| ------------------------------------------------- | ------------ | ----------- | ---------- |
| 赋值(Assignment) | x = y | x = y |
| 加法赋值(Addition assignment) | x += y | x = x + y |
| 减法赋值(Subtraction assignment) | x -= y | x = x - y |
| 乘法赋值(Multiplication assignment) | x \*= y | x = x \* y |
| 除法赋值(Division assignment) | x /= y | x = x / y |
| 求余赋值(Remainder assignment) | x %= y | x = x % y |
| 左移位赋值(Left shift assignment) | x <<= y | x = x << y |
| 右移位赋值(Right shift assignment) | x >>= y | x = x >> y |
| 无符号右移位赋值(Unsigned right shift assignment) | x >>>= y | x = x >>> y |
| 按位与赋值(Bitwise AND assignment) | x &= y | x = x & y |
| 按位异或赋值(Bitwise XOR assignment) | x ^= y | x = x ^ y |
| 按位或赋值(Bitwise OR assignment) | x \|= y | x \|= y | x = x \| y |
##### 比较运算符(Comparison operators)
| 运算符 | 描述 | 返回 true 的示例 |
| ----------------------------------- | ------------------------------------------- | ---------------- |
| 等于 Equal (==) | 如果两边操作数相等时返回 true。 | var1==var2 |
| 不等于 Not equal (!=) | 如果两边操作数不相等时返回 true | var1!=var2 |
| 全等 Strict equal (===) | 两边操作数相等且类型相同时返回 true。 | var1===var2 |
| 不全等 Strict not equal (!==) | 两边操作数不相等或类型不同时返回 true。 | var1!==var2 |
| 大于 Greater than (>) | 左边的操作数大于右边的操作数返回 true | var1>var2 |
| 大于等于 Greater than or equal (>=) | 左边的操作数大于或等于右边的操作数返回 true | var1>=var2 |
| 小于 Less than (<) | 左边的操作数小于右边的操作数返回 true | var1<var2 |
| 小于等于 Less than or equal (<=) | 左边的操作数小于或等于右边的操作数返回 true | var1<=var2 |
##### 算数运算符(Arithmetic operators)
| 运算符 | 范例 | 描述 |
| -------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| 求余(%) | | 二元运算符. 返回相除之后的余数. |
| 自增(++) | | 一元运算符. 将操作数的值加一. 如果放在操作数前面 (++x), 则返回加一后的值; 如果放在操作数后面 (x++), 则返回操作数原值,然后再将操作数加一. |
| 自减(--) | | 一元运算符. 将操作数的值减一. 前后缀两种用法的返回值类似自增运算符. |
##### 位运算符(Bitwise operators)
| Operator | Usage | Description |
| ------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| 按位与 AND | a & b | 在 a,b 的位表示中,每一个对应的位都为 1 则返回 1, 否则返回 0. |
| 按位或 OR | a \| b | 在 a,b 的位表示中,每一个对应的位,只要有一个为 1 则返回 1, 否则返回 0. |
| 按位异或 XOR | a ^ b | 在 a,b 的位表示中,每一个对应的位,两个不相同则返回 1,相同则返回 0. |
| 按位非 NOT | ~ a | 反转被操作数的位。 |
| 左移 shift | a << b | 将 a 的二进制串向左移动 b 位,右边移入 0. |
| 算术右移 | a >> b | 把 a 的二进制表示向右移动 b 位,丢弃被移出的所有位.(译注:算术右移左边空出的位是根据最高位是 0 和 1 来进行填充的) |
| 无符号右移(左边空出位用 0 填充) | a >>> b | 把 a 的二进制表示向右移动 b 位,丢弃被移出的所有位,并把左边空出的位都填充为 0 |
##### 逻辑运算符(Logical operators)
| 运算符 | 范例 | 描述 |
| ------------ | ---------------- | -------- |
| 逻辑与(&&) | expr1 && expr2 | (逻辑与) |
| 逻辑或(\|\|) | expr1 \|\| expr2 | (逻辑或) |
| 逻辑非(!) | !expr | (逻辑非) |
##### 字符串运算符(String operators)
除了比较操作符,它可以在字符串值中使用,连接操作符(+)连接两个字符串值相连接,返回另一个字符串,它是两个操作数串的结合。
```ts
console.log("my " + "string"); // console logs the string "my string".
```
##### 条件(三元)运算符(Conditional operator)
条件运算符是 uts 中唯一需要三个操作数的运算符。运算的结果根据给定条件在两个值中取其一。语法为:
`条件 ? 值1 : 值2`
```ts
const status = age >= 18 ? "adult" : "minor";
```
### 基本类型
#### 布尔值(Boolean)
有 2 个值分别是:true 和 false。
#### 数字(Number)
整数或浮点数,例如: 42 或者 3.14159。
#### 字符串(String)
字符串是一串表示文本值的字符序列,例如:"hello" 。
#### null
一个表明 null 值的特殊关键字。
### 字面量
字面量是由语法表达式定义的常量;或,通过由一定字词组成的语词表达式定义的常量
在 uts 中,你可以使用各种字面量。这些字面量是按字面意思给出的固定的值,而不是变量
#### 数组字面量
数组字面值是一个封闭在方括号对 ([]) 中的包含有零个或多个表达式的列表,其中每个表达式代表数组的一个元素。当你使用数组字面值创建一个数组时,该数组将会以指定的值作为其元素进行初始化,而其长度被设定为元素的个数。
下面的示例用 3 个元素生成数组coffees,它的长度是 3。
```ts
const coffees = ["French Roast", "Colombian", "Kona"]
const a=[3]
console.log(a.length) // 1
console.log(a[0]) // 3
```
数组字面值同时也是数组对象。
#### 布尔字面量
布尔类型有两种字面量:true和false。
#### 数字字面量
数字字面量包括多种基数的整数字面量和以 10 为基数的浮点数字面量
##### 整数字面量
整数可以用十进制(基数为 10)、十六进制(基数为 16)、二进制(基数为 2)表示。
- 十进制整数字面量由一串数字序列组成,且没有前缀 0。如:`0, 117, -345`
- 十六进制整数以 0x(或 0X)开头,可以包含数字(0-9)和字母 a~f 或 A~F。如:`0x1123, 0x00111 , -0xF1A7`
- 二进制整数以 0b(或 0B)开头,只能包含数字 0 和 1。如:`0b11, 0b0011 , -0b11`
##### 浮点数字面量
浮点数字面值可以有以下的组成部分:
- 一个十进制整数,可以带正负号(即前缀“+”或“ - ”),
- 小数点(“.”),
- 小数部分(由一串十进制数表示),
- 指数部分。
指数部分以“e”或“E”开头,后面跟着一个整数,可以有正负号(即前缀“+”或“-”)。浮点数字面量至少有一位数字,而且必须带小数点或者“e”(大写“E”也可)。
简言之,其语法是:
```
[(+|-)][digits][.digits][(E|e)[(+|-)]digits]
```
例如:
```ts
3.14
-.2345789 // -0.23456789
-3.12e+12 // -3.12*10^12
.1e-23 // 0.1*10^(-23)=10^(-24)=1e-24
```
#### RegExp字面量
正则表达式是字符被斜线围成的表达式。下面是一个正则表达式文字的一个例子。
```ts
const re = /ab+c/;
```
#### 字符串字面量
字符串字面量是由双引号(")对或单引号(')括起来的零个或多个字符。字符串被限定在同种引号之间;也即,必须是成对单引号或成对双引号。下面的例子都是字符串字面值:
```ts
"foo"
'bar'
"1234"
"one line \n another line"
"John's cat"
```
你可以在字符串字面值上使用字符串对象的所有方法,你也能用对字符串字面值使用类似 String.length 的属性:
```ts
console.log("John's cat".length)
// 将打印字符串中的字符个数(包括空格)
// 结果为:10
```
##### 模板字符串
模板字面量 是允许嵌入表达式的字符串字面量。你可以使用多行字符串和字符串插值功能。也被称为“模板字符串”。
```ts
// Basic literal string creation
`In uts '\n' is a line-feed.`
// Multiline strings
`In uts this is
not legal.`
// String interpolation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
```
##### 转义特殊字符
|字符 |意思 |
|-- |-- |
|`\b` |退格符 |
|`\f` |换页符 |
|`\n` |换行符 |
|`\r` |回车符 |
|`\t` |制表符 |
|`\'` |单引号 |
|`\"` |双引号 |
|`\\` |反斜杠字符 |
### 控制流程
#### 条件
##### If 语句
当一个逻辑条件为真,用 if 语句执行一个语句。当这个条件为假,使用可选择的 else 从句来执行这个语句。if 语句如下所示:
```ts
if (condition_1) {
statement_1;
} else if (condition_2) {
statement_2;
} else if (condition_n_1) {
statement_n;
} else {
statement_last;
}
```
> 注意:if 和 else if 中的条件表达式必须为布尔值
##### switch 语句
switch 语句允许一个程序求一个表达式的值并且尝试去匹配表达式的值到一个 case 标签。如果匹配成功,这个程序执行相关的语句。switch 语句如下所示:
```ts
switch (expression) {
case label_1:
statements_1
[break;]
case label_2:
statements_2
[break;]
default:
statements_def
[break;]
}
```
程序首先查找一个与 expression 匹配的 case 语句,然后将控制权转移到该子句,执行相关的语句。如果没有匹配值, 程序会去找 default 语句,如果找到了,控制权转移到该子句,执行相关的语句。如果没有找到 default,程序会继续执行 switch 语句后面的语句。default 语句通常出现在 switch 语句里的最后面,当然这不是必须的。
可选的 break 语句与每个 case 语句相关联, 保证在匹配的语句被执行后程序可以跳出 switch 并且继续执行 switch 后面的语句。如果 break 被忽略,则程序将继续执行 switch 语句中的下一条语句。
##### 三元表达式
uts 支持使用三元表达式。一个条件后面会跟一个问号(?),如果条件为 true ,则问号后面的表达式 A 将会执行;表达式 A 后面跟着一个冒号(:),如果条件为 false ,则冒号后面的表达式 B 将会执行。本运算符经常作为 if 语句的简捷形式来使用。
```ts
function getFee(isMember: boolean): string {
return isMember ? "$2.00" : "$10.00";
}
console.log(getFee(true));
// expected output: "$2.00"
console.log(getFee(false));
// expected output: "$10.00"
console.log(getFee(null));
// expected output: "$10.00"
```
三元操作符是右结合的,也就是说你可以像这样把它链接起来, 和 if … else if … else if … else 链类似:
```ts
function example(): string {
return condition1
? value1
: condition2
? value2
: condition3
? value3
: value4;
}
// Equivalent to:
function example(): string {
if (condition1) {
return value1;
} else if (condition2) {
return value2;
} else if (condition3) {
return value3;
} else {
return value4;
}
}
```
#### 循环
##### for
一个 for 循环会一直重复执行,直到指定的循环条件为 false。 一个 for 语句是这个样子的:
```ts
for ([initialExpression]; [condition]; [incrementExpression]) {
statement;
}
```
当一个 for 循环执行的时候,会发生以下过程:
1. 如果有初始化表达式 initialExpression,它将被执行。这个表达式通常会初始化一个或多个循环计数器。
2. 计算 condition 表达式的值。如果 condition 的值是 true,循环中的语句会被执行。如果 condition 的值是 false,for 循环终止。如果 condition 表达式整个都被省略掉了,3. condition 的值会被认为是 true。
3. 循环中的 statement 被执行。如果需要执行多条语句,可以使用块({ ... })来包裹这些语句。
4. 如果有更新表达式 incrementExpression,执行更新表达式。
5. 回到步骤 2。
举例:
```ts
for (let i = 0; i < 10; i++) {
//...
}
```
##### do...while
do...while 语句一直重复直到指定的条件求值得到假值(false)。 一个 do...while 语句看起来像这样:
```ts
do {
statement;
} while (condition);
```
statement 在检查条件之前会执行一次。要执行多条语句(语句块),要使用块语句({ ... })包括起来。 如果 condition 为真(true),statement 将再次执行。 在每个执行的结尾会进行条件的检查。当 condition 为假(false),执行会停止并且把控制权交回给 do...while 后面的语句。
举例:
```ts
let i = 0;
do {
i += 1;
} while (i < 10);
```
##### while
一个 while 语句只要指定的条件求值为真(true)就会一直执行它的语句块。一个 while 语句看起来像这样:
```ts
while (condition) {
statement;
}
```
如果这个条件变为假,循环里的 statement 将会停止执行并把控制权交回给 while 语句后面的代码。
条件检测会在每次 statement 执行之前发生。如果条件返回为真, statement 会被执行并紧接着再次测试条件。如果条件返回为假,执行将停止并把控制权交回给 while 后面的语句。
要执行多条语句(语句块),要使用语句块 ({ ... }) 包括起来。
举例:
```ts
let n = 0;
let x = 0;
while (n < 3) {
n++;
x += n;
}
```
##### break
使用 break 语句来终止循环,switch。
举例:
```ts
for (let i = 0; i < 10; i++) {
if (i > 5) {
break;
}
}
let x = 0;
while (true) {
x++;
if (x > 5) {
break;
}
}
```
##### continue
使用 continue 语句来终止当前循环,并在下一次迭代时继续执行循环。
举例:
```ts
for (let i = 0; i < 10; i++) {
if (i > 5) {
continue;
}
}
let x = 0;
while (true) {
x++;
if (x > 5) {
continue;
}
}
```
#### 异常
你可以用 throw 语句抛出一个异常并且用 try...catch 语句捕获处理它。
使用 throw 表达式来抛出异常:
```ts
throw new Error("Hi There!");
```
使用 try……catch 表达式来捕获异常:
```ts
try {
// 一些代码
} catch (e: Error) {
// 处理程序
} finally {
// 可选的 finally 块
}
```
### 函数
函数是 uts 中的基本组件之一。 一个函数是 uts 过程 — 一组执行任务或计算值的语句。要使用一个函数,你必须将其定义在你希望调用它的作用域内。
一个 uts 函数用 function 关键字定义,后面跟着函数名和圆括号。
#### 定义函数
##### 函数声明
一个函数定义(也称为函数声明,或函数语句)由一系列的 function 关键字组成,依次为:
- 函数的名称。
- 函数参数列表,包围在括号中并由逗号分隔。
- 函数返回值类型。
- 定义函数的 uts 语句,用大括号{}括起来。
> 注意:函数必须明确标明返回值类型
例如,以下的代码定义了一个简单的 add 函数:
```ts
function add(x: string, y: string): string {
return x + y;
}
```
##### 函数表达式
虽然上面的函数声明在语法上是一个语句,但函数也可以由函数表达式创建。这样的函数可以是匿名的;它不必有一个名称。例如,函数 add 也可这样来定义:
```ts
const add = function (x: string, y: string): string {
return x + y;
};
```
> 注意:函数表达式不支持使用函数名,比如`const add = function add(){}`是不允许的。
#### 调用函数
定义一个函数并不会自动的执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。调用函数才会以给定的参数真正执行这些动作。例如,一旦你定义了函数 add,你可以如下这样调用它:
```ts
add("hello", "world");
```
上述语句通过提供参数 "hello" 和 "world" 来调用函数。函数执行完它的语句会返回值 "hello world"。
#### 函数作用域
在函数内定义的变量不能在函数之外的任何地方访问,因为变量仅仅在该函数的域的内部有定义。相对应的,一个函数可以访问定义在其范围内的任何变量和函数。
```ts
const hello = "hello";
const world = "world";
function add(): string {
return hello + world; // 可以访问到 hello 和 world
}
```
##### 嵌套函数
你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包。一个闭包是一个可以自己拥有独立的环境与变量的表达式(通常是函数)。
既然嵌套函数是一个闭包,就意味着一个嵌套函数可以”继承“容器函数的参数和变量。换句话说,内部函数包含外部函数的作用域。
可以总结如下:
- 内部函数只可以在外部函数中访问。
- 内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。
举例:
```ts
function addSquares(a: number, b: number): number {
function square(x: number): number {
return x * x;
}
return square(a) + square(b);
}
addSquares(2, 3); // returns 13
addSquares(3, 4); // returns 25
addSquares(4, 5); // returns 41
```
##### 命名冲突
当同一个闭包作用域下两个参数或者变量同名时,就会产生命名冲突。更近的作用域有更高的优先权,所以最近的优先级最高,最远的优先级最低。这就是作用域链。链的第一个元素就是最里面的作用域,最后一个元素便是最外层的作用域。
举例:
```ts
function outside(): (x: number) => number {
let x = 5;
const inside = function (x: number): number {
return x * 2;
};
return inside;
}
outside()(10); // 返回值为 20 而不是 10
```
命名冲突发生在 return x 上,inside 的参数 x 和 outside 变量 x 发生了冲突。这里的作用链域是{inside, outside}。因此 inside 的 x 具有最高优先权,返回了 20(inside 的 x)而不是 10(outside 的 x)。
#### 闭包
闭包是 uts 中最强大的特性之一。uts 允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。
但是,外部函数却不能够访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一定的安全性。
此外,由于内部函数可以访问外部函数的作用域,因此当内部函数生存周期大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行时间长。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。
举例:
```ts
const pet = function (name: string): () => string {
//外部函数定义了一个变量"name"
const getName = function (): string {
//内部函数可以访问 外部函数定义的"name"
return name;
};
//返回这个内部函数,从而将其暴露在外部函数作用域
return getName;
};
const myPet = pet("Vivie");
myPet(); // 返回结果 "Vivie"
```
#### 函数参数
##### 默认参数
函数参数可以有默认值,当省略相应的参数时使用默认值。
```ts
function multiply(a:number, b:number = 1):number {
return a*b;
}
multiply(5); // 5
```
#### 箭头函数
箭头函数表达式(也称胖箭头函数)相比函数表达式具有较短的语法。箭头函数总是匿名的。
```ts
const arr = ["Hydrogen", "Helium", "Lithium", "Beryllium"];
const a2 = arr.map(function (s): number {
return s.length;
});
console.log(a2); // logs [ 8, 6, 7, 9 ]
const a3 = arr.map((s): number => s.length);
console.log(a3); // logs [ 8, 6, 7, 9 ]
```
### 类
uts 中使用关键字 class 声明类
```ts
class Person {
/*……*/
}
```
类声明由类名以及由花括号包围的类体构成。
#### 构造函数
constructor 是一种用于创建和初始化 class 创建的对象的特殊方法。
- 语法:
```ts
constructor([arguments]) { ... }
```
- 描述:
在一个类中只能有一个名为 “constructor” 的特殊方法。 一个类中出现多次构造函数 (constructor)方法将会抛出一个 SyntaxError 错误。
在一个构造方法中可以使用 super 关键字来调用一个父类的构造方法。
如果没有显式指定构造方法,则会添加默认的 constructor 方法。
如果不指定一个构造函数(constructor)方法, 则使用一个默认的构造函数(constructor)。
- 示例:
```ts
class Polygon {
constructor() {
this.name = "Polygon";
}
}
class Square extends Polygon {
constructor() {
super();
}
}
```
#### 继承
uts 允许使用继承来扩展现有的类。
- 语法:
```ts
class ChildClass extends ParentClass { ... }
```
- 描述:
extends 关键字用来创建一个类的子类。
- 示例:
```ts
class Polygon {}
class Square extends Polygon {}
```
##### 覆盖方法
uts 对于可覆盖的成员以及覆盖后的成员需要显式修饰符:
```ts
class Polygon {
name(): string {
return "Polygon";
}
}
class Square extends Polygon {
override name(): string {
return "Square";
}
}
```
Square.name 函数上必须加上 override 修饰符。如果没写,编译器会报错。
##### 覆盖属性
属性与方法的覆盖机制相同。在超类中声明然后在派生类中重新声明的属性必须以 override 开头,并且它们必须具有兼容的类型。
```ts
class Shape {
vertexCount: Int = 0
}
class Rectangle extends Shape {
override vertexCount = 4
}
```
##### 调用超类实现
派生类中的代码可以使用 super 关键字调用其超类的函数实现:
```ts
class Rectangle {
draw() {}
}
class FilledRectangle extends Rectangle {
override draw() {
super.draw();
}
}
```
#### 实例属性
uts 中实例属性存在于类的每一个实例中。
##### 声明实例属性
uts 可以在类中声明属性,默认可读,可写。
```ts
class Address {
city: String = "beijing";
}
```
使用一个实例属性,以类实例引用它即可:
```ts
function copyAddress(address: Address): Address {
const result = new Address();
result.city = address.city; // 访问 city 属性
return result;
}
```
##### Getter 与 Setter
uts 支持通过 getters/setters 来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。
```ts
const passcode = "secret passcode";
class Employee {
private _fullName: string = "";
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode === "secret passcode") {
this._fullName = newName;
} else {
console.log("Error: Unauthorized update of employee!");
}
}
}
```
##### readonly
uts 可以使用 readonly 关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
```ts
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor (theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.
```
#### 静态属性
使用关键字 static 来将一个属性声明为静态属性。静态属性不会在实例中被调用,而只会被类本身调用。
```ts
class ClassWithStaticField {
static staticField = "static field";
}
console.log(ClassWithStaticField.staticField);
```
#### 实例方法
uts 中实例方法存在于类的每一个实例中。
##### 声明实例方法
uts 可以在类中声明实例方法。
```ts
class Rectangle {
private height:number;
private width:number;
constructor(height: number, width: number) {
this.height = height;
this.width = width;
}
calcArea(): number {
return this.height * this.width;
}
}
```
使用一个实例方法,以类实例调用它即可:
```ts
const square = new Rectangle(10, 10);
square.calcArea();
```
#### 静态方法
使用关键字 static 来将一个方法声明为静态方法。静态方法不会在实例中被调用,而只会被类本身调用。它们经常是工具函数,比如用来创建或者复制对象。
```ts
class ClassWithStaticMethod {
static staticMethod(): string {
return "static method has been called.";
}
}
ClassWithStaticMethod.staticMethod();
```
#### 可见性修饰符
类的方法与属性都可以有可见性修饰符。
在 uts 中有三个可见性修饰符:private、 protected、 和 public。 默认可见性是 public。
##### public
在 uts 中可以自由的访问程序里定义的 public 成员,这也是 uts 的默认行为。
##### private
当成员被标记成 private 时,它就不能在声明它的类的外部访问。比如:
```ts
class Cat {
private name: string = "Cat";
}
new Cat().name; // 错误: 'name' 是私有的.
```
##### protected
protected 修饰符与 private 修饰符的行为很相似,但有一点不同,protected 成员在派生类中仍然可以访问。比如:
```ts
class Person {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch(): string {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
const howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // 错误
```
注意,我们不能在 Person 类外使用 name,但是我们仍然可以通过 Employee 类的实例方法访问,因为 Employee 是由 Person 派生而来的。
### 模块
uts 支持将程序拆分为可按需导入的单独模块,模块中可以导入和导出各种类型的变量,如函数,字符串,数字,布尔值,类等。
#### 导出
export 语句可以将一个文件中的函数,类等导出。比如:
```ts
export const name: string = "square";
export function draw() {}
export default class Canvas {} // default 关键词支持默认导出
```
- 导出的函数声明与类声明必须要有名称。
- export 命令可以出现在模块的任何位置,但必需处于模块顶层。
- 在一个文件中,export、import 可以有多个,export default 仅有一个。
- 通过 export 方式导出,在导入时要加{ },export default 则不需要。
#### 导入
import 语句可以将另一个文件中的函数,类等导入到当前文件。比如:
```ts
import { name as name1, draw } from "./canvas.uts" // 支持 as 语法做别名导入
import * as Utils from "./utils.uts" // Test 包含所有 export 的导出
import Canvas from "./canvas.uts" // 对应 export default 的导出
```
示例
```ts
/*-----export [test.js]-----*/
export const name = 'test'
export function test(){
console.log('test')
}
export default class Test{
test(){
console.log('Test.test')
}
}
```
```ts
import { name } from './test.uts'
import * as testModule from './test.uts'
import Test from './test.uts'
console.log(name)
testModule.test()
const test = new Test()
test.test()
```
### 内置对象
#### Array
Array 对象是用于构造数组的全局对象,数组是类似于列表的高阶对象。
##### 实例属性
###### length
数组中的元素个数
##### 实例方法
###### concat
用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组
###### copyWithin
浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度
###### every
测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值
###### fill
用一个固定值填充一个数组中从起始索引到终止索引内的全部元素
###### filter
创建一个新数组,其包含通过所提供函数实现的测试的所有元素
###### find
返回数组中满足提供的测试函数的第一个元素的值
###### findIndex
返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1
###### flat
按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
###### flatMap
使用映射函数映射每个元素,然后将结果压缩成一个新数组
###### forEach
对数组的每个元素执行一次给定的函数
###### includes
判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回 false
###### indexOf
返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回 -1
###### join
将一个数组的所有元素连接成一个字符串并返回这个字符串
###### lastIndexOf
返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1
###### map
返回一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值
###### pop
从数组中删除最后一个元素,并返回该元素的值
###### push
将一个或多个元素添加到数组的末尾,并返回该数组的新长度
###### reduce
对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果汇总为单个返回值
###### reduceRight
接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值
###### shift
从数组中删除第一个元素,并返回该元素的值
###### slice
提取源数组的一部分并返回一个新数组
###### some
测试数组中是不是至少有一个元素通过了被提供的函数测试
###### splice
通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容
###### unshift
将一个或多个元素添加到数组的头部,并返回该数组的新长度
##### 常见操作
- 创建数组
```ts
const fruits = ['Apple', 'Banana']
console.log(fruits.length)
```
- 通过索引访问数组元素
```ts
const first = fruits[0]
// Apple
const last = fruits[fruits.length - 1]
// Banana
```
- 遍历数组
```ts
fruits.forEach(function(item, index, array) {
console.log(item, index)
})
// Apple 0
// Banana 1
```
- 添加元素到数组的末尾
```ts
const newLength = fruits.push('Orange')
// ["Apple", "Banana", "Orange"]
```
- 删除数组末尾的元素
```ts
const last = fruits.pop() // remove Orange (from the end)
// ["Apple", "Banana"]
```
- 删除数组头部元素
```ts
const first = fruits.shift() // remove Apple from the front
// ["Banana"]
```
- 添加元素到数组的头部
```ts
const newLength = fruits.unshift('Strawberry') // add to the front
// ["Strawberry", "Banana"]
```
- 找出某个元素在数组中的索引
```ts
fruits.push('Mango')
// ["Strawberry", "Banana", "Mango"]
const pos = fruits.indexOf('Banana')
// 1
```
- 通过索引删除某个元素
```ts
const removedItem = fruits.splice(pos, 1) // this is how to remove an item
// ["Strawberry", "Mango"]
```
- 从一个索引位置删除多个元素
```ts
const vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot']
console.log(vegetables)
// ["Cabbage", "Turnip", "Radish", "Carrot"]
const pos = 1
const n = 2
const removedItems = vegetables.splice(pos, n)
// this is how to remove items, n defines the number of items to be removed,
// starting at the index position specified by pos and progressing toward the end of array.
console.log(vegetables)
// ["Cabbage", "Carrot"] (the original array is changed)
console.log(removedItems)
// ["Turnip", "Radish"]
```
- 复制一个数组
```ts
const shallowCopy = fruits.slice() // this is how to make a copy
// ["Strawberry", "Mango"]
```
##### 访问数组元素
数组的索引是从 0 开始的,第一个元素的索引为 0,最后一个元素的索引等于该数组的 长度 减 1。
如果指定的索引是一个无效值,将会抛出 IndexOutOfBoundsException 异常
下面的写法是错误的,运行时会抛出 SyntaxError 异常,而原因则是使用了非法的属性名:
```ts
console.log(arr.0) // a syntax error
```
#### Date
#### Error
#### JSON
#### Map
#### Promise
#### RegExp
#### Set
## 学习资料
### JavaScript 开发者快速上手 uts
### Android 开发者快速上手 uts
\ No newline at end of file
::: warning 注意
您正在浏览的是老版uni统计1.0的文档。推荐升级到[uni统计2.0](uni-stat-v2.html)
:::
uni-app 2.2.3+ 版本新增 `uni 统计1.0`,支持全平台业务统计,包括App、H5及各家小程序。
......
......@@ -123,6 +123,15 @@ uni统计的开源且基于[uni-admin](/uniCloud/admin)的插件规范提供了
|version|String|"1"|"1" , "2"|统计版本 ,如不填写,默认使用版本1.0,推荐使用2.0版本|
|debug|Boolean|false|true , false|开启统计调试模式 ,会产生大量日志,且会在开发阶段上报数据,应用发布请关闭此项|
|reportInterval|Number|10|true , false|前端数据上报周期 **HBuilderX 3.5.4+ 支持**|
|collectItems|Object|-|-|采集项配置 **HBuilderX 3.5.5+ 支持**|
**collectItems 采集项配置说明**
|字段|类型|默认值|可选值|说明|
|:-:|:-:|:-:|:-:|:-:|
|uniPushClientID|Boolean|false|true/false|是否开启推送`PushClientID`的采集|
**分平台设置**
`uniStatistics` 支持分平台设置,比如仅开启微信小程序平台的 `uni统计`,则在`mp-weixin`节点下设置 `uniStatistics ->enable` 即可,如下:
......@@ -135,7 +144,7 @@ uni统计的开源且基于[uni-admin](/uniCloud/admin)的插件规范提供了
}
```
**uniStatistics说明**
**分平台uniStatistics说明**
|字段|类型|默认值|可选值|说明|
|:-:|:-:|:-:|:-:|:-:|
......@@ -362,7 +371,7 @@ uni统计新增的文件主要包括:
为方便开发者使用 sourceMap 文件定位代码问题,增加在统计中使用 sourceMap 错误解析功能。
#### 使用环境
#### 使用环境@sourcemap-parse-error-env
1. 使用腾讯云服务空间,不支持阿里云服务空间
2. HBuiderX 3.5.3+
......@@ -951,7 +960,7 @@ db.collection('uni-stat-event-logs')
3. 重新上传覆盖所有的`DB Schema`
4. 将原`uni-stat-app-versions`表中的数据导入到`opendb-app-versions`表中;如下提供了一个代码片段,你可以创建一个云函数,将示例代码拷贝到云函数中,右键执行 “运行-本地云函数”,即可自动完成数据内容的迁移;
```
```js
'use strict';
const db = uniCloud.database()
exports.main = async (event, context) => {
......
......@@ -76,6 +76,7 @@
* [uni-sec-check 内容安全](https://ext.dcloud.net.cn/plugin?id=5460)
* [统一发行页面](uni-portal.md)
* [uni-cloud-router](uniCloud/uni-cloud-router.md)
* [uni-open-bridge](uniCloud/uni-open-bridge.md)
* [案例](uniCloud/resource.md)
* [开发者使用反馈](uniCloud/feedback.md)
* [DCloud行业认证服务商](https://ask.dcloud.net.cn/article/39388)
......
......@@ -128,6 +128,7 @@ context对象的属性清单如下:
|CLIENTIP |string |客户端IP。如果调用来源是其他服务器,会返回调用方的ip |
|CLIENTUA |string |客户端userAgent。注意非本地运行环境下客户端getSystemInfoSync也会获取ua参数并上传给云函数,但是云函数会从http请求头里面获取ua而不是clientInfo里面的ua |
|uniIdToken |string |客户端uni-id token字符串,新增于HBuilderX 3.5.1。 |
|requestId |string |当前请求id,新增于HBuilderX 3.5.5。 |
除了上述属性,如果是uni-app客户端通过callfunction访问云函数,那么context还会追加一批客户端信息。
- HBuilderX 3.4.9前,context 添加了一批大写属性,如APPID、OS。
......
......@@ -286,13 +286,17 @@ errMsg用于存放具体错误信息,包括展示给开发者、终端用户
|uniCloud.deleteFile() |云函数删除云存储的文件 [详情](uniCloud/storage?id=clouddeletefile) |
|uniCloud.getTempFileURL() |获取云存储文件的临时路径 [详情](uniCloud/storage?id=cloudgettempfileurl) |
|uniCloud.customAuth() |使用云厂商自定义登录,仅腾讯云支持[详情](uniCloud/authentication.md?id=cloud-custom-auth) |
|uniCloud.callFunction() |云函数/云对象中调用另一个云函数 [见下](?id=callbyfunction) |
|uniCloud.callFunction() |云函数/云对象中调用另一个云函数 [见下](#callbyfunction) |
|uniCloud.importObject() |云函数/云对象中调用另一个云对象 [详情](cloud-obj.md?id=call-by-cloud) |
|uniCloud.httpclient |云函数中通过http访问其他系统 [见下](uniCloud/cf-functions?id=httpclient) |
|uniCloud.httpclient |云函数中通过http访问其他系统 [见下](#httpclient) |
|uniCloud.sendSms() |发送短信,需添加扩展库 [详见](uniCloud/send-sms.md) |
|uniCloud.getPhoneNumber() |获取一键登录手机号,需添加扩展库 [详见](uniCloud/univerify.md?id=cloud) |
|uniCloud.init() |获取指定服务空间的uniCloud实例 [详见](uniCloud/concepts/space.md?id=multi-space) |
|uniCloud.logger |云函数中打印日志到[uniCloud web控制台](https://unicloud.dcloud.net.cn/)的日志系统(非HBuilderX控制台)[详情](rundebug.md?id=uniCloudlogger) |
|uniCloud.httpProxyForEip |使用云厂商代理访问http服务(阿里云固定IP方案),仅阿里云云端环境支持 [详见](#aliyun-eip),新增于`HBuilderX 3.5.5`|
|uniCloud.getRequestList |获取当前云函数实例内正在处理的请求Id列表 [详见](#get-request-list),新增于`HBuilderX 3.5.5`|
|uniCloud.getClientInfos |获取当前云函数实例内正在处理的请求对应的客户端信息列表 [详见](#get-client-infos),新增于`HBuilderX 3.5.5`|
|uniCloud.getCloudInfos |获取当前云函数实例内正在处理的请求对应的云端信息列表 [详见](#get-cloud-infos),新增于`HBuilderX 3.5.5`|
## 错误对象@uni-cloud-error
......@@ -427,6 +431,88 @@ exports.main = async (event, context) => {
```
## 其他API
### 获取请求id列表@get-request-list
非单实例多并发场景下列表长度为1,仅有的一个requestId表示当前请求的requestId。单实例多并发场景下会返回正在处理的所有请求的requestId列表。如需获取当前请求的requestId参考:[云函数context](cf-callfunction.md#context)[云对象获取当前请求的requestId](cloud-obj.md#get-request-id)
**示例**
```js
uniCloud.getRequestList() // ['3228166e-3c17-4d58-9707-xxxxxxxx']
```
### 获取客户端信息列表#get-client-infos
非单实例多并发场景下列表长度为1,仅有的一个cloudInfo表示当前请求的客户端信息。单实例多并发场景下返回正在处理的所有请求的客户端信息列表。
```js
const clientInfos = uniCloud.getClientInfos()
clientInfos = [{
appId: '__UNI_xxxxx',
requestId: '3228166e-3c17-4d58-9707-xxxxxxxx'
// ...
}]
```
**返回值**
getClientInfos返回的信息,是在客户端的[uni.getSystemInfo](/api/system/info.md#getsysteminfo)的基础之上,增加了一些额外的信息。
除了`getSystemInfo`返回字段外,还包含以下信息
|属性名 |类型 |说明 |
|-- |-- |-- |
|clientIP |string |客户端ip |
|userAgent|string |客户端ua,注意非本地运行环境下客户端getSystemInfoSync也会获取ua参数并上传给云对象,但是云对象会从http请求头里面获取ua而不是clientInfo里面的ua|
|source |string |调用来源,返回值见下。 |
|scene |string |场景值。客户端[uni.getLaunchOptionsSync](/api/plugins/getLaunchOptionsSync.md#getlaunchoptionssync)返回的scene参数, |
|requestId|string |请求Id,可以使用此字段筛选出当前请求的客户端信息 |
云函数调用来源,它的值域为:
|取值 |说明 |
|-- |-- |
|client |uni-app客户端导入云对象调用 |
|function |由其他云函数或云对象调用 |
|http |云对象URL化后通过http访问调用|
|timing |定时任务调用云对象 |
**注意事项**
- 客户端上报的信息在理论上存在被篡改可能,实际业务中应验证前端传来的数据的合法性
- 除了clientIP外,其他客户端信息只有使用uni-app客户端以callFunction或者importObject方式访问云函数或云对象时才有
- 云对象与云函数内获取客户端platform稍有不同,云函数未拉齐vue2、vue3版本app平台的platform值,vue2为`app-plus`,vue3为`app`。云对象无论客户端是vue2还是vue3,在app平台获取的platform均为`app`。这一点在使用uni-id时需要特别注意,详情见:[uni-id文档 preferedAppPlatform](uniCloud/uni-id.md?id=prefered-app-platform)
### 获取云端信息@get-cloud-infos
非单实例多并发场景下列表长度为1,仅有的一个cloudInfo表示当前请求的云端信息。单实例多并发场景下返回正在处理的所有请求的云端信息列表。
**示例**
```js
const cloudInfos = uniCloud.getCloudInfos()
cloudInfos = [{
provider: 'aliyun',
spaceId: 'xxxxx',
functionName: 'xxx',
functionType: 'xxxx',
requestId: '3228166e-3c17-4d58-9707-xxxxxxxx'
}]
```
**返回值**
|参数名 |类型 |必备 |说明 |
|-- |-- |-- |-- |
|provider |string |是 |服务空间供应商,阿里云为:`aliyun`,腾讯云为:`tencent`|
|spaceId |string |是 |服务空间Id |
|functionName |string |是 |云对象名称,新增于 |
|functionType |string |是 |云对象此值固定为`cloudobject`,新增于 |
|requestId |string |是 |请求Id,可以使用此字段筛选出当前请求的云端信息 |
## 扩展库@extension
uniCloud的api中,有些api对应的实现,其代码体积较大,且这些功能并不是每一个云函数都会使用。为了方便开发者控制云函数的体积,设计了`uniCloud扩展库`的概念。
......@@ -771,6 +857,8 @@ exports.main = async function() {
### 固定出口IP@eip
#### 腾讯云@tencent-eip
serverless默认是没有固定的服务器IP的,因为有很多服务器资源在后台供随时调用,每次调用到哪个服务器、哪个ip都不固定。
但一些三方系统,要求配置固定ip白名单,比如微信公众号的js sdk,此时只能提供固定ip地址。
......@@ -792,6 +880,115 @@ serverless默认是没有固定的服务器IP的,因为有很多服务器资
建议已开通redis的服务空间先将云函数关联redis扩展再开通固定出口IP,**2022年7月20日起新上传的云函数会默认开启vpc功能,如需旧云函数和新云函数保持一致可以把旧云函数关联redis扩展后上传一次,注意这样操作会改变旧云函数的固定出口IP**
#### 阿里云@aliyun-eip
> 新增于 HBuilderX 3.5.5,仅阿里云支持
uniCloud.httpProxyForEip ,其原理是通过代理请求获得固定出口IP的能力。IP为轮转不固定,因此三方服务要求使用白名单时开发者需要将代理服务器可能的IP均加入到白名单中,见下方代理服务器列表。此外对于代理的域名有限制,当前仅持`weixin.qq.com`泛域名。若开发者有其他域名代理需求,发送邮件到service@dcloud.io申请。
代理服务器IP列表
```
39.100.3.155
47.92.39.39
47.92.67.205
47.92.25.106
47.92.68.159
```
如需在获取微信公众号access_token场景使用,请将上述ip配置到`微信公众平台 -> 基本配置 -> IP白名单`内,相关链接:[微信公众平台](https://mp.weixin.qq.com/)
##### 发送Get请求@http-proxy-get
**用法**
```js
uniCloud.httpProxyForEip.get(url: String, params?: Object)
```
**示例**
```js
await uniCloud.httpProxyForEip.get(
'https://api.weixin.qq.com/cgi-bin/token',
{
grant_type: 'client_credential',
appid: 'xxxx',
secret: 'xxxx'
}
)
```
##### 发送POST请求携带表单数据@http-proxy-post-form
注意,此接口以`application/x-www-form-urlencoded`格式发送数据而不是`multipart/form-data`
**用法**
```js
uniCloud.httpProxyForEip.postForm(url: String, data?: Object, headers?: Object)
```
**示例**
```js
uniCloud.httpProxyForEip.postForm(
'https://www.example.com/search',
{
q: 'nodejs',
cat: '1001'
}
)
```
##### 发送POST请求携带JSON数据@http-proxy-post-json
`application/json`格式post数据
**用法**
```js
uniCloud.httpProxyForEip.postJson(url: String, json?: Object, headers?: Object)
```
**示例**
```js
uniCloud.httpProxyForEip.postJson(
'https://www.example.com/search',
{
q: 'nodejs',
cat: '1001'
}
)
```
##### POST通用数据@http-proxy-post
**用法**
```js
uniCloud.httpProxyForEip.post(url: String, text?: String, headers?: Object)
```
**示例**
```js
uniCloud.httpProxyForEip.post(
'https://www.example.com/search',
'abcdefg',
{
"Content-Type": "text/plain"
}
)
```
**注意**
- 不支持发送multipart格式的内容
- 代理请求超时时间为5秒
- 上述接口支持本地运行
### 单实例多并发@concurrency
> 仅阿里云支持
......
......@@ -19,6 +19,7 @@ uniCloud分为客户端和云端两部分,有些接口名称相同,参数也
|uniCloud.init() |同时使用多个服务空间时初始化额外服务空间 [详情](init.md) |
|uniCloud.addInterceptor() |新增拦截器 [详情](#add-interceptor) |
|uniCloud.removeInterceptor() |移除拦截器 [详情](#remove-interceptor) |
|uniCloud.interceptObject() |拦截云对象请求 [详情](#intercept-object) |
|uniCloud.onResponse() |监听服务端(云函数、云对象、clientDB)响应 [详情](#on-response) |
|uniCloud.offResponse() |移除监听服务端(云函数、云对象、clientDB)响应 [详情](#off-response) |
|uniCloud.onNeedLogin() |监听需要登录事件 [详情](#on-need-login) |
......@@ -71,7 +72,7 @@ console.log(uniCloud.getCurrentUserInfo().role.indexOf('admin')>-1); // 如果
> 新增于HBuilderX 3.1.20
接口形式:`uniCloud.addInterceptor(String apiName, Object interceptorMap)`
接口形式:`uniCloud.addInterceptor(String apiName, Object interceptor)`
**平台兼容性**
......@@ -85,9 +86,9 @@ console.log(uniCloud.getCurrentUserInfo().role.indexOf('admin')>-1); // 如果
| 字段 | 类型 | 必填| 说明 |
| --- | --- | --- | --- |
| apiName | string| 是 | 要拦截的Api名称,可选值:callFunction、database、uploadFile |
| interceptorMap| object| 是 | 要添加的拦截器 |
| interceptor| object| 是 | 要添加的拦截器 |
**interceptorMap参数说明**
**interceptor参数说明**
|参数名 |类型 |必填 |默认值 |说明 |平台差异说明 |
|--- |--- |--- |--- |--- |--- |
......@@ -120,16 +121,16 @@ uniCloud.addInterceptor('callFunction', {
> 新增于HBuilderX 3.1.20
接口形式:`uniCloud.removeInterceptor(String apiName, Object interceptorMap)`
接口形式:`uniCloud.removeInterceptor(String apiName, Object interceptor)`
**入参说明**
| 字段 | 类型 | 必填| 说明 |
| --- | --- | --- | --- |
| apiName | string| 是 | 要拦截的Api名称,可选值:callFunction、database、uploadFile |
| interceptorMap| object| 是 | 要移除的拦截器,选填,不传递此参数时移除此Api所有拦截器 |
| interceptor| object| 是 | 要移除的拦截器,选填,不传递此参数时移除此Api所有拦截器 |
**interceptorMap参数说明**
**interceptor参数说明**
|参数名 |类型 |必填 |默认值 |说明 |平台差异说明 |
|--- |--- |--- |--- |--- |--- |
......@@ -167,6 +168,55 @@ uniCloud.removeInterceptor('callFunction', {
})
```
### 拦截云对象请求intercept-object
> 新增于HBuilderX 3.5.5
接口形式:`uniCloud.interceptObject(Object interceptor)`
**interceptor参数说明**
|参数名 |类型 |必填 |默认值 |说明 |平台差异说明 |
|--- |--- |--- |--- |--- |--- |
|invoke |Function |否 | |拦截前触发 | |
|success |Function |否 | |成功回调拦截 | |
|fail |Function |否 | |失败回调拦截 | |
|complete |Function |否 | |完成回调拦截 | |
**invoke**拦截器内将会收到以下形式的参数
```js
{
objectName: "", // 云对象名称
methodName: "", // 云对象的方法名称
params: [] // 参数列表
}
```
**success**拦截器内将会收到以下形式的参数
```js
{
objectName: "", // 云对象名称
methodName: "", // 云对象的方法名称
params: [], // 参数列表
result: {} // 云对象响应结果
}
```
**fail**拦截器内将会收到以下形式的参数
```js
{
objectName: "", // 云对象名称
methodName: "", // 云对象的方法名称
params: [], // 参数列表
error: new Error() // 错误对象
}
```
**complete**拦截器内将会收到success或fail拦截器相同的参数,具体以云函数是否执行成功为准
### 监听云端响应@on-response
> 新增于HBuilderX 3.4.13
......
......@@ -385,6 +385,25 @@ module.exports = {
}
```
### 获取当前请求id@get-request-id
**接口形式**
`this.getUniCloudRequestId()`
**示例**
```js
module.exports = {
_after: function(error, result) {
if(error) {
const requestId = this.getUniCloudRequestId()
// log(requestId, error) 出错时记录日志,log方法需自行实现
}
}
}
```
### 获取url化时的http信息@get-http-info
> 新增于HBuilderX 3.5.2
......
......@@ -2,7 +2,7 @@
开发者应经常查阅自己的慢查询,修复问题,保证业务系统的健康稳定。
在数据库语句执行超过一定时间(**腾讯云为5秒,阿里云为3秒**)仍不能返回结果后,阿里云甚至会报错`operation exceeded time limit`**如果对数据库超时时间有更高的需求,建议使用腾讯云。**
在数据库语句执行超过一定时间(**腾讯云、阿里云均为5秒**)仍不能返回结果后,数据库请求会报超时错误。
这里介绍如何进行查询优化以避免此类问题。
......
......@@ -392,4 +392,8 @@ let's encrypt于2021年9月30日根证书过期并切换到新版根证书。详
### 调用云函数时出现“Unauthenticated access is denied”@access-denied
如使用腾讯云作为服务商,出现此问题时请检查前端是否有执行clearStorage操作。clearStorage会清理掉腾讯云设置的token,导致请求云函数报错。
\ No newline at end of file
如使用腾讯云作为服务商,出现此问题时请检查前端是否有执行clearStorage操作。clearStorage会清理掉腾讯云设置的token,导致请求云函数报错。
### 阿里云存储在部分地区、运营商无法访问的问题
阿里云云存储目前没有服务空间级别的域名隔离,因此在有服务空间的云存储因为违法、违规被封禁域名时会影响其他服务空间。阿里云提供了一个备用CDN域名`vkceyugu-backup.cdn.bspapp.com`,替换原CDN域名`vkceyugu.cdn.bspapp.com`
\ No newline at end of file
......@@ -509,7 +509,7 @@ new db.Geo.MultiPolygon([
|腾讯云 |阿里云 |
|-- |-- |
|5秒 |3秒 |
|5秒 |5秒 |
如果是大数据批处理,可以参考云函数递归调用,连续执行多个云函数处理一个任务[详情查看](uniCloud/cf-functions.md?id=recurrence)
......
......@@ -28,7 +28,9 @@ DCloud为开发者提供了`uni发布平台`,包括网站发布、App发布和
`前端网页托管`和云函数没有绑定关系,可以和云函数部署在一个服务空间,也可以是不同的空间,甚至是不同云服务商的空间。
- 阿里云`前端网页托管`免费。
- 腾讯云`前端网页托管`需付费开通,定价由腾讯云提供。腾讯云的不同档套餐有不同规格,见文末附表:
- 腾讯云`前端网页托管`需付费开通,定价由腾讯云提供。由于腾讯云新计费已上线,新计费模式下前端网页托管仅支持按量计费模式,原包年包月套餐已下线。
现存包年包月`前端网页托管`,如果服务空间升级到新套餐,则`前端网页托管`会自动切换为按量计费模式,请确保余额充足。
## 使用
......
......@@ -27,7 +27,7 @@ uniCloud提供包月、按量计费两种计费方式(仅腾讯云),具体
|云函数定时触发最小间隔 |1小时 |- |
|云存储容量 |10GB |- |
|云数据库容量 |100GB |- |
|单次数据库执行时长限制 |3秒 |**不可申请调整** |
|单次数据库执行时长限制 |5秒 |**不可申请调整** |
尤其注意阿里云的cdn确实是全免费的,这些免费资源可用于正常公司业务,阿里云不允许开发者使用这些免费的存储及CDN资源来开展图床类业务。
......@@ -106,6 +106,8 @@ uniCloud提供包月、按量计费两种计费方式(仅腾讯云),具体
- 在正式进行计费方式切换之日起,用户将不可继续续费或新购旧版套餐或按量计费服务空间。用户可选择是否切换新的计费方式,超时(2022.09.08)切换的服务空间将会停服释放。
**注:当包年包月服务空间升级新套餐时,如果已开通前端网页托管,则前端网页托管会自动转为按量计费,请确保账号余额充足!**
## 发生故障时如何判断故障点
当你的线上系统故障时,可以参考此文档判断责任归属:[如何判断是DCloud或阿里云或腾讯云的问题](https://uniapp.dcloud.io/uniCloud/faq?id=fault)
......
......@@ -160,6 +160,7 @@ HBuilderX自带一个云函数本地运行环境,运行项目时也默认选
- 虽然uni-app支持vscode等其他ide开发,但因为uniCloud对安全性要求极高,仅支持使用HBuilderX开发
- HBuilderX 也支持 cli。[详见](https://hx.dcloud.net.cn/cli/README)
## web控制台@webcp
web控制台网址:[https://unicloud.dcloud.net.cn](https://unicloud.dcloud.net.cn)
......
......@@ -42,7 +42,7 @@
**使用方式**
- 如果没有安装本地运行插件,按照提示安装即可
- 如需配置运行参数请参考:[配置运行测试参数](https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=runparam)
- 如需配置运行参数请参考:[配置运行测试参数](https://uniapp.dcloud.net.cn/uniCloud/rundebug.html#runparam)
<div align=center>
<img style="max-width:750px;" src="https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/cb5457a0-4b19-11eb-8ff1-d5dcf8779628.jpg"/>
......@@ -63,7 +63,7 @@
运行云函数时,如需要给云函数传参,又不想启动客户端,那么可以通过配置json文件来传测试参数。
在云函数对应的目录右键可以配置运行测试参数,如下图,选择之后会生成一个形如`${函数名}.param.json`的文件,此文件内容会在云函数`上传并运行`以及`本地运行云函数`时作为参数传入云函数内。详细用法可参考:[配置运行测试参数](https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=runparam)
在云函数对应的目录右键可以配置运行测试参数,如下图,选择之后会生成一个形如`${函数名}.param.json`的文件,此文件内容会在云函数`上传并运行`以及`本地运行云函数`时作为参数传入云函数内。详细用法可参考:[配置运行测试参数](https://uniapp.dcloud.net.cn/uniCloud/rundebug.html#runparam)
## 上传并运行云函数@uploadandrun
......@@ -288,6 +288,32 @@ const hour = getOffsetDate(8).getHours()
"uniIdToken": "xxxx"
}
```
<!--
## 运行云对象时传配置运行测试参数@run-obj-param
> 新增于HBuilderX 3.5.6
右键点击云对象时选择`运行-本地云对象``调试运行-本地云对象`时,会自动创建运行参数文件`${objName}.param.js`,可在此文件内以以下格式配置参数,配置完毕后再次运行即可。
其中`const clientInfo = {xxx}`为模拟客户端信息。完整clientInfo列表请参考:[getClientInfo](cloud-obj.md#get-client-info)
`login('xxx', 'xxx')`用于指定调用的方法名和参数。
```js
const clientInfo = { // 模拟clientInfo
uniPlatform: 'web',
source: 'client', // 调用来源,不传时默认为 client
clientIP: '127.0.0.1', // 客户端ip,不传时默认为 127.0.0.1
userAgent: 'xx MicroMessenger/xxx' // 客户端ua,不传时默认为 HBuilderX
uniIdToken: 'xxx',
}
login('name-demo', 'password-demo') // 调用login方法传入参数'name-demo'和'password-demo'
```
**注意**
- 此文件并非可执行的js文件,仅用来配置参数,因此不可在文件内定义变量并使用
- 如果存在多个方法、参数配置运行时会使用第一个 -->
## 断点调试云函数
......
......@@ -105,7 +105,8 @@
# 前端页面
## 初始化
你需要在App.vue中初始化`uni-id-pages``init.js`文件
需要在App.vue中初始化`uni-id-pages``init.js`文件
示例代码如下:
```js
<script>
......@@ -175,7 +176,8 @@ export default {
```
#### 调试模式@debug
debug模式下,启动应用会自动发起一次网络请求(调用`uni-id-co``getSupportedLoginType`),
debug模式下,启动应用会自动发起一次网络请求(调用`uni-id-co``getSupportedLoginType`)。
检查:uni-id-pages客户端配置的登录方式,是否未在uniCloud服务端配置正确,否则抛出异常。
#### 登录方式@loginTypes
......@@ -183,8 +185,8 @@ debug模式下,启动应用会自动发起一次网络请求(调用`uni-id-c
|-- |-- |-- |
|univerify |[一键登录](https://uniapp.dcloud.io/univerify.html) |App 3.0.0+|
|smsCode |短信验证码登录 ||
|weixin |微信登录 |App,微信小程序,H5(uni-id-pages 版本号1.0.8起支持,含微信公众号内的网页授权登录 和 普通浏览器内网页生成二维码,实现手机微信扫码登录) |
|apple |苹果登录[Apple登录](https://ask.dcloud.net.cn/article/36651) | iOS13+支持,App 2.4.7+|
|weixin |微信登录 |App,微信小程序,Web(uni-id-pages 版本号1.0.8起支持) |
|apple |苹果登录[Apple登录](https://uniapp.dcloud.io/tutorial/app-oauth-apple) | iOS13+支持,App 2.4.7+|
|username |用户名密码登录 ||
##### 配置示例
......@@ -215,7 +217,7 @@ export default {
}
```
**注意:** iOS的App Store应用规则:应用若支持三方社交登录服务(如:一键登录、微信登录等),则必须同时向用户提供“以苹果账号登录”的选项。即:如果你的应用不支持三方登录,那么可以不带上苹果登录,如果你的应用支持三方登录,那必须同时把苹果登录也带上。
**注意:** iOS 的 AppStore 规则:应用若支持三方社交登录服务(如:一键登录、微信登录等),则必须同时向用户提供“以苹果账号登录”的选项。即:如果你的应用不支持三方登录,那么可以不带上苹果登录,如果你的应用支持三方登录,那必须同时把苹果登录也带上。
以上配置仅开启前端登录入口,实现功能还需:
1. 开通对应登录方式服务,获得服务密钥,并在服务端`uni-id`模块的配置文件中完成配置。详情查看:[登录服务开通与配置](#登录服务开通与配置)
......@@ -235,11 +237,11 @@ export default {
|register |String |注册(包括注册并登录,如:微信登录、苹果登录、短信验证码登录) |
|login |String |登录(如:用户名密码登录) |
一款规范的小程序或要上架到国内应用商店app必须提供《隐私政策和用户使用协议》,参考模版:[隐私权政策模板.zip](https://ask.dcloud.net.cn/file/download/file_name-6ZqQ56eB5p2D5pS/562W5qih5p2/LnppcA==__url-Ly9pbWctY2RuLXRjLmRjbG91ZC5uZXQuY24vdXBsb2Fkcy9hcnRpY2xlLzIwMjAwMjE0LzUyMDRmMWU2Y2Q3NjcwZWE0YTJjMjBmZGRhMTBhMDdh)
一款规范的小程序或App要上架到国内应用商店必须提供《隐私政策和用户使用协议》,参考模版:[隐私权政策模板.zip](https://ask.dcloud.net.cn/file/download/file_name-6ZqQ56eB5p2D5pS/562W5qih5p2/LnppcA==__url-Ly9pbWctY2RuLXRjLmRjbG91ZC5uZXQuY24vdXBsb2Fkcy9hcnRpY2xlLzIwMjAwMjE0LzUyMDRmMWU2Y2Q3NjcwZWE0YTJjMjBmZGRhMTBhMDdh)
更多合规问题[详情参考](https://uniapp.dcloud.io/tutorial/android-store.html#app%E5%9B%A0%E5%90%88%E8%A7%84%E9%97%AE%E9%A2%98%E6%97%A0%E6%B3%95%E4%B8%8A%E6%9E%B6)
推荐使用:HBuilderX编辑器,以markdown文档格式编辑《隐私政策和用户使用协议》,通过在文档中鼠标右键[一键分享](https://ask.dcloud.net.cn/article/37573)上传到[前端网页托管](hosting.md#%E7%AE%80%E4%BB%8B)获得链接
推荐使用:HBuilderX编辑器,以markdown文档格式编辑《隐私政策和用户使用协议》,通过在文档中鼠标右键[一键分享](https://hx.dcloud.net.cn/Tutorial/extension/markdown_share)上传到[前端网页托管](hosting.md)获得链接
#### 接入各类服务(如微信登录服务)的应用id@appid
......@@ -260,12 +262,14 @@ export default {
|weak |String |弱:密码必须包含字母 |
## 页面介绍
`uni-id-pages`包含:账号注册、免密登录、头像更换、修改昵称、绑定手机号码、找回密码、注销账号等页面。[详情查看](https://ext.dcloud.net.cn/plugin?name=uni-id-pages)
`uni-id-pages`包含:账号注册、免密登录、头像更换、修改昵称、绑定手机号码、找回密码、注销账号等页面。[插件地址](https://ext.dcloud.net.cn/plugin?name=uni-id-pages)
项目中常有打开登录页面的需求,这里对登录页面展开介绍;包括两类登录方式:
- 密码登录(账号密码登录),页面路径: `/uni_modules/uni-id-pages/pages/login/login-withpwd`
- 免密登录(一键登录,短信验证码登录,微信登录,苹果登录),页面路径: `/uni_modules/uni-id-pages/pages/login/login-withoutpwd`
执行`uni.navigateTo`打开登录页面,会默认使用配置中`loginTypes`值的第一项为登录方式。
例如`loginTypes``["weixin","apple","univerify"]`会以`weixin`,即`微信登录`为默认登录方式
`uni-id-pages`支持通过传递参数`type`,指定登录方式。例如:指定苹果登录,使用如下代码即可
......@@ -559,6 +563,40 @@ await uniIdCo.loginByWeixin({
|&nbsp;&#124;-&nbsp;token |string |token |
|&nbsp;&#124;-&nbsp;tokenExpired|string |token过期时间 |
**注意**
- 支持的登录方式:微信小程序、微信公众号、App、web站微信扫码登录
- 微信登录会自动保存用户的openid,在`uni-id-pages 1.0.8`及更高版本在存储openid时会同时存储一份以当前应用的Appid(manifest.json内的DCloud AppId)为key的openid,见下方关于openid的说明。
- 如果有多个应用同时使用微信小程序登录,且希望用户身份不隔离请确保这些应用在微信小程序平台为同一主体所有,即保证不同应用可以获取同样的unionid
- `uni-id-pages 1.0.8`及以上版本会使用uni-open-bridge-common保存`session_key`(微信小程序登录)、`access_token`(微信公众号登录、微信App登录)这些信息,但是为了兼容旧版逻辑仍在用户表存储了一份副本。详细说明参考:[自动保存用户sessionKey、accessToken等信息](uni-id-summary.md#save-user-token)
**关于openid的说明**
`uni-id-pages 1.0.7`及之前的版本会将微信的openid存为如下格式
```js
{
"_id": "xx",
"wx_openid": {
"mp": "weixin-openid-demo"
}
}
```
可以看到如果存在多个微信小程序应用连接一个uniCloud后台且关联同一个账号,此时只能存储一个小程序的openid。
`uni-id-pages 1.0.8`版本对此进行了调整修正,多个DCloud Appid可以对应不同的微信openid。以Appid`__UNI_123456`为例,openid会在数据库内存储为以下形式:
```js
{
"_id": "xx",
"wx_openid": {
"mp": "weixin-openid-demo",
"mp___UNI_123456": "weixin-openid-demo",
}
}
```
#### QQ登录@login-by-qq
QQ账号已存在时登录,否则注册
......@@ -592,6 +630,38 @@ await uniIdCo.loginByQQ({
|&nbsp;&#124;-&nbsp;token |string |token |
|&nbsp;&#124;-&nbsp;tokenExpired|string |token过期时间 |
**注意**
- 支持的登录方式:QQ小程序、QQ App
- QQ登录会自动保存用户的openid,在`uni-id-pages 1.0.8`及更高版本在存储openid时会同时存储一份以当前应用的Appid(manifest.json内的DCloud AppId)为key的openid,见下方关于openid的说明。
- 如果有多个应用同时使用QQ小程序登录,且希望用户身份不隔离请确保这些应用在QQ小程序平台为同一主体所有,即保证不同应用可以获取同样的unionid
- `uni-id-pages 1.0.8`及以上版本会使用uni-open-bridge-common保存session_key(QQ小程序登录)、access_token(QQ App登录)这些信息,但是为了兼容旧版逻辑仍在用户表存储了一份副本。详细说明参考:[自动保存用户sessionKey、accessToken等信息](uni-id-summary.md#save-user-token)
**关于openid的说明**
`uni-id-pages 1.0.7`及之前的版本会将QQ的openid以以下形式存储
```js
{
"_id": "xx",
"qq_openid": {
"mp": "weixin-openid-demo"
}
}
```
可以看到如果存在多个QQ小程序关联同一个账号,这时候只能存储一个小程序的openid,在`uni-id-pages 1.0.8`版本对此进行了调整以Appid`__UNI_123456`为例,openid会在数据库内存储为以下形式
```js
{
"_id": "xx",
"qq_openid": {
"mp": "weixin-openid-demo",
"mp___UNI_123456": "weixin-openid-demo",
}
}
```
#### 支付宝登录@login-by-alipay
支付宝账号已存在时登录,否则注册
......@@ -800,7 +870,11 @@ await uniIdCo.bindMobileByUniverify({
#### 通过微信绑定手机号@bind-mobile-by-mp-weixin
使用此接口时务必注意,微信小程序的规则是客户端应先使用checkSession接口检测上次获取的sessionKey是否仍有效。如果有效则直接使用上次存储的sessionKey即可,如果无效应重新调用login接口再次刷新sessionKey。微信小程序登录,绑定小程序微信账号时会自动更新用户表的sessionKey。
使用此接口时务必注意,微信小程序的规则是客户端应先使用checkSession接口检测上次获取的sessionKey是否仍有效。
如果有效则直接使用上次存储的sessionKey即可,如果无效应重新调用login接口再次刷新sessionKey。
微信小程序登录、绑定小程序微信账号时会自动更新用户的sessionKey。
**接口形式**
......@@ -1447,7 +1521,11 @@ module.exports = {
uni-id-pages已全面支持:app、小程序、web(uni-id-pages 版本号1.0.8起),三端的微信登录。
微信将应用分为4类:`移动应用``网站应用``公众帐号``小程序`
微信将应用分为4类:
1. 移动应用:指非微信的App,调用微信登陆。属于微信开放平台[微信开放平台账号](https://open.weixin.qq.com/)
2. 网站应用:指微信外的浏览器网页,通过手机微信扫码等方式调用微信登录。属于微信开放平台[微信开放平台账号](https://open.weixin.qq.com/)
3. 公众帐号:指在微信内置浏览器访问公众号H5。属于微信公众号平台[https://mp.weixin.qq.com/](https://mp.weixin.qq.com/)
4. 小程序:指微信内的小程序。属于微信公众号平台[https://mp.weixin.qq.com/](https://mp.weixin.qq.com/)
这里的`网站应用``公众帐号`都是给web应用,接入微信登录功能。但有如下区别:
......@@ -1457,21 +1535,26 @@ uni-id-pages已全面支持:app、小程序、web(uni-id-pages 版本号1.0.
|普通浏览器 |网站应用 |手机微信扫码登录 |
### 是否申请[微信开放平台账号](https://open.weixin.qq.com/)?
### 如何选择微信开放平台和微信公众平台
- 如果你的应用只运行在`微信内`,不管是微信小程序还是微信公众号H5,都属于[微信公众平台](https://open.weixin.qq.com/)
- 如果你的应用运行在`微信外`,不管是其他App还是微信外的其他网页,都属于[微信开放平台](https://open.weixin.qq.com/)
根据你的需求开通相应平台账户即可。
如果你的应用只有微信小程序端,或者只运行在微信app内才支持登录的web端。那就无需开通`微信开放平台账号`,开通`小程序`或者`公众帐号`即可。
**注意**
而以下两种情况必须开通`微信开放平台账号`
1. `APP端,微信授权登录``web端,手机微信扫码登录`,必须开通[微信开放平台账号](https://open.weixin.qq.com/),创建`移动应用``网站应用`才能接入微信登录。
2. 如果你的应用有多端,实现同一个用户在公众号、小程序、APP、官方网站等不同场景里的身份统一识别、信息同步和行为跟踪(详情参考:[“UnionID关联”功能介绍及运营建议](https://developers.weixin.qq.com/community/business/doc/00024a52cec260f09b69c704e5b00d)就需要将`小程序``公众帐号`绑定到同一个`微信开放平台账号`下。
* 绑定方式:登录[微信开放平台](https://open.weixin.qq.com/) -> `管理中心` -> 选择`公众号/小程序` -> 点击`绑定公众号/小程序`
如果你的应用有多端,实现同一个用户在公众号、小程序、APP、官方网站等不同场景里的身份统一识别、信息同步和行为跟踪
(详情参考:[“UnionID关联”功能介绍及运营建议](https://developers.weixin.qq.com/community/business/doc/00024a52cec260f09b69c704e5b00d)
就需要将`小程序``公众帐号`绑定到同一个`微信开放平台账号`下。
* 绑定方式:登录[微信开放平台](https://open.weixin.qq.com/) -> `管理中心` -> 选择`公众号/小程序` -> 点击`绑定公众号/小程序`
### 客户端配置
- APP端
- APP端
* 打开`manifest.json` ->`App模块配置` -> `OAuth(登录鉴权)` -> `勾选微信登录` -> 填写`appid``ios平台通用链接`
* iOS平台微信登录SDK需要配置通用链接,详情参考:[https://uniapp.dcloud.io/api/plugins/universal-links.html](https://uniapp.dcloud.io/api/plugins/universal-links.html)
- 小程序端打开`manifest.json` -> `微信小程序配置` -> 填写微信小程序AppID
- web端打开`/uni_modules/uni-id-pages/config.js` -> `appid` -> `weixin``h5`节点配置微信公众号的appid,`web`节点配置微信开放平台创建的网站应用appid
- 小程序端打开`manifest.json` -> `微信小程序配置` -> 填写微信小程序AppID
- web端打开`/uni_modules/uni-id-pages/config.js` -> `appid` -> `weixin``h5`节点配置微信公众号的appid,`web`节点配置微信开放平台创建的网站应用appid
### 服务端配置
* 服务端`uni-id`的密钥信息统一在`uni-config-center`中配置,路径:`uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json`,完整的配置信息[详情查看](uni-id-summary.md#config)
......@@ -1483,8 +1566,10 @@ uni-id-pages已全面支持:app、小程序、web(uni-id-pages 版本号1.0.
2. 进入授权页面,用户同意授权得到code;以get参数的形式携带code,重定向至步骤1填写的redirect_uri
3. 回到应用页面,拿到code值调用`uni-id-co`云对象的`loginByWeiXin`方法,得到`token`完成登录
`appid`说明:微信app内打开的网页,为公众号的appid。其他场景则为在`微信开放平台`创建的`网站应用`的appid。
`redirect_uri`说明:进入授权页面后返回的网站链接,此链接的域名需要先在服务后台配置,详情查看:[回调域名的配置](#redirect_uri)
- `appid`说明:微信app内打开的网页,为公众号的appid。其他场景则为在`微信开放平台`创建的`网站应用`的appid。
- `redirect_uri`说明:进入授权页面后返回的网站链接,此链接的域名需要先在服务后台配置,详情查看:[回调域名的配置](#redirect_uri)
示例代码已经在uni-id-pages插件中提供。
#### 回调域名的配置@redirect_uri
......@@ -1520,7 +1605,6 @@ host文件路径: Windows系统一般为:`C:\Windows\System32\drivers\etc`
- 教程参考[短信服务开通指南](https://ask.dcloud.net.cn/article/37534)
- 密钥配置:`uni-id配置文件` --> `service` --> `sms` 填写相关密钥信息。
# 从老版uni-id公共模块升级到uni-id-pages
在HBuilderX 3.5之前,DCloud提供了一个公共模块[uni-id](https://ext.dcloud.net.cn/plugin?id=2116)(注意别和uni-id-common混淆)和一个示例性云函数uni-id-cf(集成在uni-starter和uni-admin中)。
......
......@@ -194,6 +194,7 @@ uni-id的云端配置文件在`uniCloud/cloudfunctions/common/uni-config-center/
// 如果拷贝此内容切记去除注释
{
"passwordSecret": "passwordSecret-demo", // 数据库中password字段是加密存储的,这里的passwordSecret即为加密密码所用的密钥,注意修改为自己的密钥,使用一个较长的字符串即可
"passwordStrength": "strong", // 密码强度,新增于 uni-id-pages 1.0.8版本,见下方说明
"tokenSecret": "tokenSecret-demo", // 生成token所用的密钥,注意修改为自己的,使用一个较长的字符串即可
"tokenExpiresIn": 7200, // 全平台token过期时间,未指定过期时间的平台会使用此值
"tokenExpiresThreshold": 600, // 新增于uni-id 1.1.7版本,checkToken时如果token有效期小于此值且在有效期内则自动获取新token,请注意将新token返回给前端保存(云对象会自动保存符合uniCloud响应体规范的响应内的新token),如果不配置此参数则不开启自动获取新token功能
......@@ -220,7 +221,17 @@ uni-id的云端配置文件在`uniCloud/cloudfunctions/common/uni-config-center/
}
},
"web": { // 如果你使用旧版本uni-id公共模块而不是uni-id-common这里可能配置的是h5,务必注意调整为web
"tokenExpiresIn": 14400,
"tokenExpiresIn": 259200,
"oauth": {
"weixin-h5": { // 微信公众号登录配置
"appid": "weixin appid",
"appsecret": "weixin appsecret"
},
"weixin-web": { // 微信PC页面扫码登录配置
"appid": "weixin appid",
"appsecret": "weixin appsecret"
}
}
},
"mp-weixin": {
"tokenExpiresIn": 259200,
......@@ -259,12 +270,12 @@ uni-id的云端配置文件在`uniCloud/cloudfunctions/common/uni-config-center/
"codeExpiresIn": 180, // 验证码过期时间,单位为秒,注意一定要是60的整数倍
"smsKey": "your sms key", // 短信密钥key,开通短信服务处可以看到
"smsSecret": "your sms secret", // 短信密钥secret,开通短信服务处可以看到
"scene": {
"bind-mobile": { // 对绑定手机号场景的配置
"templateId": "your template id", // 绑定手机号使用的短信验证码模板
"codeExpiresIn": 240 // 绑定手机号验证码过期时间
}
}
"scene": {
"bind-mobile": { // 对绑定手机号场景的配置
"templateId": "your template id", // 绑定手机号使用的短信验证码模板
"codeExpiresIn": 240 // 绑定手机号验证码过期时间
}
}
},
"univerify": {
"appid": "your appid", // 当前应用的appid,使用云函数URL化,此项必须配置
......@@ -275,7 +286,7 @@ uni-id的云端配置文件在`uniCloud/cloudfunctions/common/uni-config-center/
}
```
**关于token自动刷新**
### token自动刷新@auto-refresh-token
tokenExpiresThreshold用于指定token还有多长时间过期时自动刷新token。
......@@ -283,6 +294,43 @@ tokenExpiresThreshold用于指定token还有多长时间过期时自动刷新tok
在token还有5分钟过期时调用checkToken接口会返回新的token和新的token的过期时间(新token有效时间也是2小时)。
### 密码强度@password-strength
> 新增于uni-id-pages 1.0.8
支持以下四种内置规则
```js
{
// 密码必须包含大小写字母、数字和特殊符号
super: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/,
// 密码必须包含字母、数字和特殊符号
strong: /^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/,
// 密码必须为字母、数字和特殊符号任意两种的组合
medium: /^(?![0-9]+$)(?![a-zA-Z]+$)(?![~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]+$)[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/,
// 密码必须包含字母和数字
weak: /^(?=.*[0-9])(?=.*[a-zA-Z])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{6,16}$/
}
```
uni-id-co 与 uni-id-pages 内的前端页面均支持这四个内置规则,如需自定义规则,请参考:[uni-id-co自定义校验规则](uni-id-pages.md#custom-validator)
### 登录方式及配置说明@login-and-config
|登录方式 |配置及获取方式 |
|-- |-- |
|用户名、手机号、邮箱+密码|配置`passwordSecret`即可 |
|手机号+验证码 |配置`service.sms`,在开发者中心短信服务内获取配置信息:[短信服务](https://dev.dcloud.net.cn/#/pages/sms/base) |
|手机号一键登录 |配置`service.univerify`,在开发者中心一键登录服务内获取:[一键登录](https://dev.dcloud.net.cn/#/pages/uniLogin/index) |
|微信小程序登录 |配置`mp-weixin.oauth.weixin`,在微信公众平台获取:[微信公众平台](https://mp.weixin.qq.com/) |
|微信公众号登录 |配置`web.oauth.weixin-h5`,在微信公众平台获取:[微信公众平台](https://mp.weixin.qq.com/) |
|微信PC页面扫码登录 |配置`web.oauth.weixin-web`,在微信开放平台获取:[微信开放平台](https://open.weixin.qq.com/) |
|微信APP端登录 |配置`app.oauth.weixin`,在微信开放平台获取:[微信开放平台](https://open.weixin.qq.com/) |
|QQ 小程序端登录 |配置`mp-qq.oauth.qq`,在QQ开放平台获取:[QQ开放平台](https://q.qq.com/) |
|QQ APP端登录 |配置`app.oauth.qq`,在QQ互联获取:[QQ互联](https://connect.qq.com/) |
|支付宝小程序端登录 |配置`mp-alipay.oauth.alipay`,在支付宝开放平台获取:[支付宝开放平台](https://openhome.alipay.com/develop/manage) |
|Apple APP端登录 |配置`app.oauth.apple`,在Apple开发者中心自行配置:[Apple开发者中心](https://developer.apple.com/account/resources/identifiers/list)|
## token令牌
首先解释下token的概念。token是服务器颁发给客户端的一个令牌。
......@@ -297,7 +345,7 @@ tokenExpiresThreshold用于指定token还有多长时间过期时自动刷新tok
在传统开发下,客户端和服务器各自需要为了token做很多事情。在uni云端一体下,开发者无需操心,只需要在uni-id云端config.json中配置好token的secret和有效期即可。剩余的工作都被自动处理了。
uni-id云端会在login方法成功后自动返回token,uni-app前端框架会自动识别并保存这个token在storage中(uni-id-token),在前端每次连接uniCloud(不管是clientDB、callfunction、云对象调用),都会自动带上这个token。
uni-id云端会在login方法成功后自动返回token,uni-app前端框架会自动识别并保存这个token在storage中(uni_id_token),在前端每次连接uniCloud(不管是clientDB、callfunction、云对象调用),都会自动带上这个token。
云函数和云对象都提供了获取和校验token的方法,在uni-id相关业务中,校验token的代码都已经写好。
......@@ -770,7 +818,7 @@ uniIdRouter 是一个运行在前端的、对前端页面访问权限路由进
```
以上代码,指定了登录页为首页`index`,然后将`list`页面和`detail`目录下的所有页面,设为需要登录才能访问。那么访问`list`页面和`detail`目录下的页面时,如果客户端未登录或登录状态过期(也就是uni-id-token失效),那么会自动跳转到`index`页面来登录。
以上代码,指定了登录页为首页`index`,然后将`list`页面和`detail`目录下的所有页面,设为需要登录才能访问。那么访问`list`页面和`detail`目录下的页面时,如果客户端未登录或登录状态过期(也就是uni_id_token失效),那么会自动跳转到`index`页面来登录。
与此功能对应的有两个uniCloud客户端api,`uniCloud.onNeedLogin()``uniCloud.offNeedLogin()`,开发者在监听onNeedLogin事件后,框架就不再自动跳转到登录页面,而是由开发者在onNeedLogin事件内自行处理。详情参考:[uniCloud.onNeedLogin](uniCloud/client-sdk.md?id=on-need-login)
......@@ -868,7 +916,7 @@ module.exports = {
**注意**
- pages.json内有`uniIdRouter`节点上述逻辑才会生效,自HBuilderX 3.5.0起创建空项目模板会自动配置空的`uniIdRouter`节点
- uniIdRouter底层使用navigateTo、redirectTo、reLaunch、switchTab的拦截器进行页面跳转拦截,不会拦截进入首页和点击原生tabbar
- uniIdRouter底层使用navigateTo、redirectTo、reLaunch、switchTab的拦截器进行页面跳转拦截,不会拦截进入首页,web端和app端会拦截原生tabbar点击,其他端不会拦截原生tabbar点击
一般tabbar页面都不做自动跳转,而是在页面内再提供登录按钮。比如tabbar上有购物车或个人中心,点击购物车后在购物车页面内部会放一个提示语和按钮,告知用户需要登录。
在页面内判断用户是否登录,使用API[uniCloud.getCurrentUserInfo()](client-sdk.md#client-getcurrentuserinfo)
......@@ -1113,3 +1161,92 @@ module.exports = {
```
uni-id会自动进行语言匹配,无需额外配置
### 自动保存用户sessionKey、accessToken等信息@save-user-token
uni-id-co在微信、QQ登录或注册时会自动保存用户的sessionKey、accessToken信息。
`uni-id-pages 1.0.8`之前,uni-id-co直接将这些信息保存在了用户表(uni-id-users)的third_party字段下,仅按照平台区分没有按照不同应用区分。具体结构如下
```js
{
"_id": "uid",
"wx_unionid": "xxx",
"qq_unionid": "xxx",
"third_party": {
"mp_weixin": {
"session_key": "xxxx"
},
"app_weixin": {
"access_token": "accessToken",
"access_token_expired": 1111
},
"mp_qq": {
"session_key": "xxxx"
},
"app_qq": {
"access_token": "accessToken",
"access_token_expired": 1111
}
}
}
```
此结构无法满足多应用同一平台关联同一服务空间且允许用户跨应用登录的场景。因此在`uni-id-pages 1.0.8`及更高版本对此做出了调整,改为使用[uni-open-bridge-common](uni-open-bridge.md#uni-open-bridge-common)存储用户在三方平台的凭据信息。同时为了兼容旧版本上述third_party字段仍存有这些信息。
目前被`uni-id-co`保存的三方凭据有以下几种:
- 微信小程序端用户session_key,通过`uni-open-bridge-common``setSessionKey`方法写入
- 微信公众号页面用户access_token,通过`uni-open-bridge-common``setUserAccessToken`方法写入
- 微信web页面扫码登录时返回的用户access_token,通过`uni-open-bridge-common``setUserAccessToken`方法写入
- 微信APP登录时返回的用户access_token,通过`uni-open-bridge-common``setUserAccessToken`方法写入
- QQ小程序端用户session_key,通过`uni-open-bridge-common``setSessionKey`方法写入
- QQ APP登录时返回的用户access_token,通过`uni-open-bridge-common``setUserAccessToken`方法写入
### 钩子@hooks
> 新增于 uni-id-pages 1.0.8
uni-id-co是一个完整的云对象,里面注册登录等流程都已完全实现,开发者不方便进行修改。例如要实现注册时为某端用户统一添加一个角色的功能,只能去修改uni-id-co的代码。因此uni-id-co提供了通过钩子干涉内置逻辑的功能
uni-id钩子函数需要在uni-config-center内配置。在`uni-config-center/uni-id`下创建hooks目录并在其内创建`index.js`内容如下
```js
module.exports = {
beforeRegister: function (){
// 注册前钩子
}
}
```
#### beforeRegister@before-register
beforeRegister在注册用户记录入库前触发。钩子会接收到如下参数,需要返回处理后的用户记录用以入库存储
|参数名 |类型 |说明 |
|-- |-- |-- |
|userRecord |Object |即将入库的用户记录 |
|clientInfo |Object |客户端信息,参考:[云对象 getClientInfo](cloud-obj.md#get-client-info) |
以为__UNI_123123这个应用注册的用户添加"teacher"角色为例,beforeRegister钩子示例如下
```js
// 钩子函数示例 hooks/index.js
function beforeRegister({
userRecord,
clientInfo
} = {}) {
if(clientInfo.appId === '__UNI_123123') {
if(userRecord.role) {
userRecord.role.push('teacher')
} else {
userRecord.role = ['teacher']
}
}
}
module.exports = {
beforeRegister
}
```
\ No newline at end of file
# uni-open-bridge
`uni-open-bridge` 是统一接管微信等三方平台认证凭据(包括但不限于`access_token``session_key``encrypt_key``ticket`)的开源库
开发者对接微信等三方开放平台时,这些开放平台有众多的凭据需要管理,比如`access_token``session_key``encrypt_key``ticket`
## 背景
`uni-open-bridge` 是一个统一管理微信等三方平台认证凭据的开源工具。
调用微信等三方开放平台时,涉及众多凭据。有的是固定凭据,没有有效期。有的是临时凭据,会在一定时间或一定操作后失效。
## 背景
尤其是临时凭据,比如微信的`access_token``session_key``encrypt_key``ticket`, 开发者需要动态从微信服务器获取,统一保存
调用微信等三方开放平台时,涉及众多凭据
但实际上这里面的坑很多:
- 微信公众号h5、小程序、app、web各自都有若干凭据
- 有的是应用级凭据、有的是用户级凭据、有的是一次性凭据
- 有的从微信后台web界面复制,有的向微信服务器请求获得,有的需要先在客户端发起然后服务器再请求
- 有的凭据没有有效期,有的是临时凭据,会在一定时间或一定操作后失效,不同凭据的失效时间还不一样
- 有的凭据不能一直向微信服务器请求,有次数限制,需要自己缓存下来
1. 微信官方建议公众号开发者使用中控服务器统一获取和刷新 `access_token`,其他业务逻辑服务器所使用的 `access_token` 均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致 `access_token` 覆盖而影响业务;
2. 有的凭据有效期较短,比如`ticket` 的有效期为7200秒,需要定时请求,避免过期。并且由于获取 `ticket` 的 api 调用次数非常有限,频繁刷新 `ticket` 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存 `ticket `
3. 在客户端任意地方调用 `wx.login()` 后,会让上一个 `session_key` 立即过期
这里面容易搞混和出错的地方非常多。假使在不同的业务逻辑中都向微信服务器请求凭据,必然会冲突。
当多个业务都需要这些临时凭据时,无法让每个业务各自请求微信服务器,会非常混乱和容易冲突。
比如,
1. `ticket` 的有效期为7200秒,需要定时请求,避免过期。并且由于获取 `ticket` 的 api 调用次数非常有限,频繁刷新 `ticket` 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存 `ticket `
2. 在客户端任意地方调用 `wx.login()` 后,会让上一个 `session_key` 立即过期
3. 关于`access_token`,微信官方文档直接建议公众号开发者使用中控服务器统一获取和刷新 `access_token`,其他业务逻辑服务器所使用的 `access_token` 均来自于该中控服务器,不应该各自去微信服务器刷新,否则容易造成冲突。
所以需要在一个中央系统,在定时任务里统一请求微信服务器,保存到数据库。
所以需要在一个中央系统来统一管理这些凭据,需要定时请求的凭据则由中央系统定时统一请求微信服务器,保存到数据库。
然后各个业务需要这些凭据时,从这个中央系统的接口中获取,而不是自己向微信服务器请求。
这个中央系统就是`uni-open-bridge`
## 流程介绍
## 系统组成
`uni-open-bridge` 包括:
1. 一个云对象 `uni-open-bridge`
2. 一个公共模块 `uni-open-bridge-common`
3. 配套的数据库,表名为 `opendb-open-data`。在redis中的key格式为 `uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]`
1. 一个同名云对象 `uni-open-bridge`,插件下载地址:[https://ext.dcloud.net.cn/plugin?id=9002](https://ext.dcloud.net.cn/plugin?id=9002)。(其依赖了下面的公共模块,但不是一个插件)
2. 一个公共模块 `uni-open-bridge-common` ,插件下载地址:[https://ext.dcloud.net.cn/plugin?id=9177](https://ext.dcloud.net.cn/plugin?id=9177)。它独立为单独插件,是为了方便其他业务模块引用。事实上uni-id就引用了这个common插件。
3. 配套的数据库,保存这些凭据,表名为 [opendb-open-data](https://gitee.com/dcloud/opendb/blob/master/collection/opendb-open-data/collection.json)。在redis中的key格式为 `uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]`
`uni-open-bridge`系统中,有一个同名云对象`uni-open-bridge`,它默认就是定时运行的,在package.json中配置了每小时定时运行一次(部署线上系统生效)。
云对象`uni-open-bridge`默认是定时运行的,在package.json中配置了每小时定时运行一次(部署到线上服务空间后生效)。
该云对象根据在 `uni-config-center`[配置](#uni-id-config)固定凭据,从而有权定时向微信服务器发请求,将获取到的 `access_token``ticket` 保存到数据库 `opendb-open-data` 表中。
当所在服务空间开通redis时,还会缓存在redis的key。这会让系统性能更好。
上述获取到微信的各种临时凭据后,当各个业务代码需要这些凭据时,通过如下方式获取。
云对象`uni-open-bridge`还提供了URL化能力,以方便外部系统读写这些凭据。
[uni-open-bridge-common](#uni-open-bridge-common) 提供了操作微信等三方平台凭据的底层接口,包括访问微信服务器和多层读写Redis、数据库的能力。
云对象`uni-open-bridge`访问微信服务器和读写凭据时其实也是依赖 [uni-open-bridge-common](#uni-open-bridge-common)公共模块。安装 `uni-open-bridge` 云对象插件时会自动安装依赖插件 [uni-open-bridge-common](#uni-open-bridge-common)
从微信获取到各种凭据后,当各个业务代码需要这些凭据时,通过如下方式获取。
- 云函数/云对象获取这些临时凭据,可引用公共模块 `uni-open-bridge-common` ,通过该模块的API获取,比如getAccessToken。[见下](#uni-open-bridge-common)
- 非uniCloud系统,比如传统云,获取这些凭据,需要将云对象`uni-open-bridge`进行URL化,通过Http方式请求凭据。[见下](#http)
流程图如下:
![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-a90b5f95-90ba-4d30-a6a7-cd4d057327db/b80cec3b-e106-489d-9075-90b5ecb02963.png)
## 使用
1. **下载插件[uni-open-bridge](https://ext.dcloud.net.cn/plugin?id=9002)到项目中。
## 凭据介绍
### 凭据汇总
微信有公众号h5、小程序、App、web等4种平台,每个平台都有若干凭据。
微信提供了2个体系,公众平台和开放平台。
- 公众平台,[https://mp.weixin.qq.com/](https://mp.weixin.qq.com/),负责微信内的能力开放,即微信公众号H5和小程序,这2个都运行在微信内部。
- 开放平台,[https://open.weixin.qq.com/](https://open.weixin.qq.com/),负责微信外的系统来使用微信能力,即外部App和外部web站,这些外部应用来调用微信登录、微信支付等能力。
|凭据 |微信小程序 |微信公众号H5 |微信外的web站 |非微信的App|
|:-: |:-: |:-: |:-: |:-: |
|[access_token](#access_token) |定时刷新 |定时刷新 |开发者操作 |开发者操作 |
|[user_access_token](#user_access_token)|- |开发者操作 |- |- |
|[session_key](#session_key) |uni-id维护或开发者操作 |- |- |- |
|[encrypt_key](#encrypt_key) |[uni云端一体安全网络](secret-net)或开发者操作 |- |- |- |
|[ticket](#ticket) |- |定时刷新 |- |- |
- `定时刷新`:指由云对象 `uni-open-bridge` 的定时任务触发,自动从微信服务器获取凭据,通过调用 `uni-open-bridge-common` 写入到Redis或数据库
- `开发者操作`:指由开发者引入公共模块 `uni-open-bridge-common`,调用相关读写[方法](#uni-open-bridge-common)
- `session_key`: 如果使用了uni-id,则uni-id用户登陆时会自动读写该凭据。一般无需开发者维护。
- `encrypt_key` 依赖 `access_token``session_key`,如果依赖的值已存在,可直接读取 `encrypt_key`,如果不存在自动向微信服务器获取、开发者应该仅读取该值,如果使用了[uni云端一体安全网络](secret-net)由其维护,如果有不使用 `uni-open-bridge` 托管的[情况](#nouseuniopenbridge),则有外部系统操作
- `ticket` 依赖 `access_token`,直接获取 `ticket` 会检查 `access_token`,如果不存在默认先请求微信服务器获取并保存,继续请求 `ticket`
还有一些不常用的凭据暂不列出,例如:非微信的App平台的 access_token。
### 平台标记Platform@platform
`uni-open-bridge`中将不同平台命名如下表,在API和存储数据时都使用下表标记。注意不同于前端条件编译使用的uniPlatform。
|值 |描述 |
|:-: |:-: |
|weixin-mp |微信小程序 |
|weixin-h5 |微信公众号H5 |
|weixin-web |微信外的Web站 |
|weixin-app |非微信的App |
|qq-mp |QQ小程序 |
|qq-app |QQ外的App |
提示:自动刷新固定应用级凭据目前仅支持 `weixin-mp``weixin-h5`。 后续补充其他平台
### 常见凭据用途
- 微信小程序
1. 客户端登陆需要保存 [session_key](#session_key)
2. 解密用户敏感数据需要 [access_token](#access_token)[session_key](#session_key),例如:获取用户授权的手机号、用户敏感资料
3. 解密[uni云端一体安全网络](secret-net)通道使用的加密数据需要 [access_token](#access_token)[session_key](#session_key)[encrypt_key](#encrypt_key)
- 微信公众号
1. 微信内公众号H5页面用户登陆需要用到 [user_access_token](#user_access_token)[ticket](#ticket)
微信凭据分应用级、用户级、一次性等凭据,如果你之前未接触过微信这些凭据,请务必阅读下面的**每个凭据的详细介绍**
### access_token(应用级)@access_token
- 微信小程序 `access_token` 是微信小程序全局唯一后台接口调用凭据,调用绝大多数后台接口时都需使用。[详情](https://developers.weixin.qq.com/miniprogram/dev/framework/server-ability/backend-api.html#access_token)
- 微信公众号H5 `access_token` 是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用 `access_token`。开发者需要进行妥善保存。`access_token` 的存储至少要保留512个字符空间。`access_token` 的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的 `access_token` 失效。
**注意:微信公众号H5`access_token`的获取需要固定IP,需将IP白名单填入到微信公众平台。uniCloud中默认没有固定IP,获取固定IP需另见文档[固定IP](cf-functions.md#eip)**
公众平台的 API 调用所需的 `access_token` 的使用及生成方式说明:
1、建议公众号开发者使用中控服务器统一获取和刷新 `access_token`,其他业务逻辑服务器所使用的 `access_token` 均来自于该中控服务器,不应该各自去微信服务器刷新,否则容易造成冲突,导致 `access_token` 覆盖而影响业务;
2、目前`access_token` 的有效期通过返回的expires_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新 `access_token`。在刷新过程中,中控服务器可对外继续输出的老 `access_token`,此时公众平台后台会保证在5分钟内,新老 `access_token` 都可用,这保证了第三方业务的平滑过渡;
3、`access_token` 的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新 `access_token` 的接口,这样便于业务服务器在 API 调用获知 `access_token` 已超时的情况下,可以触发 `access_token` 的刷新流程。
4、对于可能存在风险的调用,在开发者进行获取 `access_token` 调用时进入风险调用确认流程,需要用户管理员确认后才可以成功获取。具体流程为:
开发者通过某 IP 发起调用->平台返回错误码[89503]并同时下发模板消息给公众号管理员->公众号管理员确认该 IP 可以调用->开发者使用该 IP 再次发起调用->调用成功。
如公众号管理员第一次拒绝该 IP 调用,用户在1个小时内将无法使用该 IP 再次发起调用,如公众号管理员多次拒绝该 IP 调用,该 IP 将可能长期无法发起调用。平台建议开发者在发起调用前主动与管理员沟通确认调用需求,或请求管理员开启 IP 白名单功能并将该 IP 加入 IP 白名单列表。
### user_access_token(用户级)@user_access_token
微信公众号H5平台有两个相同名字 `access_token`,分别用于
2.`uni-config-center``uni-id` 下配置固定凭据,详情见下面的示例代码
1、应用级:公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用 `access_token`
2、用户级:网页授权接口调用凭证,用户授权的作用域 `access_token`
众多凭据命名都叫`access_token`,无法有效区分。对于用户级的`access_token`**在 uni-open-bridge 中改名为** `user_access_token` 。它对应微信公众平台网页用户授权 `access_token`
|平台 |值 |描述 |
|:-: |:-: |:-: |
|微信公众号H5 |access_token |微信公众号H5用户会话密钥。[详情](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html) |
### code(临时凭据)@code
微信小程序用户登录凭证校验
在客户端通过调用 `uni.login()` 获得临时登录凭证 `code` 后传到开发者服务器在请求微信服务器获得 `session_key``openid``unionid`
`code` 仅可在服务器使用一次,客户端调用频率限制每个用户每分钟100次。
所以`uni-open-bridge`中并没有持续化存储code。
### openid(用户级)@openid
微信小程序用户唯一标识
需要在开发者服务器请求微信服务器获得,依赖参数 code,[详情](#code)
`uni-open-bridge`中并没有持续化存储openid,相关读写和保存是交由另一个插件`uni-id`来负责的。
可通过 `uni-id-co` 获取,[详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id-summary.html#save-user-token)
### session_key(用户级)@session_key
平台对应的值
|平台 |值 |描述 |
|:-: |:-: |:-: |
|微信小程序 |session_key|微信小程序会话密钥。[详情](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html) |
会话密钥 `session_key` 有效性
开发者如果遇到因为 `session_key` 不正确而校验签名失败或解密失败,请关注下面几个与 `session_key` 有关的注意事项。
`uni.login` 调用时,用户的 `session_key` 可能会被更新而致使旧 `session_key` 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 `uni.login`,并非每次调用都导致 `session_key` 刷新)。
开发者应该在明确需要重新登录时才调用 `uni.login`,及时通过 `code2Session` 接口更新服务器存储的 `session_key`
微信不会把 `session_key` 的有效期告知开发者,会根据用户使用小程序的行为对 `session_key` 进行续期。用户越频繁使用小程序,`session_key` 有效期越长。
开发者在 `session_key` 失效时,可以通过重新执行登录流程获取有效的 `session_key`。使用接口 [uni.checkSession](https://uniapp.dcloud.net.cn/api/plugins/login.html#uni-checksession) 可以校验 `session_key` 是否有效,从而避免小程序反复执行登录流程。
当开发者在实现自定义登录态时,可以考虑以 `session_key` 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。
### encrypt_key(用户级)@encrypt_key
为了避免微信小程序与开发者后台通信时数据被截取和篡改,微信侧维护了一个用户维度的可靠key,用于小程序和后台通信时进行加密和签名。[详情](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/user-encryptkey.html)
开发者可以分别通过小程序前端和微信后台提供的接口,获取用户的加密 key。
### ticket(用户级)@ticket
`ticket` 是微信公众号用于调用微信 JS 接口的临时票据。正常情况下,`ticket` 的有效期为7200秒,通过 `access_token` 来获取。
由于获取 `ticket` 的 api 调用次数非常有限,频繁刷新 `ticket` 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存 `ticket `[详情](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62)
而在`uni-open-bridge`已经缓存了该凭据。
## uni-open-bridge的使用流程
### 1. **下载插件[uni-open-bridge](https://ext.dcloud.net.cn/plugin?id=9002)到项目中。
### 2. `uni-config-center`的 `uni-id` 下配置固定凭据
如果你没有`appid``secret` ,需要先向微信申请
- 微信小程序或微信公众号,向微信的[公众平台](https://mp.weixin.qq.com/)申请 `appid``secret` 固定凭据。
- 微信App或PC网页,向微信的[开放平台](https://open.weixin.qq.com/)申请 `appid``secret` 固定凭据。
首先向微信的[公众平台](https://mp.weixin.qq.com/)申请 `appid``secret` 固定凭据
然后在项目的 uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 文件中配置
**示例代码**
如果不需要定时刷新 `access_token``ticket`、也不需要通过外部系统访问凭据时可单独引入 [uni-open-bridge-common](#uni-open-bridge-common),然后在云函数或云对象中直接调用相关方法
### uni-id-config
**uni-id-config中uni-id示例代码**
```json
// uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json
{
"dcloudAppid": "__UNI__xxxxxx", // 在项目的 manifest.json
"mp-weixin": {
"mp-weixin": { // 微信小程序
"tokenExpiresIn": 259200,
"oauth": {
"weixin": {
......@@ -71,7 +235,7 @@
},
"web": {
"oauth": {
"h5-weixin": {
"weixin-h5": { //微信公众号h5
"appid": "", // 微信公众平台申请的网页授权 appid
"appsecret": "" // 微信公众平台申请的网页授权 secret
}
......@@ -80,13 +244,17 @@
}
```
注意:拷贝此文件内容时需要移除 `注释`
-`weixin-mp``weixin-h5` 平台,通过调用 [uni-open-bridge-common](#uni-open-bridge-common) 的get相关方法可自动从微信服务器获取 [access_token](#access_token)[encrypt_key](#encrypt_key)[ticket](#ticket) 时需要用到配置文件中的 `appid``appsecret`
- 暂时不需要配置 `weixin-web``weixin-app``qq-mp``qq-app`,后续支持这些平台时需要再次补充配置,但仍然可通过调用 [uni-open-bridge-common](#uni-open-bridge-common) 的方法传入设置值
3.`uni-config-center`目录下新建子目录`uni-open-bridge`, 新增 `config.json`,配置 dcloudAppid ,详情见下面的示例代码
### uni-open-bridge-config@uniopenbridgeconfig
注意:拷贝此文件内容时需要移除 `注释`。标准json不支持注释。在HBuilderX中可用多选//来批量移除注释。
**示例代码**
### 3. `uni-config-center`下配置`uni-open-bridge`@uniopenbridgeconfig
`uni-config-center`目录下新建子目录`uni-open-bridge`, 新增 `config.json`,配置 dcloudAppid ,详情见下面的示例代码
**uni-id-config中uni-open-bridge示例代码**
```json
// uniCloud/cloudfunctions/common/uni-config-center/uni-open-bridge/config.json
......@@ -94,33 +262,39 @@
"schedule": {
"__UNI__xxxxxx": { // dcloudAppid, 需要和 `uni-config-center` uni-id中的配置一致
"enable": true, // 任务全局开关,优先级最高
"mp-weixin": { // 平台,目前仅支持 微信小程序、微信 H5,详情参见 https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#platform
"weixin-mp": { // 平台,目前仅支持 微信小程序、微信 H5,详情参见 https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#platform
"enable": true, // 当前平台任务开关
"tasks": ["accessToken"] // 要执行的任务,微信小程序支持 accessToken
},
"h5-weixin": {
"weixin-h5": {
"enable": false,
"tasks": ["ticket"] // 支持微信 H5 ticket,因 ticker 依赖微信 H5 accessToken,内部自动先获取 accessToken。此处的 accessToken 和微信小程序的 accessToken 不是一个值
}
}
},
"ipWhiteList": ["0.0.0.0"] // 用于 http 调用的服务器IP白名单
"ipWhiteList": ["0.0.0.0"] // 用于 URL化后 http 调用的服务器IP白名单,即指定ip的服务器才可以访问URL化后的`uni-open-bridge云对象
}
```
注意:拷贝此文件内容时需要移除 `注释`
注意:拷贝此文件内容时需要移除 `注释`。标准json不支持注释。在HBuilderX中可用多选//来批量移除注释。
4. 将插件上传到服务空间。最好开通redis,会有更好的性能
然后在数据库和redis的`uni-id`分组中会看到数据。
### 4. 将插件上传到服务空间
云对象`uni-open-bridge`上传到服务空间后,会每隔一个小时自动运行一次,从微信服务器获取相关凭据并保存到数据库。
在数据库`opendb-open-data`中会看到数据。如开通redis则在redis的`uni-id`分组中查看(推荐开通redis以获取更好的性能)。
如果异常,请在 [uniCloud Web控制台](https://unicloud.dcloud.net.cn/),找到云函数/云对象 `uni-open-bridge` 检查运行日志。很可能是第一步或第二步的配置出错了。
## 业务系统获取相关凭据的方法
当然如果不需要定时任务,可以修改云对象package.json里的定时任务配置并重新上传。或在uniCloud web控制台修改定时任务。一般不推荐修改定时任务设置。
当业务不在uniCloud上时,在`uni-open-bridge`云对象获取到相关凭据后,当业务系统需要使用这些凭据时,通过下面的云对象URL化方式获取。
**注意**
如需获取微信公众号H5平台的`access_token`,需要处理服务空间的固定出口IP问题。因为需将IP白名单填入到微信公众平台,然后才能在从微信服务器拿到该凭据。uniCloud中默认没有固定IP,获取固定IP需另见文档[固定IP](cf-functions.md#eip)
注意:为了安全鉴权需要在 `uni-open-bridge-config` 中的 ipWhiteList 节点下配置服务器IP
## 业务系统获取相关凭据的方法
`uni-open-bridge`云对象获取到相关凭据后,当业务系统(比如登录支付或其他业务)需要使用这些凭据时,通过以下方式获取。
### 云函数公共模块方式@uni-open-bridge-common
......@@ -128,23 +302,51 @@
> `云函数公共模块`是不同云函数共享代码的一种方式。如果你不了解什么是`云函数公共模块`,请另读文档[公共模块](https://uniapp.dcloud.io/uniCloud/cf-common)
`uni-open-bridge-common` 提供了 `access_token``session_key``encrypt_key``ticket` 的读取、写入、删除操作。
`uni-open-bridge-common` 公共模块,提供了 [access_token](#access_token)[user_access_token](#user_access_token)[session_key](#session_key)[encrypt_key](#encrypt_key)[ticket](#ticket) 的读取、写入、删除操作。
`uni-open-bridge-common` 支持多层 读取 / 写入 机制,`redis -> database -> fallback`,优先级如下:
如果用户没有开通 `redis` 或者操作失败,透传到 `database``database` 失败后,如果用户配置了 `fallback`,继续调用 `fallback` 方法,否则抛出 `Error``database` 对应的表为: `opendb-open-data`
在常见的情况下,在你的云函数/云对象中调用`uni-open-bridge-common`的几个get方法即可。
```js
let uobc = require('uni-open-bridge-common')
// 应用级凭据
const key = {
dcloudAppid: '__UNI__xxx', // DCloud Appid
platform: 'weixin-mp' // 指定凭据所属平台,解释见上
}
uobc.getAccessToken(key)
uobc.getTicket(key)
// 用户级凭据,需要同时传入 openid 才能获得
const userKey = {
dcloudAppid: '__UNI__xxx', // DCloud Appid
platform: 'weixin-mp', // 指定凭据所属平台,解释见上
openid: '' // 用户唯一标识,解释见上
}
uobc.getUserAccessToken(userKey)
uobc.getSessionKey(userKey)
uobc.getEncryptKey(userKey)
```
除了上述常见方法,下文列出了所有凭据的get、set、remove方法。
#### getAccessToken(key: Object, fallback: Function)
读取 access_token
#### setAccessToken(key: Object, value: Object, expiresIn: Number)
写入 access_token
写入 access_token。开发者一般只需使用get类方法,用不到set、remove类方法。下同
#### removeAccessToken(key: Object)
删除 access_token
删除 access_token。开发者一般只需使用get类方法,用不到set、remove类方法。下同
**key 属性**
......@@ -156,9 +358,9 @@
**value 属性**
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|access_token |String | |
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|access_token |String |[详情](#access_token)|
**expiresIn**
......@@ -179,7 +381,7 @@ const {
exports.main = async (event, context) => {
const key = {
dcloudAppid: '__UNI__xxx',
platform: 'mp-weixin'
platform: 'weixin-mp'
}
const value = {
access_token: ''
......@@ -205,15 +407,15 @@ exports.main = async (event, context) => {
#### getUserAccessToken(key: Object, fallback: Function)
读取 user_access_token
读取 `user_access_token`
#### setUserAccessToken(key: Object, value: Object, expiresIn: Number)
写入 user_access_token
写入 `user_access_token`
#### removeUserAccessToken(key: Object)
删除 user_access_token
删除 `user_access_token`
对应微信公众平台网页用户授权 `access_token`,详情见下文说明
......@@ -221,17 +423,17 @@ exports.main = async (event, context) => {
**key 属性**
|参数 |类型 |必填 |描述 |
|:-: |:-: |:-: |:-: |
|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) |
|platform |String |是 |[详情](#platform) |
|openid |String |是 | |
|参数 |类型 |必填 |描述 |
|:-: |:-: |:-: |:-: |
|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) |
|platform |String |是 |[详情](#platform) |
|openid |String |是 |[详情](#openid) |
**value 属性**
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|access_token |String |微信公众平台用户会话密钥 |
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|access_token |String |微信公众平台用户会话密钥[详情](#user_access_token) |
**expiresIn**
......@@ -251,7 +453,7 @@ const {
exports.main = async (event, context) => {
const key = {
dcloudAppid: '__UNI__xxx',
platform: 'h5-weixin',
platform: 'weixin-h5',
openid: ''
}
const value = {
......@@ -293,17 +495,17 @@ exports.main = async (event, context) => {
**key 属性**
|参数 |类型 |必填 |描述 |
|:-: |:-: |:-: |:-: |
|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) |
|platform |String |是 |[详情](#platform) |
|openid |String |是 | |
|参数 |类型 |必填 |描述 |
|:-: |:-: |:-: |:-: |
|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) |
|platform |String |是 |[详情](#platform) |
|openid |String |是 |[详情](#openid) |
**value 属性**
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|session_key|String |微信小程序会话密钥 |
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|session_key|String |微信小程序会话密钥[详情](#session_key) |
**expiresIn**
......@@ -324,7 +526,7 @@ const {
exports.main = async (event, context) => {
const key = {
dcloudAppid: '__UNI__xxx',
platform: 'mp-weixin',
platform: 'weixin-mp',
openid: ''
}
const value = {
......@@ -366,20 +568,20 @@ exports.main = async (event, context) => {
**key 属性**
|参数 |类型 |必填 |描述 |
|:-: |:-: |:-: |:-: |
|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) |
|platform |String |是 |[详情](#platform) |
|openid |String |是 | |
|version |Number |是 |版本 |
|参数 |类型 |必填 |描述 |
|:-: |:-: |:-: |:-: |
|dcloudAppid|String |是 |DCloud应用appid。[详情](https://ask.dcloud.net.cn/article/35907) |
|platform |String |是 |[详情](#platform) |
|openid |String |是 |[详情](#openid) |
|version |Number |是 |版本 |
**value 属性**
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|encrypt_key|String |加密 key |
|iv |String |加密 iv |
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|encrypt_key|String |加密 key[详情](#encrypt_key) |
|iv |String |加密 iv |
**expiresIn**
......@@ -400,7 +602,7 @@ const {
exports.main = async (event, context) => {
const key = {
dcloudAppid: '__UNI__xxx',
platform: 'mp-weixin',
platform: 'weixin-mp',
openid: '',
version: 1
}
......@@ -452,7 +654,7 @@ exports.main = async (event, context) => {
|参数 |类型 |描述 |
|:-: |:-: |:-: |
|ticket |String | |
|ticket |String |[详情](#ticket) |
**expiresIn**
......@@ -473,7 +675,7 @@ const {
exports.main = async (event, context) => {
const key = {
dcloudAppid: '__UNI__xxx',
platform: 'h5-weixin'
platform: 'weixin-h5'
}
const value = {
ticket: ''
......@@ -499,20 +701,6 @@ exports.main = async (event, context) => {
```
#### Platform@platform
平台对应的值
|值 |描述 |
|:-: |:-: |
|mp-weixin |微信小程序 |
|app-weixin |微信 App |
|h5-weixin |微信公众号 |
|web-weixin |微信pc网页 |
|mp-qq |QQ 小程序 |
|app-qq |QQ App |
提示:目前仅支持 `mp-weixin``h5-weixin` 后续补充其他平台
#### fallback
......@@ -525,7 +713,7 @@ exports.main = async (event, context) => {
}
```
为了简化调用 `getAccessToken()``getTicket()` 已内置 `fallback` 到微信的服务器,需要在 `config-center` 中配置 `appid` `appsecret`
为了简化调用 `getAccessToken()``getTicket()` 已内置 `fallback` 到微信的服务器,需要在 `config-center` 中配置 `appid` `appsecret`[详情](#uni-id-config)
#### 注意事项
......@@ -533,14 +721,15 @@ exports.main = async (event, context) => {
- 所有方法校验 `key` 属性是否有效,无效则 `throw new Error()`,对 `value` 仅校验是否为 `Object`
### 云对象URL化方式
### 云对象URL化方式@cloudurl
云对象 `uni-open-bridge` URL化后,非uniCloud系统可通过 http 方式访问凭据。
云对象 `uni-open-bridge` URL化后,非uniCloud系统可通过 http 方式访问凭据。
[URL化](http.md),是一种让云函数或云对象暴露为Http接口的方式,[详见](http.md)。可以在 [uniCloud Web控制台](https://unicloud.dcloud.net.cn/) 操作。
请求类型 `POST`, 可以配置IP白名单字段 `ipWhiteList`,参见 `config.json`
配置URL化后,其他系统可以通过下面的http接口,读写删各种开放平台凭据。
#### getAccessToken
......@@ -555,22 +744,30 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getAcces
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin"
"platform": "weixin-mp"
}
```
其中参数platform值域[详见](#platform)。下同,不再复述。
#### setAccessToken
如果各种开放平台凭据由`uni-open-bridge`托管,那么只需要调用各种get方法,是用不到set等方法的。但在某些情况下,相关凭据没有由`uni-open-bridge`从微信服务器获取,就需要这些set方法了。[详见](#nouseuniopenbridge)
Url
```
https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setAccessToken
```
参数
由外部系统从微信获取到相关凭据,然后写入。[详见](#nouseuniopenbridge)
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin",
"platform": "weixin-mp",
"value": {
"access_token": ""
},
......@@ -578,6 +775,7 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setAcces
}
```
#### removeAccessToken
Url
......@@ -591,11 +789,10 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeAc
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin"
"platform": "weixin-mp"
}
```
其中参数platform值域[详见](#platform)
#### getUserAccessToken
......@@ -610,11 +807,13 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getUserA
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "h5-weixin",
"platform": "weixin-h5",
"openid": ""
}
```
其中参数openid值域[详见](#openid)。下同,不再复述。
#### setUserAccessToken
Url
......@@ -625,10 +824,12 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setUserA
参数
由外部系统从微信获取到相关凭据,然后写入。[详见](#nouseuniopenbridge)
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "h5-weixin",
"platform": "weixin-h5",
"openid": "",
"value": {
"access_token": ""
......@@ -650,7 +851,7 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeUs
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "h5-weixin",
"platform": "weixin-h5",
"openid": ""
}
```
......@@ -668,7 +869,7 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getSessi
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin",
"platform": "weixin-mp",
"openid": ""
}
```
......@@ -683,10 +884,12 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setSessi
参数
由外部系统从微信获取到相关凭据,然后写入。[详见](#nouseuniopenbridge)
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin",
"platform": "weixin-mp",
"openid": "",
"value": {
"session_key": ""
......@@ -708,7 +911,7 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeSe
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin",
"platform": "weixin-mp",
"openid": ""
}
```
......@@ -726,7 +929,7 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getEncry
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin",
"platform": "weixin-mp",
"openid": "",
"version": 1 // 此版本号应根据客户端传递的版本号
}
......@@ -742,10 +945,12 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setEncry
参数
由外部系统从微信获取到相关凭据,然后写入。[详见](#nouseuniopenbridge)
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin",
"platform": "weixin-mp",
"openid": "",
"version": 1,
"value": {
......@@ -768,7 +973,7 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeEn
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "mp-weixin",
"platform": "weixin-mp",
"openid": "",
"version": 1
}
......@@ -788,7 +993,7 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/getTicke
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "h5-weixin"
"platform": "weixin-h5"
}
```
......@@ -802,10 +1007,12 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/setTicke
参数
由外部系统从微信获取到相关凭据,然后写入。[详见](#nouseuniopenbridge)
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "h5-weixin",
"platform": "weixin-h5",
"value": {
"ticket": ""
}
......@@ -825,80 +1032,33 @@ https://xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx.bspapp.com/uni-open-bridge/removeTi
```json
{
"dcloudAppid": "__UNI__xxx",
"platform": "h5-weixin"
"platform": "weixin-h5"
}
```
## 微信凭据介绍
### access_token(应用级)@access_token
- 微信小程序 `access_token` 是微信小程序全局唯一后台接口调用凭据,调用绝大多数后台接口时都需使用。[详情](https://developers.weixin.qq.com/miniprogram/dev/framework/server-ability/backend-api.html#access_token)
- 微信H5 `access_token` 是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用 `access_token`。开发者需要进行妥善保存。`access_token` 的存储至少要保留512个字符空间。`access_token` 的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的 `access_token` 失效。
公众平台的 API 调用所需的 `access_token` 的使用及生成方式说明:
1、建议公众号开发者使用中控服务器统一获取和刷新 `access_token`,其他业务逻辑服务器所使用的 `access_token` 均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致 `access_token` 覆盖而影响业务;
2、目前`access_token` 的有效期通过返回的expires_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新 `access_token`。在刷新过程中,中控服务器可对外继续输出的老 `access_token`,此时公众平台后台会保证在5分钟内,新老 `access_token` 都可用,这保证了第三方业务的平滑过渡;
3、`access_token` 的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新 `access_token` 的接口,这样便于业务服务器在 API 调用获知 `access_token` 已超时的情况下,可以触发 `access_token` 的刷新流程。
4、对于可能存在风险的调用,在开发者进行获取 `access_token` 调用时进入风险调用确认流程,需要用户管理员确认后才可以成功获取。具体流程为:
开发者通过某 IP 发起调用->平台返回错误码[89503]并同时下发模板消息给公众号管理员->公众号管理员确认该 IP 可以调用->开发者使用该 IP 再次发起调用->调用成功。
## 不使用 `uni-open-bridge` 托管的情况@nouseuniopenbridge
公众号管理员第一次拒绝该 IP 调用,用户在1个小时内将无法使用该 IP 再次发起调用,如公众号管理员多次拒绝该 IP 调用,该 IP 将可能长期无法发起调用。平台建议开发者在发起调用前主动与管理员沟通确认调用需求,或请求管理员开启 IP 白名单功能并将该 IP 加入 IP 白名单列表
开发者的老业务里已经获取了微信的access_token等凭据,难以迁移到由`uni-open-bridge`来托管微信相关凭据
### user_access_token(用户级)@user_access_token
那么`uni-open-bridge`也暴露了允许三方系统给`uni-open-bridge`写入微信相关凭据的接口。
平台对应的值
因为其他插件会依赖`uni-open-bridge`,比如:
1. `uni-ad`微信小程序激励视频广告服务器回调
2. uni云端一体安全网络
|平台 |值 |描述 |
|:-: |:-: |:-: |
|微信内置浏览器H5 |access_token |微信内置浏览器H5用户会话密钥。[详情](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html) |
如果`uni-open-bridge`里没有相关凭据,上述插件或功能就无法使用。
对应微信公众平台网页用户授权 `access_token`
因此,开发者即不想改成由`uni-open-bridge`托管微信凭据,又需要使用上述依赖`uni-open-bridge`的功能或插件,就只能将老系统获取到的相关凭据写入到`uni-open-bridge`中。
微信公众平台网页授权有两个相同名字 `access_token`,分别用于
此时,开发者需通过以下方式处理:
1、公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用 `access_token`
2、网页授权接口调用凭证,用户授权的作用域 `access_token`
1. 取消`uni-open-bridge`云对象的定时任务,不再定时向微信服务器请求凭据
在微信内置浏览器H5无法区分两个相同名称值不同的 `access_token`,所以以更直观的名称 `user_access_token` 对应用户授权 `access_token`
### session_key
平台对应的值
|平台 |值 |描述 |
|:-: |:-: |:-: |
|微信小程序 |session_key|微信小程序会话密钥。[详情](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html) |
会话密钥 `session_key` 有效性
开发者如果遇到因为 `session_key` 不正确而校验签名失败或解密失败,请关注下面几个与 `session_key` 有关的注意事项。
`uni.login` 调用时,用户的 `session_key` 可能会被更新而致使旧 `session_key` 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 `uni.login`,并非每次调用都导致 `session_key` 刷新)。
开发者应该在明确需要重新登录时才调用 `uni.login`,及时通过 `code2Session` 接口更新服务器存储的 `session_key`
微信不会把 `session_key` 的有效期告知开发者。我们会根据用户使用小程序的行为对 `session_key` 进行续期。用户越频繁使用小程序,`session_key` 有效期越长。
开发者在 `session_key` 失效时,可以通过重新执行登录流程获取有效的 `session_key`。使用接口 `uni.checkSession` 可以校验 `session_key` 是否有效,从而避免小程序反复执行登录流程。
当开发者在实现自定义登录态时,可以考虑以 `session_key` 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。
### encrypt_key
为了避免小程序与开发者后台通信时数据被截取和篡改,微信侧维护了一个用户维度的可靠key,用于小程序和后台通信时进行加密和签名。[详情](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/user-encryptkey.html)
开发者可以分别通过小程序前端和微信后台提供的接口,获取用户的加密 key。
`uni-open-bridge`云对象的package.json中找到定时器节点`triggers`,删除该节点。本地修改package.json后需重新上传到服务空间方生效。
### ticket
参考[定时任务配置](cf-functions.md#packagejson))。
`ticket` 是公众号用于调用微信 JS 接口的临时票据。正常情况下,`ticket` 的有效期为7200秒,通过 `access_token` 来获取。
2. 老系统从微信服务器获取到相关凭据后调用`uni-open-bridge`的set方法写入凭据
由于获取 `ticket` 的 api 调用次数非常有限,频繁刷新 `ticket` 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存 `ticket `[详情](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62)
\ No newline at end of file
先将云对象`uni-open-bridge`进行URL化,暴露出http接口。然后老系统调用setAccessToken、setUserAccessToken、setSessionKey、setEncryptKey、setTicket等接口。[参考](#cloudurl)
## 视频介绍
<a target="_blank" href="https://www.bilibili.com/video/BV17p4y1a71x?p=11">
<a target="_blank" href="https://www.bilibili.com/video/BV17p4y1a71x?p=12">
<img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/71d310a5-ef69-4ca5-88c8-9a3abf8fb8e3.png" alt="腾讯课堂uniCloud视频教程" style="width: 70%;margin-bottom:26px;">
</a>
......@@ -51,7 +51,7 @@ GitCode 仓库:[https://gitcode.net/dcloud/uni-starter](https://gitcode.net/dc
6. 更好的性能:首页采用nvue,fast编译模式,加快App端启动速度
7. 内置拦截器:
- 页面路由拦截,配置需强制登录的页面;打开时自动检测`token`若无效就自动跳转到登录页
- 调用云函数(callFunction)拦截器,自动携带必要参数、自动处理响应体。详见9.自动完成1-2
- 调用云函数(callFunction)拦截器,自动携带必要参数、自动处理响应体。详见8.自动完成1-2
8. 自动完成:
- 分析uniCloud.callfunction和clientDB操作的响应体,判断code执行对应的操作如跳转到登录页,自动续期token
- 操作注册/登录操作自动获取客户端设备:push_clientid、imei、oaid、idfa新增/更新到数据表uni-id-device
......
......@@ -12,7 +12,7 @@
### 5+应用:
+ plus节点 --> distribute节点 --> plugins节点 --> push节点 --> igexin节点(或者unipush节点) --> icons节点 --> small节点下配置
```
```json
"plugins": { // 第三方sdk配置
"push": { // 模块名称
"igexin": { // 个推SDK参数配置
......@@ -45,7 +45,7 @@
### uni应用:
+ app-plus节点 --> distribute节点 --> sdkConfigs节点 --> push节点 --> igexin节点(或者unipush节点) --> icons节点 --> small节点下配置
~~~
```json
"sdkConfigs": {
"push": {
"unipush": {
......@@ -71,7 +71,7 @@
}
}
~~~
```
......
......@@ -31,6 +31,6 @@
},
"dependencies": {
"@docsearch/js": "^3.1.0",
"vuepress-theme-uni-app-test": "^1.2.2"
"vuepress-theme-uni-app-test": "^1.2.3"
}
}
\ No newline at end of file
......@@ -8503,10 +8503,10 @@ vuepress-theme-uni-app-test@^1.2.0:
vuepress-plugin-juejin-style-copy "^1.0.4"
vuepress-theme-uni-app-test "^1.1.9"
vuepress-theme-uni-app-test@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/vuepress-theme-uni-app-test/-/vuepress-theme-uni-app-test-1.2.2.tgz#a570cda549d6082d300a8ec53eb65cbaafb96e9b"
integrity sha512-ciw6DyfTc8czeq0KzGtx9SLUzuxGv6ZD60spb/ODoa6LYxXqXlYpnDtilPmxcQDKAISRv246w3MWFt74rxayaA==
vuepress-theme-uni-app-test@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/vuepress-theme-uni-app-test/-/vuepress-theme-uni-app-test-1.2.3.tgz#0b20868f7224d9268563f43f4c35ea2d74d622d8"
integrity sha512-Sub44LWuD1H+ce3yNcdx61sQfRtmtEPwP09CGhzY9yiFGiqTUt8NI+dztHLgEqxVBnLr/AGNRCT9H8z1MlJqvg==
dependencies:
"@vuepress/plugin-back-to-top" "^1.9.5"
"@vuepress/theme-default" "^1.8.2"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册