HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

easypush的简单使用

消息推送 推送 Push

获取appkey

点击这里先注册一个账号,然后在应用管理中创建一个新的应用,这样就可以获得一个appkey

客户端集成jssdk

 在客户端页面通过以下代码引入jssdk:  
<script type="text/javascript" src="http://ep.eastech-inc.com/js/EasyPush-min.js"></script>  

初始化EasyPush

控制台

   通过以下代码初始化  
EasyPush: easyPush = EasyPush.init({ host:'pushapi.eastech-inc.com', appkey:'idF9J2pwWPl2pWwV', clientId:'user001' });

参数解释:
参数名称 : host 是否必填:参数值示例:pushapi.eastech-inc.com 参数解释: 云推送服务器域名,目前固定是pushapi.eastech-inc.com
参数名称 : appkey 是否必填:参数值示例: idF9J2pwWPl2pWwV 参数解释: step0中获取的appkey,每个应用都有一个appkey,通过appkey区分不用的应用,可以在控制台中查看
参数名称 : clientId 是否必填:参数值示例: user001 参数解释: 表示当前是哪个客户端连接到服务器,通过这个标识可以区分出客户端的身份,建议可以填写当前系统中能够区分身份的唯一标识,例如用户id等等

连接到云推送服务器

    通过以下代码连接到推送服务器:  
