diff --git a/docs/uniCloud/send-sms.md b/docs/uniCloud/send-sms.md
index 4b26bbaee8d9f0a74b6c6455a0b576dc1f72b9df..3141f5cedd0702fe3f8df83f12c52b7797ab208d 100644
--- a/docs/uniCloud/send-sms.md
+++ b/docs/uniCloud/send-sms.md
@@ -1,231 +1,242 @@
-## 发送短信
-
-
-
-> 自`HBuilderX 3.3.0`起,本接口支持传入phoneList参数批量发送短信,其他参数均于发送单条短信相同
-
-> 自`HBuilderX 3.4.0`起云函数需启用uni-cloud-sms之后才可以调用sendSms接口,详细说明见:[云函数使用短信扩展库](#extension)
-
-自HBuilderX 2.8.1起,uniCloud内置了短信发送API。给开发者提供更方便、更便宜的短信发送能力。
-
-该服务类似小程序的模板消息,在一个固定模板格式的文字里自定义某些字段,而不是所有文字都可以随便写。
-
-使用本功能需要在[DCloud开发者中心](https://dev.dcloud.net.cn/pages/sms/base)开通并充值,教程参考[短信服务开通指南](https://ask.dcloud.net.cn/article/37534)
-
-因涉及费用,为保障安全,本能力应该在云函数中调用,而不是在前端调用。
-
-云函数API名称:`uniCloud.sendSms`
-
-**参数说明**
-
-参数结构体为json格式。
-
-|参数名 |类型 |必填 |说明 |
-|:-: |:-: |:-: |:-: |
-|appid |String |是 |DCloud appid,可以在项目manifest.json内看到 |
-|smsKey |String |是 |调用短信接口的密钥key,从 dev.dcloud.net.cn/uniSms 后台获取 |
-|smsSecret |String |是 |调用短信接口的密钥secret,从 dev.dcloud.net.cn/uniSms 后台获取 |
-|phone |String |和phoneList二选一|发送目标手机号,暂仅支持中国大陆手机号 |
-|phoneList |Array |和phone二选一 |发送目标手机号,暂仅支持中国大陆手机号,最多50个手机号码,`HBuilderX 3.3.0`起支持 |
-|templateId |String |是 |模版Id,短信内容为固定模板,详见下方说明(应用开发阶段,可以使用 DCloud 提供的测试模板) |
-|data |Object |是 |模版里的各个变量字段,json格式 |
-
-
-**注意**
-
-- 如果使用uni-id发送短信,无需自行开发,请参考[uni-id-pages](uni-id-pages.md)
-
-#### 云函数使用短信扩展库@extension
-
-自HBuilderX 3.4.0起,短信相关功能移至扩展库`uni-cloud-sms`内。在一段时间内无论开发者是否使用扩展库云函数都可以正常使用`uniCloud.sendSms`。HBuilderX 3.4.0及之后的版本上传云函数时如果没有指定使用`uni-cloud-sms`扩展库的云函数将无法调用uniCloud.sendSms接口。
-
-关于扩展库的说明见:[云函数扩展库](cf-functions.md#extension)
-
-在云函数的package.json内添加`uni-cloud-sms`的引用即可为云函数启用此扩展,无需做其他调整,完整的package.json示例如下:
-
-```js
-{
- "name": "uni-sms",
- "extensions": {
- "uni-cloud-sms": {} // 启用短信扩展,值为空对象即可
- }
-}
-```
-
-#### 参数templateId说明@smstemplate
-
-按照国家法律和运营商要求,每个要发送短信的应用,需要备案其短信模板,并且经过运营商的审核。通过审核的模板,会得到一个templateId。
-
-短信内容规范:
-1. 不能包含涉政、黄赌毒、暴力、房产、移民、贷款、代开发票等违法内容
-2. 不能包含运营商禁止发送的内容
-3. 不能包含侵犯第三方权益的内容(如侵犯他人商标或冒名行为)
-4. 营销类短信不能违反广告法
-5. 不能利用短信骚扰或诈骗用户
-
-报备模板的方式:
-
-1. 如果尚未添加签名,请在在开发者中心-[签名配置](https://dev.dcloud.net.cn/pages/sms/sign)内添加签名
-2. 在开发者中心-[模板配置](https://dev.dcloud.net.cn/pages/sms/template)内申请自定义模板
-
-- 短信签名:
-即短信内容开头的【xxx】,可选内容为App或小程序名称、网站名称、企业名称(可使用简称,但需具备辨识度)、商标名称。如`【DCloud】`,即是DCloud官方发送短信的签名。签名的作用是明确告知用户该短信由什么样的主体发送。签名内容只允许包含中文、英文、数字,签名的长度限制为2-8位。
-
-- 模板内容:
-短信模板必然以短信签名作为开头,其内容中允许有一定的变量,以满足灵活性需求。变量用${}包裹。
-
-例如:【hello uni-app】验证码:${code},${expMinute}分钟内有效,请勿泄露并尽快验证。
-
-在实际发送短信时,在短信API中传入该模板ID,然后传入合适的变量,最终发送的短信将变为:
-`【hello uni-app】验证码:123465,用于注册,15分钟内有效,请勿泄露并尽快验证。`
-
-- 短信类别:
-分为3类,即验证码类短信、通知类短信、营销类短信。验证码类短信,其模板审核简单快速,只能单次发送。
-
-**短信测试模板说明**
-
-运营商目前审核比较严格,处于开发阶段的应用可能无法通过运营商的审核。为方便开发者测试短信功能,DCloud 提供了一个测试模板,该模板的templateId为:uni_sms_test,内容为:`【统一应用软件】尊敬的用户,您的验证码是:${code}。5分钟内有效,请尽快验证。请勿泄漏您的验证码。`
-
-使用该模板的限制:
-
-1. 每日最多给10个手机号发送不超过100条短信;
-2. 使用该模板也会正常收取费用,请保证账户有充足余额。
-
-
-**返回值**
-
-接口调用失败时会直接抛出错误,调用成功时才会有返回值。
-
-注意接口调用成功不代表短信发送成功,比如目标手机关机会导致短信发送失败。真实的短信发送成功与否请在[https://dev.dcloud.net.cn/pages/sms/base](https://dev.dcloud.net.cn/pages/sms/base)后台查看报表。
-
-|参数名 |类型 |说明 |
-|:-: |:-: |:-: |
-|errCode|Number|成功返回0,调用失败错误码见下表 |
-|errMsg|String|错误描述,调用失败时返回 |
-
-**错误码说明**
-
-|错误码 |错误 |
-|:-: |:-: |
-|1001 |参数校验未通过,errMsg内会给出详细信息|
-|4000 |参数错误 |
-|4001 |apiKey 不存在 或 templateId 不正确 |
-|4002 |请检查smsKey、smsSecret是否有误 |
-|4003 |服务空间或IP地址不在白名单中 |
-|5000 |服务错误,请联系DCloud进行排查 |
-|5001 |服务器异常,请重试! |
-
-**调用示例**
-
-```js
-// 发送单条短信示例
-'use strict';
-exports.main = async (event, context) => {
- try {
- const res = await uniCloud.sendSms({
- appid: '__UNI__xxxxxxx',
- smsKey: '****************',
- smsSecret: '****************',
- phone: '188********',
- templateId: '100**', // 请替换为自己申请的模板id
- data: {
- name: 'DCloud',
- code: '123456',
- expMinute: '3',
- }
- })
- // 调用成功,请注意这时不代表发送成功
- return res
- } catch(err) {
- // 调用失败
- console.log(err.errCode)
- console.log(err.errMsg)
- return {
- code: err.errCode,
- msg: err.errMsg
- }
- }
-};
-
-// 批量发送短信示例
-'use strict';
-exports.main = async (event, context) => {
- try {
- const res = await uniCloud.sendSms({
- appid: '__UNI__xxxxxxx',
- smsKey: '****************',
- smsSecret: '****************',
- phoneList: ['188********', '138********'],
- templateId: '100**', // 请替换为自己申请的模板id
- data: {
- name: 'DCloud',
- code: '123456',
- expMinute: '3',
- }
- })
- // 调用成功,请注意这时不代表发送成功
- return res
- } catch(err) {
- // 调用失败
- console.log(err.errCode)
- console.log(err.errMsg)
- return {
- code: err.errCode,
- msg: err.errMsg
- }
- }
-};
-```
-
-本示例使用的模板为:
-```
-【uniID】“${name}”验证码:${code},${expMinute}分钟内有效,请勿泄露并尽快验证。
-```
-
-本示例发送的短信,在手机上将显示为:
-```
-【uniID】“DCloud”验证码:123456,3分钟内有效,请勿泄露并尽快验证。
-```
-
-### 发送失败注意@fail
-
-- data内如果有`测试`、`test`等字样,系统可能会被判定为测试用途,不会真正把短信下发到对应手机(此行为由运营商控制,可能真实发送,也可能不发送)
-- 短信内容不可包含★、 ※、 →、 ●等特殊符号,可能会导致短信乱码
-- 如果本地运行提示`不支持的模板ID`,请更新到`2.9.9+`版本的HBuilderX
-- 使用同一短信模板给同一个手机号发送短信时,频率不能太高。如果1分钟内超过1次,会被运营商判定为骚扰或短信重发而被拦截,导致短信发送失败
-- 尽量使用企业实名认证,个人实名认证的审核更严格,更容易发送失败
-
-
-**其他注意事项**
-
-- 在[DCloud开发者中心](https://dev.dcloud.net.cn/pages/sms/base)绑定`uniCloud`服务空间后,将会只允许绑定的服务空间调用此接口,绑定列表为空时表示不限制服务空间
-- 如果是用于用户注册的短信验证码,那么强烈推荐使用uni-id,这是一套云端一体的、完善的用户管理方案,已经内置封装好的短信验证码功能,详见:[uni-id-pages](uni-id-pages.md)。
-- 发送短信前,如果需要图形验证码来防止机刷,可以使用[uni-captcha图形验证码](https://ext.dcloud.net.cn/plugin?id=4048)。在[uni-id-pages](uni-id-pages.md)模板中已经集成了uni-id、uni-captcha
-- Android手机在App端获取短信验证码,参考:[https://ask.dcloud.net.cn/article/676](https://ask.dcloud.net.cn/article/676)
-- 短信内容超过70个字符时为长短信,需分条发送,每67个字按一条短信计算
-
-更多问题:欢迎加入DCloud短信技术交流群
-咨询
-
-
+## 发送短信
+
+
+
+> 自`HBuilderX 3.3.0`起,本接口支持传入phoneList参数批量发送短信,其他参数均于发送单条短信相同
+
+> 自`HBuilderX 3.4.0`起云函数需启用uni-cloud-sms之后才可以调用sendSms接口,详细说明见:[云函数使用短信扩展库](#extension)
+
+自HBuilderX 2.8.1起,uniCloud内置了短信发送API。给开发者提供更方便、更便宜的短信发送能力。
+
+该服务类似小程序的模板消息,在一个固定模板格式的文字里自定义某些字段,而不是所有文字都可以随便写。
+
+使用本功能需要在[DCloud开发者中心](https://dev.dcloud.net.cn/pages/sms/base)开通并充值,教程参考[短信服务开通指南](https://ask.dcloud.net.cn/article/37534)
+
+因涉及费用,为保障安全,本能力应该在云函数中调用,而不是在前端调用。
+
+云函数API名称:`uniCloud.sendSms`
+
+**参数说明**
+
+参数结构体为json格式。
+
+|参数名 |类型 |必填 |说明 |
+|:-: |:-: |:-: |:-: |
+|appid |String |是 |DCloud appid,可以在项目manifest.json内看到 |
+|smsKey |String |是 |调用短信接口的密钥key,从 dev.dcloud.net.cn/uniSms 后台获取 |
+|smsSecret |String |是 |调用短信接口的密钥secret,从 dev.dcloud.net.cn/uniSms 后台获取 |
+|phone |String |和phoneList二选一|发送目标手机号,暂仅支持中国大陆手机号 |
+|phoneList |Array |和phone二选一 |发送目标手机号,暂仅支持中国大陆手机号,最多50个手机号码,`HBuilderX 3.3.0`起支持 |
+|templateId |String |是 |模版Id,短信内容为固定模板,详见下方说明(应用开发阶段,可以使用 DCloud 提供的测试模板) |
+|data |Object |是 |模版里的各个变量字段,json格式 |
+
+
+**注意**
+
+- 如果使用uni-id发送短信,无需自行开发,请参考[uni-id-pages](uni-id-pages.md)
+
+#### 云函数使用短信扩展库@extension
+
+自HBuilderX 3.4.0起,短信相关功能移至扩展库`uni-cloud-sms`内。在一段时间内无论开发者是否使用扩展库云函数都可以正常使用`uniCloud.sendSms`。HBuilderX 3.4.0及之后的版本上传云函数时如果没有指定使用`uni-cloud-sms`扩展库的云函数将无法调用uniCloud.sendSms接口。
+
+关于扩展库的说明见:[云函数扩展库](cf-functions.md#extension)
+
+在云函数的package.json内添加`uni-cloud-sms`的引用即可为云函数启用此扩展,无需做其他调整,完整的package.json示例如下:
+
+```js
+{
+ "name": "uni-sms",
+ "extensions": {
+ "uni-cloud-sms": {} // 启用短信扩展,值为空对象即可
+ }
+}
+```
+
+#### 参数templateId说明@smstemplate
+
+按照国家法律和运营商要求,每个要发送短信的应用,需要备案其短信模板,并且经过运营商的审核。通过审核的模板,会得到一个templateId。
+
+短信内容规范:
+1. 不能包含涉政、黄赌毒、暴力、房产、移民、贷款、代开发票等违法内容
+2. 不能包含运营商禁止发送的内容
+3. 不能包含侵犯第三方权益的内容(如侵犯他人商标或冒名行为)
+4. 营销类短信不能违反广告法
+5. 不能利用短信骚扰或诈骗用户
+
+报备模板的方式:
+
+1. 如果尚未添加签名,请在在开发者中心-[签名配置](https://dev.dcloud.net.cn/pages/sms/sign)内添加签名
+2. 在开发者中心-[模板配置](https://dev.dcloud.net.cn/pages/sms/template)内申请自定义模板
+
+- 短信签名:
+即短信内容开头的【xxx】,可选内容为App或小程序名称、网站名称、企业名称(可使用简称,但需具备辨识度)、商标名称。如`【DCloud】`,即是DCloud官方发送短信的签名。签名的作用是明确告知用户该短信由什么样的主体发送。签名内容只允许包含中文、英文、数字,签名的长度限制为2-8位。
+
+- 模板内容:
+短信模板必然以短信签名作为开头,其内容中允许有一定的变量,以满足灵活性需求。变量用${}包裹。
+
+例如:【hello uni-app】验证码:${code},${expMinute}分钟内有效,请勿泄露并尽快验证。
+
+在实际发送短信时,在短信API中传入该模板ID,然后传入合适的变量,最终发送的短信将变为:
+`【hello uni-app】验证码:123465,用于注册,15分钟内有效,请勿泄露并尽快验证。`
+
+- 短信类别:
+分为3类,即验证码类短信、通知类短信、营销类短信。验证码类短信,其模板审核简单快速,只能单次发送。
+
+**短信测试模板说明**
+
+运营商目前审核比较严格,处于开发阶段的应用可能无法通过运营商的审核。为方便开发者测试短信功能,DCloud 提供了一个测试模板,该模板的templateId为:uni_sms_test,内容为:`【统一应用软件】尊敬的用户,您的验证码是:${code}。5分钟内有效,请尽快验证。请勿泄漏您的验证码。`
+
+使用该模板的限制:
+
+1. 每日最多给10个手机号发送不超过100条短信;
+2. 使用该模板也会正常收取费用,请保证账户有充足余额。
+
+
+**返回值**
+
+接口调用失败时会直接抛出错误,调用成功时才会有返回值。
+
+注意接口调用成功不代表短信发送成功,比如目标手机关机会导致短信发送失败。真实的短信发送成功与否请在[https://dev.dcloud.net.cn/pages/sms/base](https://dev.dcloud.net.cn/pages/sms/base)后台查看报表。
+
+|参数名 |类型 |说明 |
+|:-: |:-: |:-: |
+|errCode|Number|成功返回0,调用失败错误码见下表 |
+|errMsg|String|错误描述,调用失败时返回 |
+
+**错误码说明**
+
+|错误码 |错误 |
+|:-: |:-: |
+|1001 |参数校验未通过,errMsg内会给出详细信息|
+|4000 |参数错误 |
+|4001 |apiKey 不存在 或 templateId 不正确 |
+|4002 |请检查smsKey、smsSecret是否有误 |
+|4003 |服务空间或IP地址不在白名单中 |
+|5000 |服务错误,请联系DCloud进行排查 |
+|5001 |服务器异常,请重试! |
+
+**调用示例**
+
+```js
+// 发送单条短信示例
+'use strict';
+exports.main = async (event, context) => {
+ try {
+ const res = await uniCloud.sendSms({
+ appid: '__UNI__xxxxxxx',
+ smsKey: '****************',
+ smsSecret: '****************',
+ phone: '188********',
+ templateId: '100**', // 请替换为自己申请的模板id
+ data: {
+ name: 'DCloud',
+ code: '123456',
+ expMinute: '3',
+ }
+ })
+ // 调用成功,请注意这时不代表发送成功
+ return res
+ } catch(err) {
+ // 调用失败
+ console.log(err.errCode)
+ console.log(err.errMsg)
+ return {
+ code: err.errCode,
+ msg: err.errMsg
+ }
+ }
+};
+
+// 批量发送短信示例
+'use strict';
+exports.main = async (event, context) => {
+ try {
+ const res = await uniCloud.sendSms({
+ appid: '__UNI__xxxxxxx',
+ smsKey: '****************',
+ smsSecret: '****************',
+ phoneList: ['188********', '138********'],
+ templateId: '100**', // 请替换为自己申请的模板id
+ data: {
+ name: 'DCloud',
+ code: '123456',
+ expMinute: '3',
+ }
+ })
+ // 调用成功,请注意这时不代表发送成功
+ return res
+ } catch(err) {
+ // 调用失败
+ console.log(err.errCode)
+ console.log(err.errMsg)
+ return {
+ code: err.errCode,
+ msg: err.errMsg
+ }
+ }
+};
+```
+
+本示例使用的模板为:
+```
+【uniID】“${name}”验证码:${code},${expMinute}分钟内有效,请勿泄露并尽快验证。
+```
+
+本示例发送的短信,在手机上将显示为:
+```
+【uniID】“DCloud”验证码:123456,3分钟内有效,请勿泄露并尽快验证。
+```
+
+
+### 发送失败注意@fail
+
+- data内如果有`测试`、`test`等字样,系统可能会被判定为测试用途,不会真正把短信下发到对应手机(此行为由运营商控制,可能真实发送,也可能不发送)
+- 短信内容不可包含★、 ※、 →、 ●等特殊符号,可能会导致短信乱码
+- 如果本地运行提示`不支持的模板ID`,请更新到`2.9.9+`版本的HBuilderX
+- 使用同一短信模板给同一个手机号发送短信时,频率不能太高。如果1分钟内超过1次,会被运营商判定为骚扰或短信重发而被拦截,导致短信发送失败
+- 尽量使用企业实名认证,个人实名认证的审核更严格,更容易发送失败
+
+
+**其他注意事项**
+
+- 在[DCloud开发者中心](https://dev.dcloud.net.cn/pages/sms/base)绑定`uniCloud`服务空间后,将会只允许绑定的服务空间调用此接口,绑定列表为空时表示不限制服务空间
+- 如果是用于用户注册的短信验证码,那么强烈推荐使用uni-id,这是一套云端一体的、完善的用户管理方案,已经内置封装好的短信验证码功能,详见:[uni-id-pages](uni-id-pages.md)。
+- 发送短信前,如果需要图形验证码来防止机刷,可以使用[uni-captcha图形验证码](https://ext.dcloud.net.cn/plugin?id=4048)。在[uni-id-pages](uni-id-pages.md)模板中已经集成了uni-id、uni-captcha
+- Android手机在App端获取短信验证码,参考:[https://ask.dcloud.net.cn/article/676](https://ask.dcloud.net.cn/article/676)
+- 短信内容超过70个字符时为长短信,需分条发送,每67个字按一条短信计算
+
+更多问题:欢迎加入DCloud短信技术交流群
+咨询
+
+
+### 短信费用说明@sms-fee
+
+- 短信费用为:0.036元/条,但在实际使用中需要依赖`uniCloud`云服务,在阿里云商业化后,每条大约需要多花0.0000139元,几乎可以忽略不计,详情查看[短信及一键登录性价比测评](uniCloud/sms-and-unilogin-evaluation.md)。
+- 计费条数计算方法:短信内容少于70个字符(每个汉字、标点、空格、字母均算一个字符)算作1条短信,短信内容多于70个字符时,每67个字符算作一条短信,并向上取整(不足67个字符的部分也算做1条)。 例: 短信内容有 100个字符时计费短信条数应为 100 / 67 ≈ 1.49 向上取整后算作2条。
+- 最终按照成功回执状态为"成功"的短信条数计费,成功回执状态可在"发送记录"页面查看。
+
+特别注意:短信成功回执最长延迟为72小时。
+
+
+
diff --git a/docs/uniCloud/sms-and-unilogin-evaluation.md b/docs/uniCloud/sms-and-unilogin-evaluation.md
new file mode 100644
index 0000000000000000000000000000000000000000..4b045204a7e6b9aa279e57526edbf607557f78a6
--- /dev/null
+++ b/docs/uniCloud/sms-and-unilogin-evaluation.md
@@ -0,0 +1,58 @@
+近期,uniCloud阿里云版开始正式商用,部分开发者对基于uniCloud的`短信`和`一键登录`业务开始纠结,不清楚`短信`和`一键登录`业务比之前会多花费多少钱,对比其它厂家是否还具有价格优势。
+
+本文尝试算细账、算总账,以阿里云[按量计费](https://uniapp.dcloud.net.cn/uniCloud/price.html#aliyun-postpay)为例,详细预测`短信`和`一键登录`业务在不同用户规模下的资源消耗及对应费用,帮助大家明智选择,无忧开发。
+
+本文主要分为两个部分:
+- 短信和一键登录业务的消耗资源费用测算
+- 综合考虑,你该如何选择
+
+## 短信和一键登录业务的消耗资源费用测算
+
+`短信`和`一键登录`业务涉及费用的部分主要是云函数/云对象的使用量、调用次数、和出网流量(如:使用`uni-id-co`或自定义的云函数/云对象来发送短信)。
+接下来,我们对不同资源,分别进行费用评估。
+
+我们按照[uniCloud官网](https://uniapp.dcloud.net.cn/uniCloud/price.html#aliyun-postpay)列出的按量计费规则,计算一下云函数的资源消耗。
+
+![](https://mp-8ca8132b-2139-4831-aff2-582d4c8385da.cdn.bspapp.com/cloudstorage/8492ba8e-f4c6-45de-abf2-f9d6825ceefb.png)
+
+我们可以简单得出如下公式:
+
+`云函数/云对象费用 = 资源使用量 * 0.000110592 + 调用次数 * 0.0133 / 10000 + 出网流量 * 0.8`
+
+其中:
+- 资源使用量 = 云函数内存(单位为G) * 云函数平均单次执行时长(单位为秒) * 调用次数
+- 调用次数 = 发送短信条数(一般情况下发送条数 = 调用次数,特殊情况除外)+ 一键登录调用次数(如果只使用其中某一项业务,则可设另一项业务调用次数为0)
+
+
+我们假设如下数据模型:
+
+- 云函数内存:512M,即0.5G (云函数内存默认为512M,用户可以自定义设置,最低可设置为128M)
+- 云函数平均单次执行时长:200毫秒,即0.2秒
+- 短信和一键登录业务平均每日调用次数:10000次
+- 出网流量:单次请求 2 KB
+
+按照如上公式,其`短信`业务云函数每天的费用为:
+
+```
+云函数费用(天) = 资源使用量 * 0.000110592 + 调用次数 * 0.0133 / 10000 + 出网流量 * 0.8
+ = 云函数内存(单位为G) * 云函数平均单次执行时长(单位为秒) * 调用次数 + 调用次数 * 0.0133 / 10000 + 出网流量 * 0.8
+ = 0.5G * 0.2S * 10000 * 0.000110592 + 10000 * 0.0133/10000 + 10000 * 2 * 0.8 / 1024 * 1024
+ = 0.110592 + 0.0133 + 0.0152587890625
+ = 0.1391507890625(元)
+ ≈ 0.139(元)
+```
+
+即:如果你的`短信`和`一键登录`业务平均每天发送条数为10000条,使用阿里云商业版云服务空间后,对应云函数每天大概消耗0.139元,对比之前的短信和一键登录费用,平均每次调用多花0.0000139元。
+
+
+## 综合考虑,你该如何选择
+
+再次说回`短信`和`一键登录`业务,通过上面的费用测算可得知,`短信`和`一键登录`业务单次调用费用只增加了0.0000139元,几乎可以忽略不计,相比其它厂商仍然保持着价格优势。
+
+以日均调用1000次来说,每月才多了0.417元,每年才多了5块钱,一年多花5块钱,可以省掉工程师重新选择厂商对接的成本,让工程师将更多精力投入核心业务中。这5块钱的买卖,不划算吗?它不香吗?
+
+不重复制造轮子,聚焦业务,快速验证模式,实现商业增长,才应该是聪明工程师的追求。
+
+本篇评测仅供大家参考。
+
+
diff --git a/docs/uniCloud/univerify.md b/docs/uniCloud/univerify.md
index 1aae8869a6e7766c68f79f26ad1ee124e1ee7559..aaa179107cfb7d809beadb0da6bc92b9df0d9ae0 100644
--- a/docs/uniCloud/univerify.md
+++ b/docs/uniCloud/univerify.md
@@ -1,237 +1,242 @@
-## 一键登录@univerify
-
-
-
-`univerify` 是DCloud 推出的一键登录产品,通过与运营商深度合作,实现APP用户无需输入帐号密码,即可使用本机手机号码自动登录的能力。
-
-`univerify`是替代短信验证登录的下一代登录验证方式,能消除现有短信验证模式等待时间长、操作繁琐和容易泄露的痛点。
-
-> 注意:一键登录必须是手机使用流量的前提下才能获取到手机号码,用Wi-Fi联网时无法获取到手机号码,同时如果是双卡手机,获取到的手机号码是默认移动数据的那个手机卡的号码。
-
-## 重要调整
-
-### 云函数使用一键登录扩展库@extension
-
-自`HBuilderX 3.4.0`起,一键登录相关功能移至扩展库`uni-cloud-verify`内。在一段时间内无论开发者是否使用扩展库云函数都可以正常使用`uniCloud.getPhoneNumber`。HBuilderX 3.4.0及之后的版本上传云函数时如果没有指定使用`uni-cloud-verify`扩展库的云函数将无法调用uniCloud.getPhoneNumber接口。
-
-关于扩展库的说明见:[云函数扩展库](uniCloud/cf-functions.md?id=extension)
-
-在云函数的package.json内添加`uni-cloud-verify`的引用即可为云函数启用此扩展,无需做其他调整,完整的package.json示例如下:
-
-```js
-{
- "name": "univerify",
- "extensions": {
- "uni-cloud-verify": {} // 启用一键登录扩展,值为空对象即可
- }
-}
-```
-
-## 客户端@client
-
-客户端如何使用一键登录请参考此文档:[univerify 使用指南](/univerify)
-
-## 云函数@cloud
-
-> 自`HBuilderX 3.4.0`起云函数需启用uni-cloud-verify之后才可以调用getPhoneNumber接口,详细说明见:[云函数使用一键登录扩展库](#extension)
-
-客户端调用一键登录接口会获取如下结果
-
-```js
-{
- "target": {
- "id": "univerify",
- "description": "一键登录",
- "authResult": {
- "openid": "xxx",
- "access_token": "xxx"
- }
- }
-}
-```
-
-使用上面结果中的`openid`和`access_token`即可在`云函数`内调用接口获取手机号
-
-云函数内接口调用形式如下
-
-```js
-exports.main = async function(event, context){
- const res = await uniCloud.getPhoneNumber({
- provider: 'univerify',
- appid: context.APPID, // 客户端callFunction时携带的AppId信息
- apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
- apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
- access_token: event.access_token,
- openid: event.openid
- })
- // res形式如下
- // {
- // code: 0,
- // message: '',
- // phoneNumber: '138xxxxxxxx'
- // }
-}
-```
-
-**相关文档**
-- [uniCloud快速上手](https://uniapp.dcloud.net.cn/uniCloud/quickstart)
-- [云函数URL化](https://uniapp.dcloud.net.cn/uniCloud/http)
-
-### uni-app项目
-
-如果开发uni-app项目可以使用callFunction的方式调用云函数
-
-```js
-// 客户端
-uniCloud.callFunction({
- name: 'xxx', // 你的云函数名称
- data: {
- access_token: 'xxx', // 客户端一键登录接口返回的access_token
- openid: 'xxx' // 客户端一键登录接口返回的openid
- }
-}).then(res => {
- // res.result = {
- // code: '',
- // message: ''
- // }
-}).catch(err=>{
- // 处理错误
-})
-
-// 云函数
-exports.main = async function (event, context){
- const res = await uniCloud.getPhoneNumber({
- appid: context.APPID, // 客户端callFunction时携带的AppId信息
- provider: 'univerify',
- apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
- apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
- access_token: event.access_token,
- openid: event.openid
- })
- // 执行入库等操作,正常情况下不要把完整手机号返回给前端
- return {
- code: 0,
- message: '获取手机号成功'
- }
-}
-```
-
-**注意**
-
-- 开发期间如果重新获取过appid需要重新编译uni-app项目
-
-### 5+项目
-
-5+项目不可使用callFunction请求云函数,这时候可以使用云函数URL化让5+项目通过http请求的方式访问云函数
-
-```js
-// 客户端
-const xhr = new plus.net.XMLHttpRequest();
-xhr.onload = function(e) {
- const {
- code,
- message
- } = JSON.parse(xhr.responseText)
-}
-xhr.open( "POST", "https://xxx" ); // url应为云函数Url化之后的地址,可以在uniCloud web控制台云函数详情页面看到
-xhr.setRequestHeader('Content-Type','application/json');
-xhr.send(JSON.stringify({
- access_token: 'xxx', // 客户端一键登录接口返回的access_token
- openid: 'xxx' // 客户端一键登录接口返回的openid
-}));
-
-// 云函数,下面仅展示客户端使用post方式发送content-type为application/json请求的场景
-exports.main = async function(event){
- let body = event.body
- if(event.isBase64Encoded) {
- body = Buffer.from(body,'base64')
- }
- const {
- access_token,
- openid
- } = JSON.parse(body)
- const res = await uniCloud.getPhoneNumber({
- provider: 'univerify',
- appid: 'xxx', // DCloud appid
- apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
- apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
- access_token: access_token,
- openid: openid
- })
- // 执行入库等操作,正常情况下不要把完整手机号返回给前端
- return {
- code: 0,
- message: '获取手机号成功'
- }
-}
-```
-
-### 自有服务器调用
-
-写法类似上面5+项目的云函数url化的方式,但是不同的是需要云函数返回手机号给自己服务器,这样就需要确保数据安全。
-
-下面以一个简单的例子演示如何使用签名验证请求是否合法
-
-```js
-// 以nodejs为例
-const crypto = require('crypto')
-
-const secret = 'your-secret-string' // 自己的密钥不要直接使用示例值,且注意不要泄露
-const hmac = crypto.createHmac('sha256', secret);
-
-// 自有服务器生成签名,并以GET方式发送请求
-const params = {
- access_token: 'xxx', // 客户端传到自己服务器的参数
- openid: 'xxx'
-}
-// 字母顺序排序后拼接签名串
-const signStr = Object.keys(params).sort().map(key => {
- return `${key}=${params[key]}`
-}).join('&')
-hmac.update(signStr);
-const sign = hmac.digest('hex')
-// 最终请求如下链接,其中https://xxxx/xxx为云函数Url化地址
-// https://xxxx/xxx?access_token=xxx&openid=xxx&sign=${sign} 其中${sign}为上一步得到的sign值
-```
-
-
-```js
-// 云函数验证签名,此示例中以接受GET请求为例作演示
-const crypto = require('crypto')
-exports.main = async function (event){
-
- const secret = 'your-secret-string' // 自己的密钥不要直接使用示例值,且注意不要泄露
- const hmac = crypto.createHmac('sha256', secret);
-
- let params = event.queryStringParameters
- const sign = params.sign
- delete params.sign
- const signStr = Object.keys(params).sort().map(key => {
- return `${key}=${params[key]}`
- }).join('&')
-
- hmac.update(signStr);
-
- if(sign!==hmac.digest('hex')){
- throw new Error('非法访问')
- }
-
- const {
- access_token,
- openid
- } = params
- const res = await uniCloud.getPhoneNumber({
- provider: 'univerify',
- appid: 'xxx', // DCloud appid
- apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
- apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
- access_token: access_token,
- openid: openid
- })
- // 返回手机号给自己服务器
- return res
-}
-```
+## 一键登录@univerify
+
+
+
+`univerify` 是DCloud 推出的一键登录产品,通过与运营商深度合作,实现APP用户无需输入帐号密码,即可使用本机手机号码自动登录的能力。
+
+`univerify`是替代短信验证登录的下一代登录验证方式,能消除现有短信验证模式等待时间长、操作繁琐和容易泄露的痛点。
+
+> 注意:一键登录必须是手机使用流量的前提下才能获取到手机号码,用Wi-Fi联网时无法获取到手机号码,同时如果是双卡手机,获取到的手机号码是默认移动数据的那个手机卡的号码。
+
+## 重要调整
+
+### 云函数使用一键登录扩展库@extension
+
+自`HBuilderX 3.4.0`起,一键登录相关功能移至扩展库`uni-cloud-verify`内。在一段时间内无论开发者是否使用扩展库云函数都可以正常使用`uniCloud.getPhoneNumber`。HBuilderX 3.4.0及之后的版本上传云函数时如果没有指定使用`uni-cloud-verify`扩展库的云函数将无法调用uniCloud.getPhoneNumber接口。
+
+关于扩展库的说明见:[云函数扩展库](uniCloud/cf-functions.md?id=extension)
+
+在云函数的package.json内添加`uni-cloud-verify`的引用即可为云函数启用此扩展,无需做其他调整,完整的package.json示例如下:
+
+```js
+{
+ "name": "univerify",
+ "extensions": {
+ "uni-cloud-verify": {} // 启用一键登录扩展,值为空对象即可
+ }
+}
+```
+
+## 客户端@client
+
+客户端如何使用一键登录请参考此文档:[univerify 使用指南](/univerify)
+
+## 云函数@cloud
+
+> 自`HBuilderX 3.4.0`起云函数需启用uni-cloud-verify之后才可以调用getPhoneNumber接口,详细说明见:[云函数使用一键登录扩展库](#extension)
+
+客户端调用一键登录接口会获取如下结果
+
+```js
+{
+ "target": {
+ "id": "univerify",
+ "description": "一键登录",
+ "authResult": {
+ "openid": "xxx",
+ "access_token": "xxx"
+ }
+ }
+}
+```
+
+使用上面结果中的`openid`和`access_token`即可在`云函数`内调用接口获取手机号
+
+云函数内接口调用形式如下
+
+```js
+exports.main = async function(event, context){
+ const res = await uniCloud.getPhoneNumber({
+ provider: 'univerify',
+ appid: context.APPID, // 客户端callFunction时携带的AppId信息
+ apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
+ apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
+ access_token: event.access_token,
+ openid: event.openid
+ })
+ // res形式如下
+ // {
+ // code: 0,
+ // message: '',
+ // phoneNumber: '138xxxxxxxx'
+ // }
+}
+```
+
+**相关文档**
+- [uniCloud快速上手](https://uniapp.dcloud.net.cn/uniCloud/quickstart)
+- [云函数URL化](https://uniapp.dcloud.net.cn/uniCloud/http)
+
+### uni-app项目
+
+如果开发uni-app项目可以使用callFunction的方式调用云函数
+
+```js
+// 客户端
+uniCloud.callFunction({
+ name: 'xxx', // 你的云函数名称
+ data: {
+ access_token: 'xxx', // 客户端一键登录接口返回的access_token
+ openid: 'xxx' // 客户端一键登录接口返回的openid
+ }
+}).then(res => {
+ // res.result = {
+ // code: '',
+ // message: ''
+ // }
+}).catch(err=>{
+ // 处理错误
+})
+
+// 云函数
+exports.main = async function (event, context){
+ const res = await uniCloud.getPhoneNumber({
+ appid: context.APPID, // 客户端callFunction时携带的AppId信息
+ provider: 'univerify',
+ apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
+ apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
+ access_token: event.access_token,
+ openid: event.openid
+ })
+ // 执行入库等操作,正常情况下不要把完整手机号返回给前端
+ return {
+ code: 0,
+ message: '获取手机号成功'
+ }
+}
+```
+
+**注意**
+
+- 开发期间如果重新获取过appid需要重新编译uni-app项目
+
+### 5+项目
+
+5+项目不可使用callFunction请求云函数,这时候可以使用云函数URL化让5+项目通过http请求的方式访问云函数
+
+```js
+// 客户端
+const xhr = new plus.net.XMLHttpRequest();
+xhr.onload = function(e) {
+ const {
+ code,
+ message
+ } = JSON.parse(xhr.responseText)
+}
+xhr.open( "POST", "https://xxx" ); // url应为云函数Url化之后的地址,可以在uniCloud web控制台云函数详情页面看到
+xhr.setRequestHeader('Content-Type','application/json');
+xhr.send(JSON.stringify({
+ access_token: 'xxx', // 客户端一键登录接口返回的access_token
+ openid: 'xxx' // 客户端一键登录接口返回的openid
+}));
+
+// 云函数,下面仅展示客户端使用post方式发送content-type为application/json请求的场景
+exports.main = async function(event){
+ let body = event.body
+ if(event.isBase64Encoded) {
+ body = Buffer.from(body,'base64')
+ }
+ const {
+ access_token,
+ openid
+ } = JSON.parse(body)
+ const res = await uniCloud.getPhoneNumber({
+ provider: 'univerify',
+ appid: 'xxx', // DCloud appid
+ apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
+ apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
+ access_token: access_token,
+ openid: openid
+ })
+ // 执行入库等操作,正常情况下不要把完整手机号返回给前端
+ return {
+ code: 0,
+ message: '获取手机号成功'
+ }
+}
+```
+
+### 自有服务器调用
+
+写法类似上面5+项目的云函数url化的方式,但是不同的是需要云函数返回手机号给自己服务器,这样就需要确保数据安全。
+
+下面以一个简单的例子演示如何使用签名验证请求是否合法
+
+```js
+// 以nodejs为例
+const crypto = require('crypto')
+
+const secret = 'your-secret-string' // 自己的密钥不要直接使用示例值,且注意不要泄露
+const hmac = crypto.createHmac('sha256', secret);
+
+// 自有服务器生成签名,并以GET方式发送请求
+const params = {
+ access_token: 'xxx', // 客户端传到自己服务器的参数
+ openid: 'xxx'
+}
+// 字母顺序排序后拼接签名串
+const signStr = Object.keys(params).sort().map(key => {
+ return `${key}=${params[key]}`
+}).join('&')
+hmac.update(signStr);
+const sign = hmac.digest('hex')
+// 最终请求如下链接,其中https://xxxx/xxx为云函数Url化地址
+// https://xxxx/xxx?access_token=xxx&openid=xxx&sign=${sign} 其中${sign}为上一步得到的sign值
+```
+
+
+```js
+// 云函数验证签名,此示例中以接受GET请求为例作演示
+const crypto = require('crypto')
+exports.main = async function (event){
+
+ const secret = 'your-secret-string' // 自己的密钥不要直接使用示例值,且注意不要泄露
+ const hmac = crypto.createHmac('sha256', secret);
+
+ let params = event.queryStringParameters
+ const sign = params.sign
+ delete params.sign
+ const signStr = Object.keys(params).sort().map(key => {
+ return `${key}=${params[key]}`
+ }).join('&')
+
+ hmac.update(signStr);
+
+ if(sign!==hmac.digest('hex')){
+ throw new Error('非法访问')
+ }
+
+ const {
+ access_token,
+ openid
+ } = params
+ const res = await uniCloud.getPhoneNumber({
+ provider: 'univerify',
+ appid: 'xxx', // DCloud appid
+ apiKey: 'xxx', // 在开发者中心开通服务并获取apiKey
+ apiSecret: 'xxx', // 在开发者中心开通服务并获取apiSecret
+ access_token: access_token,
+ openid: openid
+ })
+ // 返回手机号给自己服务器
+ return res
+}
+```
+
+
+### 一键登录费用说明@unilogin-fee
+
+- 0.02元/次,失败不计费,但在实际使用中需要依赖`uniCloud`云服务,在阿里云商业化后,每条大约需要多花0.0000139元,几乎可以忽略不计,详情查看[短信及一键登录性价比测评](uniCloud/sms-and-unilogin-evaluation.md)