easyPush.connect({ onSuccess:function() { // dosomething }, onFailed:function(message) { console.log(message); } });

订阅通道接收消息

  通过以下代码订阅通道接收消息:  
 easyPush.subscribe({ channel:'channel0', onMessage:function(channel,data){ // dosomething }, onSuccess:function() { // dosomething } });  
其中channel表示需要订阅的通道名称,通道不需要预先定义,在使用过程中会自动创建。回调函数onMessage会在收到消息时自动触发,channel代表当前接收到消息的通道名称,data代表消息

发送消息

通过以下代码可以发送消息:

easyPush.publish({ message:'Hello,EasyPush', channel:'channel0', onSuccess:function() { // dosomething } });  
其中message表示发送的内容,channel表示需要发送到哪个通道,一旦发送成功,step4中订阅该通道的所有客户端会收到message  
通过以上6个步骤就可以使用EasyPush消息推送功能了。

最后,这里有一个完整版的demo,能够让你更好的了解如何使用jssdk,点击此处下载。

继续阅读 »

获取appkey

点击这里先注册一个账号,然后在应用管理中创建一个新的应用,这样就可以获得一个appkey

客户端集成jssdk

 在客户端页面通过以下代码引入jssdk:  
<script type="text/javascript" src="http://ep.eastech-inc.com/js/EasyPush-min.js"></script>  

初始化EasyPush

控制台

   通过以下代码初始化  
EasyPush: easyPush = EasyPush.init({ host:'pushapi.eastech-inc.com', appkey:'idF9J2pwWPl2pWwV', clientId:'user001' });

参数解释:
参数名称 : host 是否必填:参数值示例:pushapi.eastech-inc.com 参数解释: 云推送服务器域名,目前固定是pushapi.eastech-inc.com
参数名称 : appkey 是否必填:参数值示例: idF9J2pwWPl2pWwV 参数解释: step0中获取的appkey,每个应用都有一个appkey,通过appkey区分不用的应用,可以在控制台中查看
参数名称 : clientId 是否必填:参数值示例: user001 参数解释: 表示当前是哪个客户端连接到服务器,通过这个标识可以区分出客户端的身份,建议可以填写当前系统中能够区分身份的唯一标识,例如用户id等等

连接到云推送服务器

    通过以下代码连接到推送服务器:  
easyPush.connect({ onSuccess:function() { // dosomething }, onFailed:function(message) { console.log(message); } });

订阅通道接收消息

  通过以下代码订阅通道接收消息:  
 easyPush.subscribe({ channel:'channel0', onMessage:function(channel,data){ // dosomething }, onSuccess:function() { // dosomething } });  
其中channel表示需要订阅的通道名称,通道不需要预先定义,在使用过程中会自动创建。回调函数onMessage会在收到消息时自动触发,channel代表当前接收到消息的通道名称,data代表消息

发送消息

通过以下代码可以发送消息:

easyPush.publish({ message:'Hello,EasyPush', channel:'channel0', onSuccess:function() { // dosomething } });  
其中message表示发送的内容,channel表示需要发送到哪个通道,一旦发送成功,step4中订阅该通道的所有客户端会收到message  
通过以上6个步骤就可以使用EasyPush消息推送功能了。

最后,这里有一个完整版的demo,能够让你更好的了解如何使用jssdk,点击此处下载。

收起阅读 »

找能把银联云闪付原生SDK,封装成插件的

原生插件 银联

有没有会把银联云闪付的微信小程序、支付宝小程序支付封装成uniapp插件的,有偿,做过的来

QQ 764523371

有没有会把银联云闪付的微信小程序、支付宝小程序支付封装成uniapp插件的,有偿,做过的来

QQ 764523371

uniapp webview H5 postMessage实时提交数据

Webview HTML5

注意要点:H5里面的 webview uni对象 是存在层级问题的:uni.webView.postMessage 这个才对。uni.postMessage是不能的使用的。

注意要点:H5里面的 webview uni对象 是存在层级问题的:uni.webView.postMessage 这个才对。uni.postMessage是不能的使用的。

关于Android漏洞风险说明及修复方案

Android漏洞 安全检测 安全漏洞

此文档已迁移,Android安全漏洞风险问题请参考uni-app官方文档

<!--
陆续收到开发者同学反馈在腾讯云、百度云、爱加密等平台检测到 uni-app 或 5+ App 的漏洞风险问题。我们也在不断跟进和修复。

目前收集到的相关漏铜风险分为高风险、中风险和低风险三种危险程度。
高风险:可被恶意程序利用 且几乎不需要认证
中风险:可能被中级入侵经验者利用、且不一定需要认证
低风险:仅可能被本地利用且需要认证

风险问题多数为低风险。理论上这些低风险也不会影响应用的安全质量。对于高中漏洞风险的问题我们会优先处理!

收集到漏洞风险问题分为:

  • DCloud代码漏洞风险 :我们可以操作修改问题。或提供配置让用户抉择。
  • 三方SDK模块漏洞风险问题 :由于没有源码。无法操作修改。用户可以抉择是否使用该模块来规避风险问题

修复方案

目前会根据漏洞风险等级优先处理中高级,但可能每次版本修复的问题与开发者遇到的风险问题不一致。建议开发者同学先使用APK加固来加强应用的安全性使应用可以安全上架!等待后续版本修复相关问题。
对于三方SDK漏洞问题,需要开发者同学积极反馈敦促相关平台提供修复漏洞风险问题的SDK。我们也会留意平台更新。并及时更新到模块中!

DCloud代码漏洞风险 修复记录

HX3.1.14版本
修复以下漏洞风险问题
修复已知WebView File域同源策略绕过漏洞问题
修复已知Android平台WebView控件跨域访问高危漏洞问题
修复已知Webview绕过证书校验漏洞问题 需配置后生效
修复已知Android主机名\证书弱校验风险问题 需配置后生效

<a id="web_untrustedca"></a>

Webview绕过证书校验漏洞Android主机名\证书弱校验风险 需要配置才能生效。具体如下:

配置 manifest.json 中的untrustedca节点信息,设置"refuse"或者"warning"即可去除漏洞问题。默认值为"accept"

untrustedca值域说明:
配置应用中https请求时,如果服务器返回非受信证书的处理逻辑,字符串类型,可取值:
"accept" - 接受此非受信证书,继续访问;
"refuse" - 拒绝此非 受信证书,停止访问;
"warning" - 弹出警告提示框提醒用户,由用户确定是否继续访问。仅针对webview内部请求

默认值为"accept"。需要注意如果设置refuse、warning后可能现有应用这的网络请求无法正常运行!

配置如下 修复漏洞问题:

 "plus": {  //uni-app项目对应节点名称为"app-plus"    
        "ssl": {    
            "untrustedca": "warning/refuse"    
        },    
        // ...    
    }

怎么区分DCloud代码漏洞还是三方SDK的问题呢?

你通常可以 通过漏洞详情中的漏洞代码类名进行区分,DCloud代码多数使用io.dcloud开头,其它为三方SDK漏洞。

DCloud代码漏洞风险:

三方SDK漏洞风险:

关于组件导出风险

3.1.14+版本目前DCloud代码并没有组件导出风险的问题。基本上都是三方模块的配置具体可参考:

微信SDK: 分享、支付、登录都会有要求设置WXEntryActivity、WXPayEntryActivity并设置组件导出!
unipush模块:pushSDK内部会涉及到部分组件CustomGTService、PushReceiver、GActivity、NotificationServic等都会涉及到组件导出。

如果您的项目因为组建导出风险而无法上架只能去除以上模块的集成。

关于应用签名未校验风险

app内部记录打包时的签名SHA1。启动时可通过plus.navigator.getSignature()获取android平台的签名SHA1,两者进行比对。如果不一致表示可能被重签名存在风险选择是否退出。实现应用重签名校验逻辑。

APK可被反编译后取得源代码

请对APK进行加固,推荐使用腾讯加固平台。

WebView远程代码执行漏洞

风险描述:Android系统通过WebView.addJavascriptInterface方法注册可供JavaScript调用的Java对象,以用于增强JavaScript的功能。但是系统并没有对注册Java类的方法调用的限制。导致攻击者可以利用反射机制调用未注册的其它任何Java类,最终导致JavaScript能力的无限增强。攻击者利用该漏洞可以根据客户端能力实现远程任意代码执行攻击。 WebView 远程代码执行漏洞触发前提条件: 1)使用addJavascriptInterface方法注册可供JavaScript调用的Java对象; 2)使用WebView加载外部网页或者本地网页; 3)Android系统版本低于4.2。

目前3.1.14+版本的代码配置的minSdkVersion最低是19 也就是4.4系统。也就是说4.4系统并不存在该漏洞问题。如果你的项目minSdkVersion低于19 请修改为19或更高。

密钥硬编码漏洞

请使用3.1.14+版本打包。
-->

继续阅读 »

此文档已迁移,Android安全漏洞风险问题请参考uni-app官方文档

<!--
陆续收到开发者同学反馈在腾讯云、百度云、爱加密等平台检测到 uni-app 或 5+ App 的漏洞风险问题。我们也在不断跟进和修复。

目前收集到的相关漏铜风险分为高风险、中风险和低风险三种危险程度。
高风险:可被恶意程序利用 且几乎不需要认证
中风险:可能被中级入侵经验者利用、且不一定需要认证
低风险:仅可能被本地利用且需要认证

风险问题多数为低风险。理论上这些低风险也不会影响应用的安全质量。对于高中漏洞风险的问题我们会优先处理!

收集到漏洞风险问题分为:

  • DCloud代码漏洞风险 :我们可以操作修改问题。或提供配置让用户抉择。
  • 三方SDK模块漏洞风险问题 :由于没有源码。无法操作修改。用户可以抉择是否使用该模块来规避风险问题

修复方案

目前会根据漏洞风险等级优先处理中高级,但可能每次版本修复的问题与开发者遇到的风险问题不一致。建议开发者同学先使用APK加固来加强应用的安全性使应用可以安全上架!等待后续版本修复相关问题。
对于三方SDK漏洞问题,需要开发者同学积极反馈敦促相关平台提供修复漏洞风险问题的SDK。我们也会留意平台更新。并及时更新到模块中!

DCloud代码漏洞风险 修复记录

HX3.1.14版本
修复以下漏洞风险问题
修复已知WebView File域同源策略绕过漏洞问题
修复已知Android平台WebView控件跨域访问高危漏洞问题
修复已知Webview绕过证书校验漏洞问题 需配置后生效
修复已知Android主机名\证书弱校验风险问题 需配置后生效

<a id="web_untrustedca"></a>

Webview绕过证书校验漏洞Android主机名\证书弱校验风险 需要配置才能生效。具体如下:

配置 manifest.json 中的untrustedca节点信息,设置"refuse"或者"warning"即可去除漏洞问题。默认值为"accept"

untrustedca值域说明:
配置应用中https请求时,如果服务器返回非受信证书的处理逻辑,字符串类型,可取值:
"accept" - 接受此非受信证书,继续访问;
"refuse" - 拒绝此非 受信证书,停止访问;
"warning" - 弹出警告提示框提醒用户,由用户确定是否继续访问。仅针对webview内部请求

默认值为"accept"。需要注意如果设置refuse、warning后可能现有应用这的网络请求无法正常运行!

配置如下 修复漏洞问题:

 "plus": {  //uni-app项目对应节点名称为"app-plus"    
        "ssl": {    
            "untrustedca": "warning/refuse"    
        },    
        // ...    
    }

怎么区分DCloud代码漏洞还是三方SDK的问题呢?

你通常可以 通过漏洞详情中的漏洞代码类名进行区分,DCloud代码多数使用io.dcloud开头,其它为三方SDK漏洞。

DCloud代码漏洞风险:

三方SDK漏洞风险:

关于组件导出风险

3.1.14+版本目前DCloud代码并没有组件导出风险的问题。基本上都是三方模块的配置具体可参考:

微信SDK: 分享、支付、登录都会有要求设置WXEntryActivity、WXPayEntryActivity并设置组件导出!
unipush模块:pushSDK内部会涉及到部分组件CustomGTService、PushReceiver、GActivity、NotificationServic等都会涉及到组件导出。

如果您的项目因为组建导出风险而无法上架只能去除以上模块的集成。

关于应用签名未校验风险

app内部记录打包时的签名SHA1。启动时可通过plus.navigator.getSignature()获取android平台的签名SHA1,两者进行比对。如果不一致表示可能被重签名存在风险选择是否退出。实现应用重签名校验逻辑。

APK可被反编译后取得源代码

请对APK进行加固,推荐使用腾讯加固平台。

WebView远程代码执行漏洞

风险描述:Android系统通过WebView.addJavascriptInterface方法注册可供JavaScript调用的Java对象,以用于增强JavaScript的功能。但是系统并没有对注册Java类的方法调用的限制。导致攻击者可以利用反射机制调用未注册的其它任何Java类,最终导致JavaScript能力的无限增强。攻击者利用该漏洞可以根据客户端能力实现远程任意代码执行攻击。 WebView 远程代码执行漏洞触发前提条件: 1)使用addJavascriptInterface方法注册可供JavaScript调用的Java对象; 2)使用WebView加载外部网页或者本地网页; 3)Android系统版本低于4.2。

目前3.1.14+版本的代码配置的minSdkVersion最低是19 也就是4.4系统。也就是说4.4系统并不存在该漏洞问题。如果你的项目minSdkVersion低于19 请修改为19或更高。

密钥硬编码漏洞

请使用3.1.14+版本打包。
-->

收起阅读 »

如何把 uni-id 插件用于H5页面

一、准备

将整套uni-id插件导入编辑器,上传所有云函数及公用函数。
pages页面全部删除,自建主页,登录页,注册页,修改密码页。
保留全部VUEX部分

1.1 主页设置

  • onLoad() 即开始检测 token
  • uni_id_token 保存着 token 信息,分为两种情况:有token和没有token
  • 本地 token 正确也未过期,修改VUEX状态this.login(uni.getStorageSync('username'));
  • 本地 token 错误或者过期了,跳转登录页面 uni.reLaunch({url: '../login/login'});
  • 本地没有 token ,跳转至登录页面

import { mapState, mapMutations } from 'vuex';  
export default {  
    computed: mapState(['userName', 'hasLogin']),  
    data() {  
        return {  
        };  
    },  
    onLoad() {  
        let uid = { uid: `${uni.getStorageSync('user_id')}` };  
        let uniIdToken = uni.getStorageSync('uni_id_token');  
        if (uniIdToken) {  
        //有 token 的情况下,开始检测  
            uniCloud.callFunction({  
                name: 'user-center',  
                data: {  
                    action: 'checkToken'  
                },  
                success: e => {  
                    if (e.result.code > 0) {  
                  //检测 token 有问题,返回登录页  
                        uni.reLaunch({  
                            url: '../login/login'  
                        });  
                    }  
            this.login(uni.getStorageSync('username'));  
                },  
                fail(e) {  
                    uni.showModal({  
                        content: e.msg,  
                        showCancel: false  
                    });  
                }  
            });  
        } else {  
        //没有 token 的情况下,返回登录页  
            uni.showModal({  
                content: '请登录后再浏览',  
                showCancel: false,  
                success: res => {  
                    if (res.confirm) {  
                        uni.reLaunch({  
                            url: '../login/login'  
                        });  
                    }  
                }  
            });  
        }  
    },  
    methods: {  
        ...mapMutations(['login']),  
        login_out() {  
            uni.reLaunch({  
                url: '../login/login'  
            });  
        }  
    }  
};

1.2 登录页面设置

  • 登录后,保存了tokenusernameuser_id,然后跳转到主页
  • user_id 将用于删除云数据库uni-id-log中过多的、重复的登录记录。 文末有删除记录的云函数方法。
methods: {  
    ...mapMutations(['login']),  
    loginByPwd() {  
        const data = {  
            username: this.username,  
            password: this.password  
        };  
        uniCloud.callFunction({  
            name: 'user-center',  
            data: {  
                action: 'login',  
                params: data  
            },  
            success: (e) => {  
                if (e.result.code == 0) {  
                // 密码验证成功  
                    uni.setStorageSync('uni_id_token', e.result.token);  
                    uni.setStorageSync('username', e.result.username);  
                    uni.setStorageSync('user_id', e.result.uid);  
                    this.toMain(this.username);  
                } else {  
                // 密码验证失败  
                    uni.showModal({  
                        content: e.result.message,  
                        showCancel: false  
                    })  
                }  
            },  
            fail: (e) => {  
                uni.showModal({  
                    content: JSON.stringify(e),  
                    showCancel: false  
                })  
            }  
        })  
    },  
    toMain(userName) {  
        this.login(userName);  
        uni.reLaunch({  
            url: '../main/main',  
        });  
    }  
}

1.3 注册请求

  • 对于用户名和密码的格式要求,需自己写。
  • 注意:注册时发送给云函数user-centerdata数据的格式data:{action:'register',params: 账号,密码}
gotoRegister() {  
    uni.showLoading({  
        title: '正在提交,请稍后'  
    });  
    const data = {  
        username: this.username,  
        password: this.password  
    };  
    uniCloud.callFunction({  
        name: 'user-center',  
        data: {  
            action: 'register',  
            params: data  
        },  
        success(e) {  
            uni.hideLoading();  
            if (e.result.code === 0) {  
                uni.showToast({  
                    title: '注册成功'  
                });  
            uni.setStorageSync('uni_id_token', e.result.token);  
            uni.setStorageSync('username', e.result.username);  
            uni.reLaunch({  
                url: '../main/main'  
            });  
            } else {  
                uni.showModal({  
                    content: JSON.stringify(e.result),  
                    showCancel: false  
                });  
            }  
        },  
        fail(e) {  
            uni.hideLoading();  
            uni.showModal({  
                content: JSON.stringify(e),  
                showCancel: false  
            });  
        }  
    });  
}

1.4 补充

  • 删除多余登录记录的云函数
  • 获取当前user_id的全部登录记录数据,筛选出create_date值不是最大的全部记录,逐一删除。
  • 云函数 removeID
'use strict';  
const db = uniCloud.database();  
const dbCmd = db.command;  
exports.main = async (event, context) => {  
    const {user_id} = event;  
    let resList = await db.collection('uni-id-log')  
        .where({  
            user_id: `${user_id}`  
        })  
        .get();  
    let res = resList.data;  
    if (res.length > 1) {  
        let num = 0;  
        res.forEach((item) => {  
            if (item.create_date > num) {  
                num = item.create_date;  
            }  
        })  
        let resObjArr = await db.collection('uni-id-log')  
            .where({  
                create_date: dbCmd.neq(num)  
            })  
            .get();  
        resObjArr.data.forEach(async (item) => {  
            let resSucc = await db.collection('uni-id-log').doc(`${item._id}`).remove();  
            console.log(resSucc);  
        });  
        const date = new Date().getTime();  
        res = await db.collection('uni-id-log')  
            .where({  
                user_id: `${user_id}`  
            })  
            .get();  
        return {  
            msg: '删除成功',  
            code: 200  
        }  
    } else {  
        return {  
            msg: `当前账号仅有一次登录记录`,  
            code: 200  
        }  
    }  
};

主页onLoad()内调用

onLoad() {  
    const user_id = {user_id:`${uni.getStorageSync('user_id')}`}  
    uniCloud.callFunction({  
        name:'removeID',  
        data:user_id,  
        success: (e) => {  
            console.log(e);  
        },  
        fail: (err) => {  
            console.log(err);  
        }  
    })  
}
继续阅读 »

一、准备

将整套uni-id插件导入编辑器,上传所有云函数及公用函数。
pages页面全部删除,自建主页,登录页,注册页,修改密码页。
保留全部VUEX部分

1.1 主页设置

  • onLoad() 即开始检测 token
  • uni_id_token 保存着 token 信息,分为两种情况:有token和没有token
  • 本地 token 正确也未过期,修改VUEX状态this.login(uni.getStorageSync('username'));
  • 本地 token 错误或者过期了,跳转登录页面 uni.reLaunch({url: '../login/login'});
  • 本地没有 token ,跳转至登录页面

import { mapState, mapMutations } from 'vuex';  
export default {  
    computed: mapState(['userName', 'hasLogin']),  
    data() {  
        return {  
        };  
    },  
    onLoad() {  
        let uid = { uid: `${uni.getStorageSync('user_id')}` };  
        let uniIdToken = uni.getStorageSync('uni_id_token');  
        if (uniIdToken) {  
        //有 token 的情况下,开始检测  
            uniCloud.callFunction({  
                name: 'user-center',  
                data: {  
                    action: 'checkToken'  
                },  
                success: e => {  
                    if (e.result.code > 0) {  
                  //检测 token 有问题,返回登录页  
                        uni.reLaunch({  
                            url: '../login/login'  
                        });  
                    }  
            this.login(uni.getStorageSync('username'));  
                },  
                fail(e) {  
                    uni.showModal({  
                        content: e.msg,  
                        showCancel: false  
                    });  
                }  
            });  
        } else {  
        //没有 token 的情况下,返回登录页  
            uni.showModal({  
                content: '请登录后再浏览',  
                showCancel: false,  
                success: res => {  
                    if (res.confirm) {  
                        uni.reLaunch({  
                            url: '../login/login'  
                        });  
                    }  
                }  
            });  
        }  
    },  
    methods: {  
        ...mapMutations(['login']),  
        login_out() {  
            uni.reLaunch({  
                url: '../login/login'  
            });  
        }  
    }  
};

1.2 登录页面设置

  • 登录后,保存了tokenusernameuser_id,然后跳转到主页
  • user_id 将用于删除云数据库uni-id-log中过多的、重复的登录记录。 文末有删除记录的云函数方法。
methods: {  
    ...mapMutations(['login']),  
    loginByPwd() {  
        const data = {  
            username: this.username,  
            password: this.password  
        };  
        uniCloud.callFunction({  
            name: 'user-center',  
            data: {  
                action: 'login',  
                params: data  
            },  
            success: (e) => {  
                if (e.result.code == 0) {  
                // 密码验证成功  
                    uni.setStorageSync('uni_id_token', e.result.token);  
                    uni.setStorageSync('username', e.result.username);  
                    uni.setStorageSync('user_id', e.result.uid);  
                    this.toMain(this.username);  
                } else {  
                // 密码验证失败  
                    uni.showModal({  
                        content: e.result.message,  
                        showCancel: false  
                    })  
                }  
            },  
            fail: (e) => {  
                uni.showModal({  
                    content: JSON.stringify(e),  
                    showCancel: false  
                })  
            }  
        })  
    },  
    toMain(userName) {  
        this.login(userName);  
        uni.reLaunch({  
            url: '../main/main',  
        });  
    }  
}

1.3 注册请求

  • 对于用户名和密码的格式要求,需自己写。
  • 注意:注册时发送给云函数user-centerdata数据的格式data:{action:'register',params: 账号,密码}
gotoRegister() {  
    uni.showLoading({  
        title: '正在提交,请稍后'  
    });  
    const data = {  
        username: this.username,  
        password: this.password  
    };  
    uniCloud.callFunction({  
        name: 'user-center',  
        data: {  
            action: 'register',  
            params: data  
        },  
        success(e) {  
            uni.hideLoading();  
            if (e.result.code === 0) {  
                uni.showToast({  
                    title: '注册成功'  
                });  
            uni.setStorageSync('uni_id_token', e.result.token);  
            uni.setStorageSync('username', e.result.username);  
            uni.reLaunch({  
                url: '../main/main'  
            });  
            } else {  
                uni.showModal({  
                    content: JSON.stringify(e.result),  
                    showCancel: false  
                });  
            }  
        },  
        fail(e) {  
            uni.hideLoading();  
            uni.showModal({  
                content: JSON.stringify(e),  
                showCancel: false  
            });  
        }  
    });  
}

1.4 补充

  • 删除多余登录记录的云函数
  • 获取当前user_id的全部登录记录数据,筛选出create_date值不是最大的全部记录,逐一删除。
  • 云函数 removeID
'use strict';  
const db = uniCloud.database();  
const dbCmd = db.command;  
exports.main = async (event, context) => {  
    const {user_id} = event;  
    let resList = await db.collection('uni-id-log')  
        .where({  
            user_id: `${user_id}`  
        })  
        .get();  
    let res = resList.data;  
    if (res.length > 1) {  
        let num = 0;  
        res.forEach((item) => {  
            if (item.create_date > num) {  
                num = item.create_date;  
            }  
        })  
        let resObjArr = await db.collection('uni-id-log')  
            .where({  
                create_date: dbCmd.neq(num)  
            })  
            .get();  
        resObjArr.data.forEach(async (item) => {  
            let resSucc = await db.collection('uni-id-log').doc(`${item._id}`).remove();  
            console.log(resSucc);  
        });  
        const date = new Date().getTime();  
        res = await db.collection('uni-id-log')  
            .where({  
                user_id: `${user_id}`  
            })  
            .get();  
        return {  
            msg: '删除成功',  
            code: 200  
        }  
    } else {  
        return {  
            msg: `当前账号仅有一次登录记录`,  
            code: 200  
        }  
    }  
};

主页onLoad()内调用

onLoad() {  
    const user_id = {user_id:`${uni.getStorageSync('user_id')}`}  
    uniCloud.callFunction({  
        name:'removeID',  
        data:user_id,  
        success: (e) => {  
            console.log(e);  
        },  
        fail: (err) => {  
            console.log(err);  
        }  
    })  
}
收起阅读 »

公众号开发(十四)实现公众号的H5微信支付

微信支付商户配置

首先在之前的章节:公众号参数配置到uni-config-center 里一定要配置好支付的参数

    "mchId": "微信支付商户ID",  
    "mchKey": "微信支付API密钥",  
    "notify_url": "微信支付回调地址"

如果之前没配置,这次配置好后要重新上传uni-config-center

生成微信支付回调地址

由于使用云函数的原因,回调地址就需要让云函数支持URL访问。

进入uniCloud的web后台,点击 函数列表--云函数域名绑定

点击启用域名,就会自动生成一个域名

然后云函数点bctos-weixin的详情按钮进入详情界面,因为我们的支付回调写在这个云函数里

在详情页面最下面点编辑

请求路径必须以 /http开头,而且不能以 / 结尾,这里我填写:/http/notice

保存后,点右边的复制路径即可得到上面notify_url参数需要填写的微信支付回调地址,如我的是这样的

https://4d82a040-4004-4008-8e38-83351e4f7e03.bspapp.com/http/notice

然后在云函数的回调里只需要把订单由未支付状态修改成已支付状态即可。

前端实现微信支付

下面是封装好的支付方法,先通过后端云函数生成统一下单,并返回前端需要的支付参数,最后调起支付操作。

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

async weixinPay(money, out_trade_no, ip) {  
                let openid = await this.getOpenid()  
                if (!openid) {  
                    this.error('openid获取失败')  
                    return false  
                }  
                this.showLoading()  
                let data = {  
                    openid,  
                    ip,  
                    out_trade_no,  
                    money,  
                    action: "payment"  
                }  

                console.log('微信支付前端参数', data)  
                let e = await uniCloud.callFunction({  
                    name: 'bctos-weixin',  
                    data: data  
                })  
                if (e.result.code != 0) {  
                    this.error(e.result.msg)  
                    return false  
                }  

                let payment = e.result.data;  
                let param = {  
                    "appId": payment.appId, //公众号名称,由商户传入  
                    "timeStamp": payment.timeStamp, //时间戳,自1970年以来的秒数  
                    "nonceStr": payment.nonceStr, //随机串  
                    "package": payment.package,  
                    "signType": payment.signType, //微信签名方式:  
                    "paySign": payment.paySign //微信签名  
                }  
                console.log('微信支付前端得到的结果', param);  

                WeixinJSBridge.invoke('getBrandWCPayRequest', param)  

                const db = uniCloud.database()  

                //由于最新的微信支付推出了点金计划,导致支付成功后不再回调,因此需要主动查询支付状态  
                let time = setInterval(() => {  
                    db.collection('bctos-order').where({  
                        out_trade_no  
                    }).get().then((res) => {  
                        console.log('bctos-order', res.result.data[0].is_pay)  
                        // res 为数据库查询结果  
                        if (res.result.data[0].is_pay == 1) {  
                            uni.hideLoading()  
                            clearInterval(time)  
                            this.success('支付成功', () => {  
                                uni.redirectTo({  
                                    url: "/pages/index/index"  
                                })  
                            })  
                        }  
                    })  
                }, 1000)  
            },

最终效果

至此开发全部完成。

继续阅读 »

微信支付商户配置

首先在之前的章节:公众号参数配置到uni-config-center 里一定要配置好支付的参数

    "mchId": "微信支付商户ID",  
    "mchKey": "微信支付API密钥",  
    "notify_url": "微信支付回调地址"

如果之前没配置,这次配置好后要重新上传uni-config-center

生成微信支付回调地址

由于使用云函数的原因,回调地址就需要让云函数支持URL访问。

进入uniCloud的web后台,点击 函数列表--云函数域名绑定

点击启用域名,就会自动生成一个域名

然后云函数点bctos-weixin的详情按钮进入详情界面,因为我们的支付回调写在这个云函数里

在详情页面最下面点编辑

请求路径必须以 /http开头,而且不能以 / 结尾,这里我填写:/http/notice

保存后,点右边的复制路径即可得到上面notify_url参数需要填写的微信支付回调地址,如我的是这样的

https://4d82a040-4004-4008-8e38-83351e4f7e03.bspapp.com/http/notice

然后在云函数的回调里只需要把订单由未支付状态修改成已支付状态即可。

前端实现微信支付

下面是封装好的支付方法,先通过后端云函数生成统一下单,并返回前端需要的支付参数,最后调起支付操作。

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

async weixinPay(money, out_trade_no, ip) {  
                let openid = await this.getOpenid()  
                if (!openid) {  
                    this.error('openid获取失败')  
                    return false  
                }  
                this.showLoading()  
                let data = {  
                    openid,  
                    ip,  
                    out_trade_no,  
                    money,  
                    action: "payment"  
                }  

                console.log('微信支付前端参数', data)  
                let e = await uniCloud.callFunction({  
                    name: 'bctos-weixin',  
                    data: data  
                })  
                if (e.result.code != 0) {  
                    this.error(e.result.msg)  
                    return false  
                }  

                let payment = e.result.data;  
                let param = {  
                    "appId": payment.appId, //公众号名称,由商户传入  
                    "timeStamp": payment.timeStamp, //时间戳,自1970年以来的秒数  
                    "nonceStr": payment.nonceStr, //随机串  
                    "package": payment.package,  
                    "signType": payment.signType, //微信签名方式:  
                    "paySign": payment.paySign //微信签名  
                }  
                console.log('微信支付前端得到的结果', param);  

                WeixinJSBridge.invoke('getBrandWCPayRequest', param)  

                const db = uniCloud.database()  

                //由于最新的微信支付推出了点金计划,导致支付成功后不再回调,因此需要主动查询支付状态  
                let time = setInterval(() => {  
                    db.collection('bctos-order').where({  
                        out_trade_no  
                    }).get().then((res) => {  
                        console.log('bctos-order', res.result.data[0].is_pay)  
                        // res 为数据库查询结果  
                        if (res.result.data[0].is_pay == 1) {  
                            uni.hideLoading()  
                            clearInterval(time)  
                            this.success('支付成功', () => {  
                                uni.redirectTo({  
                                    url: "/pages/index/index"  
                                })  
                            })  
                        }  
                    })  
                }, 1000)  
            },

最终效果

至此开发全部完成。

收起阅读 »

升级中心 uni-upgrade-center - Admin 【bug】

uniapp

menu.json 配置文件
配置项
"url": "uni_modules/uni-upgrade-center/pages/app/list"
前面少了个 /
添加菜单后 点击升级中心菜单 菜单不会自动展开
应该为:
"url": "/uni_modules/uni-upgrade-center/pages/app/list"

继续阅读 »

menu.json 配置文件
配置项
"url": "uni_modules/uni-upgrade-center/pages/app/list"
前面少了个 /
添加菜单后 点击升级中心菜单 菜单不会自动展开
应该为:
"url": "/uni_modules/uni-upgrade-center/pages/app/list"

收起阅读 »

公众号开发(十三)表单界面实现

导入uni-ui

进入uni-ui插件界面

https://ext.dcloud.net.cn/plugin?id=55

使用 HBuilderX 导入插件 按钮进入bctos-weixin-h5项目,后面我们需要使用到里面的uniForms, uniEasyinput等组件

界面模板实现

可以先使用schema2code插件生成前端界面,再在这基础上修改会省事很多。

下面直接上模板代码

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

<template>  
    <view class="uni-container">  
        <view class="top-ad">  
            <image style="width: 100%; height: 100px;" mode="aspectFit" src="../../static/head.jpg"></image>  
        </view>  

        <uni-forms ref="form" :value="formData" validate-trigger="submit" err-show-type="toast">  
            <view class="white-rounded">  
                <view style="padding: 1px 15px;">  
                    <view class="nei-romkuan">  
                        <uni-easyinput disabled placeholder="服务内容: 工商注册代办 (经营范围:服务类)"></uni-easyinput>  
                    </view>  
                    <view class="nei-romkuan">  
                        <view class="uni-column">  
                            <text>*</text>电子邮箱 (xxx@xxx.com)  
                        </view>  
                        <uni-easyinput v-model="formData.email" placeholder=" 请输入" />  
                    </view>  
                    <view class="nei-romkuan">  
                        <view class="uni-column">  
                            <text>*</text>手机号码 ( 本人身份证实名的手机号码 )  
                        </view>  
                        <uni-easyinput v-model="formData.mobile" placeholder="请输入" />  
                    </view>  
                </view>  
            </view>  
            <view class="white-rounded white-rounded2">  
                <view class="kuan50">  
                    <uni-file-picker file-mediatype="image" return-type="object" v-model="formData.idcard_0"  
                        :list-styles="styles" :image-styles="styles2"></uni-file-picker>  
                    <view class="shenfen-zheng">上传身份证正面</view>  
                </view>  
                <view class="kuan50">  
                    <uni-file-picker file-mediatype="image" return-type="object" v-model="formData.idcard_1"  
                        :list-styles="styles" :image-styles="styles2" />  
                    <view class="shenfen-zheng">上传身份证背面</view>  
                </view>  
            </view>  
            <view class="uni-button-group">  
                <button type="primary" class="uni-button" @click="submit">微信支付(788.00元)</button>  
            </view>  
        </uni-forms>  
    </view>  
</template>

内容比较明了,就是一个表单页面,只不过加了些排版。

继续阅读 »

导入uni-ui

进入uni-ui插件界面

https://ext.dcloud.net.cn/plugin?id=55

使用 HBuilderX 导入插件 按钮进入bctos-weixin-h5项目,后面我们需要使用到里面的uniForms, uniEasyinput等组件

界面模板实现

可以先使用schema2code插件生成前端界面,再在这基础上修改会省事很多。

下面直接上模板代码

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

<template>  
    <view class="uni-container">  
        <view class="top-ad">  
            <image style="width: 100%; height: 100px;" mode="aspectFit" src="../../static/head.jpg"></image>  
        </view>  

        <uni-forms ref="form" :value="formData" validate-trigger="submit" err-show-type="toast">  
            <view class="white-rounded">  
                <view style="padding: 1px 15px;">  
                    <view class="nei-romkuan">  
                        <uni-easyinput disabled placeholder="服务内容: 工商注册代办 (经营范围:服务类)"></uni-easyinput>  
                    </view>  
                    <view class="nei-romkuan">  
                        <view class="uni-column">  
                            <text>*</text>电子邮箱 (xxx@xxx.com)  
                        </view>  
                        <uni-easyinput v-model="formData.email" placeholder=" 请输入" />  
                    </view>  
                    <view class="nei-romkuan">  
                        <view class="uni-column">  
                            <text>*</text>手机号码 ( 本人身份证实名的手机号码 )  
                        </view>  
                        <uni-easyinput v-model="formData.mobile" placeholder="请输入" />  
                    </view>  
                </view>  
            </view>  
            <view class="white-rounded white-rounded2">  
                <view class="kuan50">  
                    <uni-file-picker file-mediatype="image" return-type="object" v-model="formData.idcard_0"  
                        :list-styles="styles" :image-styles="styles2"></uni-file-picker>  
                    <view class="shenfen-zheng">上传身份证正面</view>  
                </view>  
                <view class="kuan50">  
                    <uni-file-picker file-mediatype="image" return-type="object" v-model="formData.idcard_1"  
                        :list-styles="styles" :image-styles="styles2" />  
                    <view class="shenfen-zheng">上传身份证背面</view>  
                </view>  
            </view>  
            <view class="uni-button-group">  
                <button type="primary" class="uni-button" @click="submit">微信支付(788.00元)</button>  
            </view>  
        </uni-forms>  
    </view>  
</template>

内容比较明了,就是一个表单页面,只不过加了些排版。

收起阅读 »

公众号开发(十二)JS-SDK配置及自定义分享

在网页中要使用分享等一系列的微信JS-SDK功能,要先配置好JS-SDK参数。

安装jweixin-module

要使用公众号H5的JS-SDK功能,先要安装jweixin-module

在bctos-weixin-h5根目录下,执行npm初始化(如果你的根目录下已经有package.json文件可省这一步)

npm init

一直默认回车即可

然后正式安装jweixin-module

npm install jweixin-module --save

安装好后在App.vue文件中引入
var wx = require('jweixin-module')

生成JS-SDK配置参数

然后在pages/index/index页面的onReady方法中加入生成JS-SDK配置参数,让页面一加载进来就完成配置

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

            uniCloud.callFunction({  
                name: 'bctos-weixin',  
                data: {  
                    "action": "getJsApiParams",  
                    "url": location.href.split('#')[0]  
                },  
                success(res) {  
                    console.log('getJsApiParams get res', res)  
                    if (res.result.code != 0) {  
                        getApp().error(res.result.message)  
                    } else {  
                        getApp().share(res.result)  
                    }  
                }  
            })

一定要注意上面url的参数,一定要填写location.href.split('#')[0]
在这一步最容易出现invalid signature错误,我们也是调试了很久才修改好,如果真出现这个问题,先按官方的建议排查一下

1. 确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。  
2. 确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。  
3. 确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。  
4. 确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。  
5. 确保一定缓存access_token和jsapi_ticket。  
6. 确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。  

后端云函数实现getJsApiParams方法的代码

async function getApiTicket() {  
    //先从缓存获取,如果存在就要不重复从微信获取  
    let key = '' + appId  
    let ticket = await cache(key)  
    if (ticket !== false) {  
        console.log('ticket缓存已存在', ticket);  
        return ticket  
    }  

    let access_token = await getAccessToken()  
    if (access_token == false) {  
        return {  
            code: 1,  
            message: '获取access_token失败'  
        }  
    } else {  
        console.log('获取access_token成功', access_token);  
    }  
    //这里也要使用代理网址请求  
    let url = 'http://weixin-agent.bctos.cn/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi'  
    let res = await uniCloud.httpclient.request(url, {  
        method: 'GET',  
        data: {}  
    })  
    let result = JSON.parse(res.data.toString())  
    if (typeof(result.ticket) == "undefined") {  
        console.log('重新获取的Ticket失败了', result)  
        return false  
    } else {  
        console.log('重新获取的Ticket的结果:', result)  
        await cache(key, result.ticket, result.expires_in)  
        return result.ticket  
    }  
}  

        //获取ticket  
        let ticket = await getApiTicket()  
        if (ticket == false) {  
            return {  
                code: 2,  
                message: '获取ticket失败'  
            }  
        } else {  
            console.log('获取ticket成功', ticket);  
        }  
        let ret = {  
            jsapi_ticket: ticket,  
            noncestr: createNonceStr(),  
            timestamp: createTimestamp(),  
            url: event.url  
        };  

        let string = raw(ret)  
        console.log('排序后加加密前的字段串', string)  
        ret.signature = sha1(string);  
        ret.appId = appId  
        ret.code = 0  
        console.log('最终返回的参数', ret)  
        return ret

注意上面获取ticket的地址,特别是&type=jsapi这个参数,由于微信文档里还有一个获取会员卡ticket的地方,名字都是相同的,URL前面的地址也是一样的,只是后面&type=card不一样。之前不知道,就是这个问题导致我们整整调试了两天,反复按官方上面提到的6点调试了很久,还是报invalid signature报错,所以真的如果报这个错误,要一个字母一个字母都仔细比对才行。

实现自定义分享

成功获取到JS-SDK参数后,就可以在前端使用wx.config进行配置了,下面是配置加自定义分享的内容,如果需要加其它功能,如地理位置等信息,需要有jsApiList里加入对于的接口名

share(jsapi_params) {  
                let config = {  
                    debug: false,  
                    appId: jsapi_params.appId, // 必填,公众号的唯一标识  
                    timestamp: jsapi_params.timestamp, // 必填,生成签名的时间戳  
                    nonceStr: jsapi_params.noncestr, // 必填,生成签名的随机串  
                    signature: jsapi_params.signature, // 必填,签名,见附录1  
                    jsApiList: [  
                        'updateAppMessageShareData',  
                        'updateTimelineShareData'  
                    ]  
                }  
                console.log('配置参数', config);  
                wx.config(config);  
                wx.error(function(res) {  
                    console.log('JS-SDK配置出问题了', res)  
                });  
                wx.ready(function() {  
                    //自定义分享的内容,开发者可以自主修改这部分内容  
                    let shareData1 = {  
                        title: '个体工商户在线注册',  
                        link: "https://caiwu.bctos.cn/index.html?suid=" + uni.getStorageSync('share_uid') +  
                            '#pages/config/detail',  
                        imgUrl: "https://caiwu.bctos.cn/static/share.jpg",  
                        success: function(res) {  
                            console.log('分享设置成功', res);  
                        }  
                    }  
                    let shareData2 = {  
                        ...shareData1,  
                        desc: '通过深牛财务线上操作,轻松,快捷办理个体营业执照。'  
                    }  
                    wx.updateAppMessageShareData(shareData2)  
                    wx.updateTimelineShareData(shareData1)  
                });  
            },

要看效果不能在浏览器里预览,一定要在微信开发者工具里看,因为浏览器无法调用微信的JS接口。这是在微信开发者工具的公众号网页调试里看到的效果,看到分享设置成功说明js-sdk参数已经配置正常,在手机里分享的话就可以看到自定义的分享内容了

继续阅读 »

在网页中要使用分享等一系列的微信JS-SDK功能,要先配置好JS-SDK参数。

安装jweixin-module

要使用公众号H5的JS-SDK功能,先要安装jweixin-module

在bctos-weixin-h5根目录下,执行npm初始化(如果你的根目录下已经有package.json文件可省这一步)

npm init

一直默认回车即可

然后正式安装jweixin-module

npm install jweixin-module --save

安装好后在App.vue文件中引入
var wx = require('jweixin-module')

生成JS-SDK配置参数

然后在pages/index/index页面的onReady方法中加入生成JS-SDK配置参数,让页面一加载进来就完成配置

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

            uniCloud.callFunction({  
                name: 'bctos-weixin',  
                data: {  
                    "action": "getJsApiParams",  
                    "url": location.href.split('#')[0]  
                },  
                success(res) {  
                    console.log('getJsApiParams get res', res)  
                    if (res.result.code != 0) {  
                        getApp().error(res.result.message)  
                    } else {  
                        getApp().share(res.result)  
                    }  
                }  
            })

一定要注意上面url的参数,一定要填写location.href.split('#')[0]
在这一步最容易出现invalid signature错误,我们也是调试了很久才修改好,如果真出现这个问题,先按官方的建议排查一下

1. 确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。  
2. 确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。  
3. 确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。  
4. 确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。  
5. 确保一定缓存access_token和jsapi_ticket。  
6. 确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。  

后端云函数实现getJsApiParams方法的代码

async function getApiTicket() {  
    //先从缓存获取,如果存在就要不重复从微信获取  
    let key = '' + appId  
    let ticket = await cache(key)  
    if (ticket !== false) {  
        console.log('ticket缓存已存在', ticket);  
        return ticket  
    }  

    let access_token = await getAccessToken()  
    if (access_token == false) {  
        return {  
            code: 1,  
            message: '获取access_token失败'  
        }  
    } else {  
        console.log('获取access_token成功', access_token);  
    }  
    //这里也要使用代理网址请求  
    let url = 'http://weixin-agent.bctos.cn/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi'  
    let res = await uniCloud.httpclient.request(url, {  
        method: 'GET',  
        data: {}  
    })  
    let result = JSON.parse(res.data.toString())  
    if (typeof(result.ticket) == "undefined") {  
        console.log('重新获取的Ticket失败了', result)  
        return false  
    } else {  
        console.log('重新获取的Ticket的结果:', result)  
        await cache(key, result.ticket, result.expires_in)  
        return result.ticket  
    }  
}  

        //获取ticket  
        let ticket = await getApiTicket()  
        if (ticket == false) {  
            return {  
                code: 2,  
                message: '获取ticket失败'  
            }  
        } else {  
            console.log('获取ticket成功', ticket);  
        }  
        let ret = {  
            jsapi_ticket: ticket,  
            noncestr: createNonceStr(),  
            timestamp: createTimestamp(),  
            url: event.url  
        };  

        let string = raw(ret)  
        console.log('排序后加加密前的字段串', string)  
        ret.signature = sha1(string);  
        ret.appId = appId  
        ret.code = 0  
        console.log('最终返回的参数', ret)  
        return ret

注意上面获取ticket的地址,特别是&type=jsapi这个参数,由于微信文档里还有一个获取会员卡ticket的地方,名字都是相同的,URL前面的地址也是一样的,只是后面&type=card不一样。之前不知道,就是这个问题导致我们整整调试了两天,反复按官方上面提到的6点调试了很久,还是报invalid signature报错,所以真的如果报这个错误,要一个字母一个字母都仔细比对才行。

实现自定义分享

成功获取到JS-SDK参数后,就可以在前端使用wx.config进行配置了,下面是配置加自定义分享的内容,如果需要加其它功能,如地理位置等信息,需要有jsApiList里加入对于的接口名

share(jsapi_params) {  
                let config = {  
                    debug: false,  
                    appId: jsapi_params.appId, // 必填,公众号的唯一标识  
                    timestamp: jsapi_params.timestamp, // 必填,生成签名的时间戳  
                    nonceStr: jsapi_params.noncestr, // 必填,生成签名的随机串  
                    signature: jsapi_params.signature, // 必填,签名,见附录1  
                    jsApiList: [  
                        'updateAppMessageShareData',  
                        'updateTimelineShareData'  
                    ]  
                }  
                console.log('配置参数', config);  
                wx.config(config);  
                wx.error(function(res) {  
                    console.log('JS-SDK配置出问题了', res)  
                });  
                wx.ready(function() {  
                    //自定义分享的内容,开发者可以自主修改这部分内容  
                    let shareData1 = {  
                        title: '个体工商户在线注册',  
                        link: "https://caiwu.bctos.cn/index.html?suid=" + uni.getStorageSync('share_uid') +  
                            '#pages/config/detail',  
                        imgUrl: "https://caiwu.bctos.cn/static/share.jpg",  
                        success: function(res) {  
                            console.log('分享设置成功', res);  
                        }  
                    }  
                    let shareData2 = {  
                        ...shareData1,  
                        desc: '通过深牛财务线上操作,轻松,快捷办理个体营业执照。'  
                    }  
                    wx.updateAppMessageShareData(shareData2)  
                    wx.updateTimelineShareData(shareData1)  
                });  
            },

要看效果不能在浏览器里预览,一定要在微信开发者工具里看,因为浏览器无法调用微信的JS接口。这是在微信开发者工具的公众号网页调试里看到的效果,看到分享设置成功说明js-sdk参数已经配置正常,在手机里分享的话就可以看到自定义的分享内容了

收起阅读 »

公众号开发(十一)实现access_token获取

要获取access_token必须先完成前面几节的配置:

前端网页托管域名配置:https://bctos.cn/doc/18/1955
公众号域名配置:https://bctos.cn/doc/18/1959
公众号IP白名单配置:https://bctos.cn/doc/18/1963
云函数缓存机制实现:https://bctos.cn/doc/18/1964

确保上面的配置都好了之后,就可以进行access_token的获取了。

由于access_token每天请求的次数有限,必须统一在后端云函数里获取并缓存起来,因此我们的实现代码如下

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

async function getAccessToken() {  
    //先从缓存获取,如果存在就要不重复从微信获取  
    let key = '' + appId  
    let token = await cache(key)  
    if (token !== false) {  
        console.log('token缓存已存在', token);  
        return token  
    }  
    //这里要使用代理网址请求  
    let url = 'http://weixin-agent.bctos.cn/cgi-bin/token?grant_type=client_credential'  
    url += '&secret=' + appSecret + '&appId=' + appId  

    let res = await uniCloud.httpclient.request(url, {  
        method: 'GET',  
        data: {}  
    })  
    let result = JSON.parse(res.data.toString())  
    if (typeof(result.access_token) == "undefined") {  
        console.log('重新获取的AccessToken失败了', result)  
        return false  
    } else {  
        console.log('重新获取的AccessToken的结果:', result)  
        await cache(key, result.access_token, result.expires_in)  
        return result.access_token  
    }  
}

如果获取失败,可以在uniCloud的WEB后台里的云函数日志中看到微信返回了什么错误信息

继续阅读 »

要获取access_token必须先完成前面几节的配置:

前端网页托管域名配置:https://bctos.cn/doc/18/1955
公众号域名配置:https://bctos.cn/doc/18/1959
公众号IP白名单配置:https://bctos.cn/doc/18/1963
云函数缓存机制实现:https://bctos.cn/doc/18/1964

确保上面的配置都好了之后,就可以进行access_token的获取了。

由于access_token每天请求的次数有限,必须统一在后端云函数里获取并缓存起来,因此我们的实现代码如下

完整的代码请在官方插件市场下载:https://ext.dcloud.net.cn/plugin?id=4829

async function getAccessToken() {  
    //先从缓存获取,如果存在就要不重复从微信获取  
    let key = '' + appId  
    let token = await cache(key)  
    if (token !== false) {  
        console.log('token缓存已存在', token);  
        return token  
    }  
    //这里要使用代理网址请求  
    let url = 'http://weixin-agent.bctos.cn/cgi-bin/token?grant_type=client_credential'  
    url += '&secret=' + appSecret + '&appId=' + appId  

    let res = await uniCloud.httpclient.request(url, {  
        method: 'GET',  
        data: {}  
    })  
    let result = JSON.parse(res.data.toString())  
    if (typeof(result.access_token) == "undefined") {  
        console.log('重新获取的AccessToken失败了', result)  
        return false  
    } else {  
        console.log('重新获取的AccessToken的结果:', result)  
        await cache(key, result.access_token, result.expires_in)  
        return result.access_token  
    }  
}

如果获取失败,可以在uniCloud的WEB后台里的云函数日志中看到微信返回了什么错误信息

收起阅读 »

uni-app 获取已链接的蓝牙列表

uniapp

官方没有找到如何获取已链接的蓝牙列表,使用如下方法实现,节省大家的时间。

getConnetedDevices(){  
    var main = plus.android.runtimeMainActivity();  
    var Context = plus.android.importClass("android.content.Context");  
    var BManager = main.getSystemService(Context.BLUETOOTH_SERVICE);  
    plus.android.importClass(BManager); //引入相关的method函数  
    var BAdapter = BManager.getAdapter();  
    plus.android.importClass(BAdapter);//引入相关的method函数,这样之后才会有isEna  
    var lists = BAdapter.getBondedDevices();  
    plus.android.importClass(lists);  
    var iterator = lists.iterator();  
    plus.android.importClass(iterator);  
    while(iterator.hasNext()) {  
        var d = iterator.next();  
        plus.android.importClass(d);  
        console.log("名称:"+d.getName()+",地址:"+d.getAddress());  
    }  
}
继续阅读 »

官方没有找到如何获取已链接的蓝牙列表,使用如下方法实现,节省大家的时间。

getConnetedDevices(){  
    var main = plus.android.runtimeMainActivity();  
    var Context = plus.android.importClass("android.content.Context");  
    var BManager = main.getSystemService(Context.BLUETOOTH_SERVICE);  
    plus.android.importClass(BManager); //引入相关的method函数  
    var BAdapter = BManager.getAdapter();  
    plus.android.importClass(BAdapter);//引入相关的method函数,这样之后才会有isEna  
    var lists = BAdapter.getBondedDevices();  
    plus.android.importClass(lists);  
    var iterator = lists.iterator();  
    plus.android.importClass(iterator);  
    while(iterator.hasNext()) {  
        var d = iterator.next();  
        plus.android.importClass(d);  
        console.log("名称:"+d.getName()+",地址:"+d.getAddress());  
    }  
}
收起阅读 »