HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

公众号开发(十)云函数缓存机制实现

由于云函数每次运行完都会注销,不像其它后端(如PHP)可以使用session或者文件缓存数据。理论上自己部署redis也是用来缓存数据,但redis不可能部署到云函数的内网中,走外网的话性能肯定大打折扣。因此只能使用云数据库来缓存数组,虽然这会增加数据库的访问次数,但也是没办法的事,好在云数据库的性能比较高,不像mysql那样会成为性能瓶颈

数据库就用之前建好的bctos-cache,它只有三个字段:键名(key),缓存内容(value)和过期时间(expired)

其中为了能保存对象数据,所有保存的数据在入库前先经过 JSON.stringify, 出库时会使用 JSON.parse 进行还原。所以不建议直接查询bctos-cache,而是调用云函数处理。

为方便使用,我们直接在APP.vue里封装了cache方法

async function cache(key, value, expired) {  
    console.log('缓存的参数', {  
        key,  
        value,  
        expired  
    });  
    let res = await uniCloud.callFunction({  
        name: 'bctos-common',  
        data: {  
            action: "cache",  
            key,  
            value,  
            expired  
        }  
    })  
    console.log('缓存的结果', res);  
    if (typeof(res.result.data) == "undefined") {  
        return res.result  
    } else {  
        return res.result.data  
    }  
}

可以这样方便的调用

let app = getApp();  

//写入缓存,并且长期有效  
app.cache('test','123456')  
//写入缓存,而且只缓存300秒,到期自动删除  
app.cache('test','123456', 300)  

//读取缓存  
let res = await app.cache('test')  

//删除缓存, value设为null表示删除  
app.cache('test', null)

如果是在云函数中使用缓存,建议把上面的cache方法复制到云函数中使用

有了这缓存的功能,后面就可以用来缓存access_token和ticket了

继续阅读 »

由于云函数每次运行完都会注销,不像其它后端(如PHP)可以使用session或者文件缓存数据。理论上自己部署redis也是用来缓存数据,但redis不可能部署到云函数的内网中,走外网的话性能肯定大打折扣。因此只能使用云数据库来缓存数组,虽然这会增加数据库的访问次数,但也是没办法的事,好在云数据库的性能比较高,不像mysql那样会成为性能瓶颈

数据库就用之前建好的bctos-cache,它只有三个字段:键名(key),缓存内容(value)和过期时间(expired)

其中为了能保存对象数据,所有保存的数据在入库前先经过 JSON.stringify, 出库时会使用 JSON.parse 进行还原。所以不建议直接查询bctos-cache,而是调用云函数处理。

为方便使用,我们直接在APP.vue里封装了cache方法

async function cache(key, value, expired) {  
    console.log('缓存的参数', {  
        key,  
        value,  
        expired  
    });  
    let res = await uniCloud.callFunction({  
        name: 'bctos-common',  
        data: {  
            action: "cache",  
            key,  
            value,  
            expired  
        }  
    })  
    console.log('缓存的结果', res);  
    if (typeof(res.result.data) == "undefined") {  
        return res.result  
    } else {  
        return res.result.data  
    }  
}

可以这样方便的调用

let app = getApp();  

//写入缓存,并且长期有效  
app.cache('test','123456')  
//写入缓存,而且只缓存300秒,到期自动删除  
app.cache('test','123456', 300)  

//读取缓存  
let res = await app.cache('test')  

//删除缓存, value设为null表示删除  
app.cache('test', null)

如果是在云函数中使用缓存,建议把上面的cache方法复制到云函数中使用

有了这缓存的功能,后面就可以用来缓存access_token和ticket了

收起阅读 »

公众号开发(九)公众号IP白名单配置

之前无论是获取openid还是获取用户信息,都是不需要使用普通接口需要的access_token参数的。但后面的接口就需要用到access_token了,而要获取微信的access_token,是需要配置IP白名单的,但我们的uniCloud云函数是运行在不同的容器中,IP地址是变化的,不是固定的。因此要完全免费实现微信公众号功能,目前看来不大可能。

想要有固定IP地址,方法有三个:

一是使用付费云空间

有钱就是任性,直接购买能提供固定IP的付费云空间就好,这个最简单

二是使用宝塔在自己服务器搭建反向代理

针对上面第二种自己有服务器的情况,并且服务器已经安装了宝塔管理系统,可以按下面流程来增加

增加站点

输入你的域名(以weixin-agent.bctos.cn为例),PHP版本选择静态即可

点网站名进入配置界面

进入反向代理--增加代理

目标URL固定填写https://api.weixin.qq.com,发送域名固定为api.weixin.qq.com,其它内容随意

保存即可生效

然后把自己服务器的外网IP地址配置到公众号平台(mp.weixin.qq.com)的基本配置页面的IP白名单中

然后后面调用微信接口的网址由https://api.weixin.qq.com/xxx修改为代理网址http://weixin-agent.bctos.cn/xxx即可。

如获取access_token的网址:
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

那么使用代理的网址是:
http://weixin-agent.bctos.cn/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

注意我没有配置代理域名的证书,因此只能使用http,如果你配置好证书,也可以使用https

三是共享代理

如果你没有自己的服务器,专门买一台服务器作代理的话花钱多而且还浪费资源。这时可以选择我们的共享代理。

共享代理就是我们出一台服务器,已经按上面的方法搭好了反向代理,你只需要付一小笔费用,就可以使用我们的服务器作代理了。

要使用共享代理请加微信(bctos-cn)咨询,付费后我们会给你服务器IP地址和代理网址(不是上面演示的网址),你只需要配置到你的公众号上即可,我们会提供长期的技术支持的哦。

扫码加微信

继续阅读 »

之前无论是获取openid还是获取用户信息,都是不需要使用普通接口需要的access_token参数的。但后面的接口就需要用到access_token了,而要获取微信的access_token,是需要配置IP白名单的,但我们的uniCloud云函数是运行在不同的容器中,IP地址是变化的,不是固定的。因此要完全免费实现微信公众号功能,目前看来不大可能。

想要有固定IP地址,方法有三个:

一是使用付费云空间

有钱就是任性,直接购买能提供固定IP的付费云空间就好,这个最简单

二是使用宝塔在自己服务器搭建反向代理

针对上面第二种自己有服务器的情况,并且服务器已经安装了宝塔管理系统,可以按下面流程来增加

增加站点

输入你的域名(以weixin-agent.bctos.cn为例),PHP版本选择静态即可

点网站名进入配置界面

进入反向代理--增加代理

目标URL固定填写https://api.weixin.qq.com,发送域名固定为api.weixin.qq.com,其它内容随意

保存即可生效

然后把自己服务器的外网IP地址配置到公众号平台(mp.weixin.qq.com)的基本配置页面的IP白名单中

然后后面调用微信接口的网址由https://api.weixin.qq.com/xxx修改为代理网址http://weixin-agent.bctos.cn/xxx即可。

如获取access_token的网址:
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

那么使用代理的网址是:
http://weixin-agent.bctos.cn/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

注意我没有配置代理域名的证书,因此只能使用http,如果你配置好证书,也可以使用https

三是共享代理

如果你没有自己的服务器,专门买一台服务器作代理的话花钱多而且还浪费资源。这时可以选择我们的共享代理。

共享代理就是我们出一台服务器,已经按上面的方法搭好了反向代理,你只需要付一小笔费用,就可以使用我们的服务器作代理了。

要使用共享代理请加微信(bctos-cn)咨询,付费后我们会给你服务器IP地址和代理网址(不是上面演示的网址),你只需要配置到你的公众号上即可,我们会提供长期的技术支持的哦。

扫码加微信

收起阅读 »

公众号开发(八)从微信中获取用户昵称头像

上一节我们使用openid完成了注册和登录,但uni-id里的用户信息都是空的,这一节我们将实现在微信中获取用户昵称头像。

类似获取openid流程,获取用户信息也是需要跳转页面的,并且还需要用户确认授权才能获取到信息

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

代码已加详细说明

async getWeixinUserInfo() {  
                //如果缓存存在,则直接返回  
                let user = uni.getStorageSync('wx-user')  
                if (user) return user  

                //本地无法跳转,不能获取user  
                if (window.location.href.indexOf('localhost') != -1) return false;  

                //先取uid,保存获取用户信息之前已经通过openid完成注册登录  
                let uid = await this.getUid()  
                if (!uid) return false;  

                //先读取公众号配置  
                let config = await this.bctosCommon('config')  
                let appid = config.result.appId  
                let secret = config.result.appSecret  

                //获取微信跳转带回来的参数  
                let option = this.getGetParam()  
                if (typeof(option.state) == "undefined" || option.state != 'bctos') { //第一步:用户同意授权,获取code  
                    let redirect_uri = encodeURIComponent(location.href.split('#')[0])  
                    window.location.href = 'https://open.weixin.qq.com/connect/oauth2/' +  
                        `authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=bctos#wechat_redirect`  
                } else if (typeof(option.state) != "undefined" && option.state == 'bctos') {  
                    //第二步:通过code换取网页授权access_token  
                    if (!typeof(option.code) || option.code == '') {  
                        this.error('获取code失败')  
                    } else {  
                        //前端不能跨域请求微信服务器,只能通过云函数代请求, 获取openid和access_token  
                        let res = await this.bctosCommon('jsonp', {  
                            url: 'https://api.weixin.qq.com/sns/oauth2/access_token?grant_type=authorization_code' +  
                                `&appid=${appid}&secret=${secret}&code=${option.code}`  
                        })  
                        let data = res.result.data  
                        if (typeof(data) != "object" || typeof(data.openid) == "undefined") {  
                            this.error(JSON.stringify(data))  
                        } else {  
                            uni.setStorageSync('openid', data.openid)  

                            //获取用户信息  
                            res = await this.bctosCommon('jsonp', {  
                                url: `https://api.weixin.qq.com/sns/userinfo?access_token=${data.access_token}&openid=${data.openid}&lang=zh_CN`  
                            })  
                            if (typeof(res.result.data) != "object" || typeof(res.result.data.openid) == "undefined") {  
                                this.error(JSON.stringify(res.result.data))  
                            } else {  
                                //获取的结果缓存在前端  
                                uni.setStorageSync('wx-user', res.result.data)  
                                //获取的结果保存到uni-id的用户表中  
                                this.bctosCommon('saveUserInfo', {  
                                    uid,  
                                    ...res.result.data  
                                })  
                                return res.result.data  
                            }  
                        }  
                    }  
                }  
                return false  
            }

虽然它调用它后端云函数jsonp,但它只是一个代获取远程信息的作用,代码如下

            if (!event.method) {  
                event.method = 'GET'  
            }  
            if (!event.data) {  
                event.data = {}  
            }  
            if (!event.dataType) {  
                event.dataType = 'json'  
            }  
            res = await uniCloud.httpclient.request(event.url, {  
                method: event.method,  
                data: event.data,  
                dataType: event.dataType  
            })

因为如果直接在前端使用uni.request请求的话,会报跨域错误,只能使用后端uniCloud.httpclient.request方法来请求。

得到结果后保存到uni-id的代码如下

            let save = {  
                uid: event.uid,  
                wx_openid: event.openid,  
                nickname: event.nickname,  
                gender: event.sex,  
                province: event.province,  
                city: event.city,  
                country: event.country,  
                avatar: event.headimgurl  
            }  
            if (typeof(event.unionid) != "undefined") save.wx_unionid = event.unionid  

            res = await uniID.updateUser(save)

其中国家(country),省(province),市(city)这三个字段有uni-id的用户表结构中是没有定义的,但不影响数据的保存

继续阅读 »

上一节我们使用openid完成了注册和登录,但uni-id里的用户信息都是空的,这一节我们将实现在微信中获取用户昵称头像。

类似获取openid流程,获取用户信息也是需要跳转页面的,并且还需要用户确认授权才能获取到信息

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

代码已加详细说明

async getWeixinUserInfo() {  
                //如果缓存存在,则直接返回  
                let user = uni.getStorageSync('wx-user')  
                if (user) return user  

                //本地无法跳转,不能获取user  
                if (window.location.href.indexOf('localhost') != -1) return false;  

                //先取uid,保存获取用户信息之前已经通过openid完成注册登录  
                let uid = await this.getUid()  
                if (!uid) return false;  

                //先读取公众号配置  
                let config = await this.bctosCommon('config')  
                let appid = config.result.appId  
                let secret = config.result.appSecret  

                //获取微信跳转带回来的参数  
                let option = this.getGetParam()  
                if (typeof(option.state) == "undefined" || option.state != 'bctos') { //第一步:用户同意授权,获取code  
                    let redirect_uri = encodeURIComponent(location.href.split('#')[0])  
                    window.location.href = 'https://open.weixin.qq.com/connect/oauth2/' +  
                        `authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=bctos#wechat_redirect`  
                } else if (typeof(option.state) != "undefined" && option.state == 'bctos') {  
                    //第二步:通过code换取网页授权access_token  
                    if (!typeof(option.code) || option.code == '') {  
                        this.error('获取code失败')  
                    } else {  
                        //前端不能跨域请求微信服务器,只能通过云函数代请求, 获取openid和access_token  
                        let res = await this.bctosCommon('jsonp', {  
                            url: 'https://api.weixin.qq.com/sns/oauth2/access_token?grant_type=authorization_code' +  
                                `&appid=${appid}&secret=${secret}&code=${option.code}`  
                        })  
                        let data = res.result.data  
                        if (typeof(data) != "object" || typeof(data.openid) == "undefined") {  
                            this.error(JSON.stringify(data))  
                        } else {  
                            uni.setStorageSync('openid', data.openid)  

                            //获取用户信息  
                            res = await this.bctosCommon('jsonp', {  
                                url: `https://api.weixin.qq.com/sns/userinfo?access_token=${data.access_token}&openid=${data.openid}&lang=zh_CN`  
                            })  
                            if (typeof(res.result.data) != "object" || typeof(res.result.data.openid) == "undefined") {  
                                this.error(JSON.stringify(res.result.data))  
                            } else {  
                                //获取的结果缓存在前端  
                                uni.setStorageSync('wx-user', res.result.data)  
                                //获取的结果保存到uni-id的用户表中  
                                this.bctosCommon('saveUserInfo', {  
                                    uid,  
                                    ...res.result.data  
                                })  
                                return res.result.data  
                            }  
                        }  
                    }  
                }  
                return false  
            }

虽然它调用它后端云函数jsonp,但它只是一个代获取远程信息的作用,代码如下

            if (!event.method) {  
                event.method = 'GET'  
            }  
            if (!event.data) {  
                event.data = {}  
            }  
            if (!event.dataType) {  
                event.dataType = 'json'  
            }  
            res = await uniCloud.httpclient.request(event.url, {  
                method: event.method,  
                data: event.data,  
                dataType: event.dataType  
            })

因为如果直接在前端使用uni.request请求的话,会报跨域错误,只能使用后端uniCloud.httpclient.request方法来请求。

得到结果后保存到uni-id的代码如下

            let save = {  
                uid: event.uid,  
                wx_openid: event.openid,  
                nickname: event.nickname,  
                gender: event.sex,  
                province: event.province,  
                city: event.city,  
                country: event.country,  
                avatar: event.headimgurl  
            }  
            if (typeof(event.unionid) != "undefined") save.wx_unionid = event.unionid  

            res = await uniID.updateUser(save)

其中国家(country),省(province),市(city)这三个字段有uni-id的用户表结构中是没有定义的,但不影响数据的保存

收起阅读 »

公众号开发(七)uni-id自动注册和登录

在上一节我们得到openid之后,就可以在uni-id绑定用户,实现注册和登录功能了。

前端比较简单,只需要把openid提交给后端,由后端操作uni-id实现注册和登录,得到用户ID后缓存起来供后面的使用

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

async getUid() {  
                //如果缓存存在,则直接返回  
                let user = uniCloud.getCurrentUserInfo()  
                console.log('user', user);  
                if (user.uid) return user.uid  

                //如果openid不存在,自动先去获取openid  
                let openid = await this.getOpenid()  
                console.log('openid', openid);  
                if (!openid) return false  

                //后端使用openid实现自动注册和登录功能  
                let res = await this.bctosCommon('loginOrRegister', {  
                    openid  
                })  
                console.log('get res', res)  
                if (res.result.code === 0) {  
                    //返回成功,缓存uni-id相关信息  
                    uni.setStorageSync('uni_id_token', res.result.token)  
                    uni.setStorageSync('uni_id_token_expired', res.result.tokenExpired)  
                    uni.setStorageSync('uid', res.result.uid)  
                    return res.result.uid  
                } else {  
                    this.error(res.result.message)  
                    return false  
                }  
            }

后面的实现代码,直接使用openid作为用户名和密码进行注册,当然这个开发者也可以加点其它信息让密码复杂些。

            let param = {  
                username: event.openid,  
                password: event.openid  
            }  
            res = await uniID.login({  
                ...param,  
                queryField: ['username']  
            })  
            if (res.code == 10101 || res.code == 10002) {  
                console.log('need register')  
                param.wx_openid = event.openid  
                if (typeof(event.unionid) != "undefined") param.wx_unionid = event.unionid  
                res = await uniID.register(param)  
            }

它先使用uniID.login登录,如果错误提示码为10101或10002表示用户不存在,就先使用uniID.register完成注册和登录

这就是openid与用户ID实现绑定的逻辑,比较简单。

继续阅读 »

在上一节我们得到openid之后,就可以在uni-id绑定用户,实现注册和登录功能了。

前端比较简单,只需要把openid提交给后端,由后端操作uni-id实现注册和登录,得到用户ID后缓存起来供后面的使用

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

async getUid() {  
                //如果缓存存在,则直接返回  
                let user = uniCloud.getCurrentUserInfo()  
                console.log('user', user);  
                if (user.uid) return user.uid  

                //如果openid不存在,自动先去获取openid  
                let openid = await this.getOpenid()  
                console.log('openid', openid);  
                if (!openid) return false  

                //后端使用openid实现自动注册和登录功能  
                let res = await this.bctosCommon('loginOrRegister', {  
                    openid  
                })  
                console.log('get res', res)  
                if (res.result.code === 0) {  
                    //返回成功,缓存uni-id相关信息  
                    uni.setStorageSync('uni_id_token', res.result.token)  
                    uni.setStorageSync('uni_id_token_expired', res.result.tokenExpired)  
                    uni.setStorageSync('uid', res.result.uid)  
                    return res.result.uid  
                } else {  
                    this.error(res.result.message)  
                    return false  
                }  
            }

后面的实现代码,直接使用openid作为用户名和密码进行注册,当然这个开发者也可以加点其它信息让密码复杂些。

            let param = {  
                username: event.openid,  
                password: event.openid  
            }  
            res = await uniID.login({  
                ...param,  
                queryField: ['username']  
            })  
            if (res.code == 10101 || res.code == 10002) {  
                console.log('need register')  
                param.wx_openid = event.openid  
                if (typeof(event.unionid) != "undefined") param.wx_unionid = event.unionid  
                res = await uniID.register(param)  
            }

它先使用uniID.login登录,如果错误提示码为10101或10002表示用户不存在,就先使用uniID.register完成注册和登录

这就是openid与用户ID实现绑定的逻辑,比较简单。

收起阅读 »

公众号开发(六)获取微信公众号的用户openid

从现在开始正式进入公众号H5开发,首先需要先获取用户openid。

由于获取openid需要先跳转到微信然后带参数跳转回来,因此只能在前端实现openid的获取。

实现获取openid代码

可能以后很多页面都需要获取openid,因此把获取方法直接写在根目录的App.vue文件的methods里

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

代码已经加了详细的说明


methods: {  
            async getOpenid() {  
                //如果缓存存在,则直接返回  
                let openid = uni.getStorageSync('openid')  
                if (openid) return openid  

                //本地无法跳转,不能获取openid  
                if (window.location.href.indexOf('localhost') != -1) return false;  

                //先读取公众号配置  
                let config = await this.bctosCommon('config')  
                let appid = config.result.appId  
                let secret = config.result.appSecret  

                //获取微信跳转带回来的参数  
                let option = this.getGetParam()  
                if (typeof(option.state) == "undefined" || option.state != 'bctos') {   
                    //第一步:用户同意授权,获取code  
                    let redirect_uri = encodeURIComponent(location.href.split('#')[0])  
                    window.location.href = 'https://open.weixin.qq.com/connect/oauth2/'    
                        `authorize?appid=${appid}
继续阅读 »

从现在开始正式进入公众号H5开发,首先需要先获取用户openid。

由于获取openid需要先跳转到微信然后带参数跳转回来,因此只能在前端实现openid的获取。

实现获取openid代码

可能以后很多页面都需要获取openid,因此把获取方法直接写在根目录的App.vue文件的methods里

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

代码已经加了详细的说明


methods: {  
            async getOpenid() {  
                //如果缓存存在,则直接返回  
                let openid = uni.getStorageSync('openid')  
                if (openid) return openid  

                //本地无法跳转,不能获取openid  
                if (window.location.href.indexOf('localhost') != -1) return false;  

                //先读取公众号配置  
                let config = await this.bctosCommon('config')  
                let appid = config.result.appId  
                let secret = config.result.appSecret  

                //获取微信跳转带回来的参数  
                let option = this.getGetParam()  
                if (typeof(option.state) == "undefined" || option.state != 'bctos') {   
                    //第一步:用户同意授权,获取code  
                    let redirect_uri = encodeURIComponent(location.href.split('#')[0])  
                    window.location.href = 'https://open.weixin.qq.com/connect/oauth2/'    
                        `authorize?appid=${appid}
收起阅读 »

【app+sockjs】app下,stompjs不支持uniapp环境?

在uniapp下,用浏览器和h5调试,使用sockjs+stompjs没有任何问题。但是app下,无法使用stompjs,貌似不兼容。只好用sockjs,然后模拟stompjs的订阅,发送消息给websocket了。

在uniapp下,用浏览器和h5调试,使用sockjs+stompjs没有任何问题。但是app下,无法使用stompjs,貌似不兼容。只好用sockjs,然后模拟stompjs的订阅,发送消息给websocket了。

uniapp 蓝牙打印机 打印图片、二维码、条码、文字等 最新解决方案【兼容 小程序、android App】无偿分享出

蓝牙打印 经验分享

参考连接:
使用native.js 在uni app中 连接经典蓝牙 任意打印图片,摆脱ble低功耗的低速传输

便携式蓝牙打印,研究了很长时间,终于打印出来了,现在分享经验,省的少走弯路

微信小程序连接蓝牙打印机打印图片示例

热敏打印机编程 ESC/POS指令 【尤其这篇对图片处理讲解的非常好】

两个页面:

使用native.js连接蓝牙的demo -- 快速打印(只兼容app)

使用BLE低功耗蓝牙的demo -- 低速打印(可兼容小程序)

努力研究了三天,熬夜两个通宵终于打印出来了
【如果你们打印出现偏差,请检查图片的宽度是不是8的倍数,如果不是就用画图调整一下】
其他的问题请 私信我

demo地址 gitee开源中国:BluetoothPrinter 欢迎star

继续阅读 »

参考连接:
使用native.js 在uni app中 连接经典蓝牙 任意打印图片,摆脱ble低功耗的低速传输

便携式蓝牙打印,研究了很长时间,终于打印出来了,现在分享经验,省的少走弯路

微信小程序连接蓝牙打印机打印图片示例

热敏打印机编程 ESC/POS指令 【尤其这篇对图片处理讲解的非常好】

两个页面:

使用native.js连接蓝牙的demo -- 快速打印(只兼容app)

使用BLE低功耗蓝牙的demo -- 低速打印(可兼容小程序)

努力研究了三天,熬夜两个通宵终于打印出来了
【如果你们打印出现偏差,请检查图片的宽度是不是8的倍数,如果不是就用画图调整一下】
其他的问题请 私信我

demo地址 gitee开源中国:BluetoothPrinter 欢迎star

收起阅读 »

公众号开发(五)公众号域名配置及参数配置

公众号平台配置

登录公众号平台(https://mp.weixin.qq.com/)

公众号设置--功能设置页面,先设置好业务,JS,网页三个地方的安全域名。

在测试号设置安全域名(正式公众号设置的地方在: 公众号设置--功能设置 里):

设置网页授权域名

确认保存

公众号参数配置到uni-config-center

由于公众号的参数(如appid,appsecret等)都是比较机密的信息,直接写到前端uniapp里不大安全,可以像上一节增加uni-id配置一样增加公众号配置到uni-config-center

uni_modules\uni-config-center\uniCloud\cloudfunctions\common\uni-config-center目录下创建bctos-weixin-h5目录,然后在其下面创建config.json文档,要根据自己公众号的实际的参数填写

{  
    "appId": "公众号appid",  
    "appSecret": "公众号密钥",  
    "mchId": "微信支付商户ID",  
    "mchKey": "微信支付API密钥",  
    "notify_url": "微信支付回调地址"  
}

增加读取配置的云函数

由于前端uniapp无法直接读取uni-config-center里的配置,需要一个云函数帮我们实现参数的读取。

在uniCloud/cloudfunctions目录上右键新键云函数,函数名为:bctos-config-center,在自动生成的index.js文件写入以下代码

'use strict';  
const createConfig = require('uni-config-center')  

exports.main = async (event, context) => {  
    //event为客户端上传的参数  
    console.log('event : ', event)  

    if (typeof(event.pluginId) == "undefined") event.pluginId = 'bctos-weixin-h5';  

    const uniIdConfig = createConfig({  
        pluginId: event.pluginId  
    })  

    if (typeof(event.key) == "undefined" || event.key == '') {  
        console.log('获取全部配置');  
        return uniIdConfig.config();  
    } else {  
        console.log('获取指定配置');  
        return uniIdConfig.config(event.key);  
    }  
};  

由于这个云函数使用了uni-config-center,因此需要右键bctos-config-center目录管理公共模块依赖

之前由于对云函数理解不深,以为直接引用就可以,其实每个云函数在运行都是在相互独立的环境中,因此资源是不互相共用的,云函数每次引用别的资源时,都需要重新执行管理公共模块依赖以便更新依赖。

测试前端是否能获取到配置

打开pages/index/index文件,直接onLoad方法里加入测试代码看看能不能取到配置数据

        onLoad() {  
            uniCloud.callFunction({  
                name: "bctos-config-center",  
                data: {}  
            }).then(res => {  
                console.log('config', res);  
            })  
        },

在HBuilder X的调试里选择连接本地云函数,因为云函数和配置还没上传云端,所以要选择本地调试

然后运行项目到内置浏览器看看

运行起来后我们可以看到配置信息

说明我们已经能正常读取公众号配置信息

继续阅读 »

公众号平台配置

登录公众号平台(https://mp.weixin.qq.com/)

公众号设置--功能设置页面,先设置好业务,JS,网页三个地方的安全域名。

在测试号设置安全域名(正式公众号设置的地方在: 公众号设置--功能设置 里):

设置网页授权域名

确认保存

公众号参数配置到uni-config-center

由于公众号的参数(如appid,appsecret等)都是比较机密的信息,直接写到前端uniapp里不大安全,可以像上一节增加uni-id配置一样增加公众号配置到uni-config-center

uni_modules\uni-config-center\uniCloud\cloudfunctions\common\uni-config-center目录下创建bctos-weixin-h5目录,然后在其下面创建config.json文档,要根据自己公众号的实际的参数填写

{  
    "appId": "公众号appid",  
    "appSecret": "公众号密钥",  
    "mchId": "微信支付商户ID",  
    "mchKey": "微信支付API密钥",  
    "notify_url": "微信支付回调地址"  
}

增加读取配置的云函数

由于前端uniapp无法直接读取uni-config-center里的配置,需要一个云函数帮我们实现参数的读取。

在uniCloud/cloudfunctions目录上右键新键云函数,函数名为:bctos-config-center,在自动生成的index.js文件写入以下代码

'use strict';  
const createConfig = require('uni-config-center')  

exports.main = async (event, context) => {  
    //event为客户端上传的参数  
    console.log('event : ', event)  

    if (typeof(event.pluginId) == "undefined") event.pluginId = 'bctos-weixin-h5';  

    const uniIdConfig = createConfig({  
        pluginId: event.pluginId  
    })  

    if (typeof(event.key) == "undefined" || event.key == '') {  
        console.log('获取全部配置');  
        return uniIdConfig.config();  
    } else {  
        console.log('获取指定配置');  
        return uniIdConfig.config(event.key);  
    }  
};  

由于这个云函数使用了uni-config-center,因此需要右键bctos-config-center目录管理公共模块依赖

之前由于对云函数理解不深,以为直接引用就可以,其实每个云函数在运行都是在相互独立的环境中,因此资源是不互相共用的,云函数每次引用别的资源时,都需要重新执行管理公共模块依赖以便更新依赖。

测试前端是否能获取到配置

打开pages/index/index文件,直接onLoad方法里加入测试代码看看能不能取到配置数据

        onLoad() {  
            uniCloud.callFunction({  
                name: "bctos-config-center",  
                data: {}  
            }).then(res => {  
                console.log('config', res);  
            })  
        },

在HBuilder X的调试里选择连接本地云函数,因为云函数和配置还没上传云端,所以要选择本地调试

然后运行项目到内置浏览器看看

运行起来后我们可以看到配置信息

说明我们已经能正常读取公众号配置信息

收起阅读 »

公众号开发(四)导入uni-id及相关配置

安装uni-id

如果你的项目在创建里就选择uni-id的模板,安装这一步可省略,但配置部分一样是需要的。

打开插件库:https://ext.dcloud.net.cn/plugin?id=2116

点击导入到当前项目中

配置uni-id

在uni-config-center公用模块下创建uni-id目录

这部分官网描述不是很清楚,如果不知道公用模块的目录在哪里,很容易搞糊涂,我也是通过其示例代码才知道是要在uni_modules\uni-config-center\uniCloud\cloudfunctions\common\uni-config-center这个目录下创建uni-id目录

在创建的uni-id目录下再创建config.json文件

config.json内容以下

{  
    "passwordSecret": "bctos-weixin-h5",  
    "tokenSecret": "bctos-weixin-h5",  
    "tokenExpiresIn": 7200,  
    "tokenExpiresThreshold": 600,  
    "passwordErrorLimit": 6,  
    "passwordErrorRetryTime": 3600,  
    "autoSetInviteCode": false,  
    "forceInviteCode": false,  
    "app-plus": {  
        "tokenExpiresIn": 2592000,  
        "oauth" : {  
            "weixin" : {  
                "appid" : "weixin appid",  
                "appsecret" : "weixin appsecret"  
            },  
            "apple":    {  
                "bundleId": "your APP bundleId"  
            }  
        }  
    },  
    "mp-weixin": {  
        "oauth" : {  
            "weixin" : {  
                "appid" : "weixin appid",  
                "appsecret" : "weixin appsecret"  
            }  
        }  
    },  
    "mp-alipay": {  
        "oauth" : {  
            "alipay" : {  
                "appid" : "alipay appid",  
                "privateKey" : "alipay privateKey"  
            }  
        }  
    },  
    "service": {  
        "sms": {  
            "name": "your app name",  
            "codeExpiresIn": 180,  
            "smsKey": "your sms key",  
            "smsSecret": "your sms secret"  
        },  
        "univerify": {  
            "appid":"your appid",  
            "apiKey": "your apiKey",  
            "apiSecret": "your apiSecret"  
        }  
    }  
}  

只需要配置passwordSecret和tokenSecret两个参数即可,其它参数用不到,全部使用官方默认

在cloudfunctions/common下上传uni-id模块

cloudfunctions/common目前有好几个,确切的完整目录应该是uniCloud\cloudfunctions\common

先上传uni-config-center公共模块

否则会报获取公共模块 uni-config-center 云端代码文件失败

然后在uni-id目录上右键,选择上传公共模块

云数据库增加uni-id数据表

在uniCloud目录上右键,打开数据库管理界面

点+号增加

使用OpenDB表模板创建

回到HBuilder X工具,在database目录下右键下载新增加的表

至此uni-id全部配置完毕,后面需要用到的uni-id的云函数还有一步操作,就是要在所需uni-id的云函数目录上右键选择管理公共模块依赖添加uni-id到云函数里,后面讲到云函数开发时也会说到。

继续阅读 »

安装uni-id

如果你的项目在创建里就选择uni-id的模板,安装这一步可省略,但配置部分一样是需要的。

打开插件库:https://ext.dcloud.net.cn/plugin?id=2116

点击导入到当前项目中

配置uni-id

在uni-config-center公用模块下创建uni-id目录

这部分官网描述不是很清楚,如果不知道公用模块的目录在哪里,很容易搞糊涂,我也是通过其示例代码才知道是要在uni_modules\uni-config-center\uniCloud\cloudfunctions\common\uni-config-center这个目录下创建uni-id目录

在创建的uni-id目录下再创建config.json文件

config.json内容以下

{  
    "passwordSecret": "bctos-weixin-h5",  
    "tokenSecret": "bctos-weixin-h5",  
    "tokenExpiresIn": 7200,  
    "tokenExpiresThreshold": 600,  
    "passwordErrorLimit": 6,  
    "passwordErrorRetryTime": 3600,  
    "autoSetInviteCode": false,  
    "forceInviteCode": false,  
    "app-plus": {  
        "tokenExpiresIn": 2592000,  
        "oauth" : {  
            "weixin" : {  
                "appid" : "weixin appid",  
                "appsecret" : "weixin appsecret"  
            },  
            "apple":    {  
                "bundleId": "your APP bundleId"  
            }  
        }  
    },  
    "mp-weixin": {  
        "oauth" : {  
            "weixin" : {  
                "appid" : "weixin appid",  
                "appsecret" : "weixin appsecret"  
            }  
        }  
    },  
    "mp-alipay": {  
        "oauth" : {  
            "alipay" : {  
                "appid" : "alipay appid",  
                "privateKey" : "alipay privateKey"  
            }  
        }  
    },  
    "service": {  
        "sms": {  
            "name": "your app name",  
            "codeExpiresIn": 180,  
            "smsKey": "your sms key",  
            "smsSecret": "your sms secret"  
        },  
        "univerify": {  
            "appid":"your appid",  
            "apiKey": "your apiKey",  
            "apiSecret": "your apiSecret"  
        }  
    }  
}  

只需要配置passwordSecret和tokenSecret两个参数即可,其它参数用不到,全部使用官方默认

在cloudfunctions/common下上传uni-id模块

cloudfunctions/common目前有好几个,确切的完整目录应该是uniCloud\cloudfunctions\common

先上传uni-config-center公共模块

否则会报获取公共模块 uni-config-center 云端代码文件失败

然后在uni-id目录上右键,选择上传公共模块

云数据库增加uni-id数据表

在uniCloud目录上右键,打开数据库管理界面

点+号增加

使用OpenDB表模板创建

回到HBuilder X工具,在database目录下右键下载新增加的表

至此uni-id全部配置完毕,后面需要用到的uni-id的云函数还有一步操作,就是要在所需uni-id的云函数目录上右键选择管理公共模块依赖添加uni-id到云函数里,后面讲到云函数开发时也会说到。

收起阅读 »

公众号开发(三)系统分析和数据表结构设计

可视化插件安装

在开始增加数据表之前,我们先安装一个可视化管理表结构插件:https://ext.dcloud.net.cn/plugin?id=4800
它可以非常直观又高效地完成表字段的创建。

安装后可能需要重启下HBuilder X

系统分析

从上一篇的界面看虽然只有两个界面,但客户要实现的需求如下:

  1. 文章的标题和内容需要在后台可以配置。
  2. 表单里的协议内容需要也在后台可以配置。
  3. 表单的内容需要在后台列出来,并需要加一个状态管理(待处理,处理中,已处理)。
  4. 还有一个隐藏需求,就是带分享分销(一级)功能,后台设置分销地址(一个地址对应一个人),用户通过这个分销地址进入的下的单记录这个分享人上。

因此,我们需要创建的数据表结构设计如下

数据表结构设计

表单数据表 bctos-order

字段名 类型 说明
email string 邮箱
mobile string 手机号码
idcard_0 file 身份证正面
idcard_1 file 身份证反面
uid string 用户id, 它关联外键:uni-id-users._id, 即用户表里的_id
share_uid string 分享人, 它关联外键:bctos-share._id, 即下表里的_id
is_pay int 支付状态, 默认为0,[{"text":"未支付","value":0},{"text":"已支付","value":1}]
out_trade_no string 微信支付订单号
status int 处理状态, 默认为0,[{"text":"未处理","value":0},{"text":"进行中","value":1},{"text":"已完成","value":2}]

后台配置/云函数缓存表 bctos-cache

字段名 类型 说明
key string 键名
value string 缓存数据,对象和数组会在保存时会自动使用JSON.stringify传成字符串保存
expired int 过期时间,为-1时表示不限制,后台配置一般为-1,云函数缓存token一般为7200秒

分销用户数据表 bctos-share

字段名 类型 说明
username string 分享人姓名
mobile string 手机号码
remark string 备注

我们开发主要围绕上面这个业务表进行,因此需要先熟悉这三表的字段。

继续阅读 »

可视化插件安装

在开始增加数据表之前,我们先安装一个可视化管理表结构插件:https://ext.dcloud.net.cn/plugin?id=4800
它可以非常直观又高效地完成表字段的创建。

安装后可能需要重启下HBuilder X

系统分析

从上一篇的界面看虽然只有两个界面,但客户要实现的需求如下:

  1. 文章的标题和内容需要在后台可以配置。
  2. 表单里的协议内容需要也在后台可以配置。
  3. 表单的内容需要在后台列出来,并需要加一个状态管理(待处理,处理中,已处理)。
  4. 还有一个隐藏需求,就是带分享分销(一级)功能,后台设置分销地址(一个地址对应一个人),用户通过这个分销地址进入的下的单记录这个分享人上。

因此,我们需要创建的数据表结构设计如下

数据表结构设计

表单数据表 bctos-order

字段名 类型 说明
email string 邮箱
mobile string 手机号码
idcard_0 file 身份证正面
idcard_1 file 身份证反面
uid string 用户id, 它关联外键:uni-id-users._id, 即用户表里的_id
share_uid string 分享人, 它关联外键:bctos-share._id, 即下表里的_id
is_pay int 支付状态, 默认为0,[{"text":"未支付","value":0},{"text":"已支付","value":1}]
out_trade_no string 微信支付订单号
status int 处理状态, 默认为0,[{"text":"未处理","value":0},{"text":"进行中","value":1},{"text":"已完成","value":2}]

后台配置/云函数缓存表 bctos-cache

字段名 类型 说明
key string 键名
value string 缓存数据,对象和数组会在保存时会自动使用JSON.stringify传成字符串保存
expired int 过期时间,为-1时表示不限制,后台配置一般为-1,云函数缓存token一般为7200秒

分销用户数据表 bctos-share

字段名 类型 说明
username string 分享人姓名
mobile string 手机号码
remark string 备注

我们开发主要围绕上面这个业务表进行,因此需要先熟悉这三表的字段。

收起阅读 »

公众号开发(二)公众号H5项目创建与域名配置

项目创建

后面系列文章以当前项目为准进行介绍说明,本次项目命名为:bctos-weixin-h5,项目配置如下

一定要启用uniCloud,默认选择阿里云即可

项目生成后,在uniCloud目录上右键,创建云空间

创建同名云空间

创建成功回到HBuilder X工具,继续在在uniCloud目录上右键,选择关联云空间

选择刚创建的云空间

即可完成项目创建

前端网页托管域名配置

由于是H5页面,域名是必须,虽然后面我们使用DCloud的前端网页托管作为网页存放的地址,它提供了默认域名,但这个默认域名还是有限制的,因此必须先有一个自己的备案过的域名。

后面我们将以 weixin-h5.bctos.cn 这个域名为例子进行说明,同时由于是演示,后面我们也是使用测试公众号来演示,如果要在手机上体验,先关注我的测试号(测试完成后建议取消关注,我们也会每隔一段时间清理一次)

打开uniCloud后台

进入前端网页托管界面,先开通


开通成功后,点参数配置

增加域名



把页面刷新下就可以把审核中的状态变成配置中,并能得到CHAME的值

在自己的域名管理那边增加CHAME解析,如我的域名在阿里云是这样配置的:

配置完成,稍等一会刷新前端网页托管配置即可看到部署完成

最后把域名配置到跨域配置中


继续阅读 »

项目创建

后面系列文章以当前项目为准进行介绍说明,本次项目命名为:bctos-weixin-h5,项目配置如下

一定要启用uniCloud,默认选择阿里云即可

项目生成后,在uniCloud目录上右键,创建云空间

创建同名云空间

创建成功回到HBuilder X工具,继续在在uniCloud目录上右键,选择关联云空间

选择刚创建的云空间

即可完成项目创建

前端网页托管域名配置

由于是H5页面,域名是必须,虽然后面我们使用DCloud的前端网页托管作为网页存放的地址,它提供了默认域名,但这个默认域名还是有限制的,因此必须先有一个自己的备案过的域名。

后面我们将以 weixin-h5.bctos.cn 这个域名为例子进行说明,同时由于是演示,后面我们也是使用测试公众号来演示,如果要在手机上体验,先关注我的测试号(测试完成后建议取消关注,我们也会每隔一段时间清理一次)

打开uniCloud后台

进入前端网页托管界面,先开通


开通成功后,点参数配置

增加域名



把页面刷新下就可以把审核中的状态变成配置中,并能得到CHAME的值

在自己的域名管理那边增加CHAME解析,如我的域名在阿里云是这样配置的:

配置完成,稍等一会刷新前端网页托管配置即可看到部署完成

最后把域名配置到跨域配置中


收起阅读 »

公众号开发(一)前言及使用dcloud全家桶开发介绍

本次公众号开发系列文章中介绍的代码已经以插件的方式上传到市场: https://ext.dcloud.net.cn/plugin?id=4829

开发背景

本作者是十几年的PHP后端开发者,偶尔前端忙不过来的话也兼一些前端工作,后来微信小程序出来后直接上手小程序开发,也发过几个小程序开发教程。一个偶然的机会我们的前端使用uniapp开发了一个项目,然后我们也都开始了uniapp开发之旅。但也仅是作为一个前端框架使用,后端还是使用我们自己的PHP系统。

直到最近看到uniCloud的逆天介绍:[什么是uniCloud](https://uniapp.dcloud.io/uniCloud/README "什么是uniCloud")

关键有三点:免费免费免费,云函数,云数据还有前端网页托管,都是免费

这对大部分创业前期的项目来说很重要,因此萌生了要把公众号需要所的后端全部修改为云函数的想法,看能不能不依赖服务器的情况完成公众号的H5全部功能

最近刚好需要一个实际运营公众号项目,决定使用uniCloud作为后端开发,虽然目前插件库很丰富,号称能减少很多重复造轮子的工作,但这些造好的轮子大多是给小程序用的,开发公众号的话还是要自己造轮子,很多基础的功能都没有现成的插件可用。

本着人人为我,我为人人的原则,给大家提供这个插件,这将大大减少大家的开发时间,大家不用再重复造轮子了

技术框架介绍

前端使用uniapp开发,这是一定的。

后台使用uniCloud的云函数,数据库也是uniCloud的云数据库

公众号H5前端有使用到uni-id用户体系,用到uni-center-config配置中心

为是免费到底,代码放到uniCloud里的前端网页托管,据说它不经过web server,页面和资源直接上cdn,就近访问,速度贼快!!^_^

要开发,我只认dcloud系列,哦耶!^_^

功能介绍

本次要开发只有一个表单界面:

功能非常简单,没有复杂的业务逻辑,因此很适合大家学习使用。但它却包含了公众号H5开发都会涉及以下几个功能:

1、在网页中获取微信公众号的用户openid

2、通过静默获取用户openid并在uni-id中实现自动完成注册登录等功能,即用户无感知进入系统时就完成了登录操作

3、从微信中获取用户昵称头像等信息,并保存到uni-id中

4、云函数实现缓存机制,并用来缓存微信access_token等数据

5、实现JS-SDK配置(这是重点和难点),实现自定义分享内容

6、导入uni-ui实现前端用户界面

7、微信支付配置及在网页中实现支付功能

总之,公众号开发涉及的主要功能都涉及了,包括签名失败的问题也搞了两天,各种填坑也没少。因此这个项目模板能省大家很多精力和时间,下载地址:https://ext.dcloud.net.cn/plugin?id=4829

继续阅读 »

本次公众号开发系列文章中介绍的代码已经以插件的方式上传到市场: https://ext.dcloud.net.cn/plugin?id=4829

开发背景

本作者是十几年的PHP后端开发者,偶尔前端忙不过来的话也兼一些前端工作,后来微信小程序出来后直接上手小程序开发,也发过几个小程序开发教程。一个偶然的机会我们的前端使用uniapp开发了一个项目,然后我们也都开始了uniapp开发之旅。但也仅是作为一个前端框架使用,后端还是使用我们自己的PHP系统。

直到最近看到uniCloud的逆天介绍:[什么是uniCloud](https://uniapp.dcloud.io/uniCloud/README "什么是uniCloud")

关键有三点:免费免费免费,云函数,云数据还有前端网页托管,都是免费

这对大部分创业前期的项目来说很重要,因此萌生了要把公众号需要所的后端全部修改为云函数的想法,看能不能不依赖服务器的情况完成公众号的H5全部功能

最近刚好需要一个实际运营公众号项目,决定使用uniCloud作为后端开发,虽然目前插件库很丰富,号称能减少很多重复造轮子的工作,但这些造好的轮子大多是给小程序用的,开发公众号的话还是要自己造轮子,很多基础的功能都没有现成的插件可用。

本着人人为我,我为人人的原则,给大家提供这个插件,这将大大减少大家的开发时间,大家不用再重复造轮子了

技术框架介绍

前端使用uniapp开发,这是一定的。

后台使用uniCloud的云函数,数据库也是uniCloud的云数据库

公众号H5前端有使用到uni-id用户体系,用到uni-center-config配置中心

为是免费到底,代码放到uniCloud里的前端网页托管,据说它不经过web server,页面和资源直接上cdn,就近访问,速度贼快!!^_^

要开发,我只认dcloud系列,哦耶!^_^

功能介绍

本次要开发只有一个表单界面:

功能非常简单,没有复杂的业务逻辑,因此很适合大家学习使用。但它却包含了公众号H5开发都会涉及以下几个功能:

1、在网页中获取微信公众号的用户openid

2、通过静默获取用户openid并在uni-id中实现自动完成注册登录等功能,即用户无感知进入系统时就完成了登录操作

3、从微信中获取用户昵称头像等信息,并保存到uni-id中

4、云函数实现缓存机制,并用来缓存微信access_token等数据

5、实现JS-SDK配置(这是重点和难点),实现自定义分享内容

6、导入uni-ui实现前端用户界面

7、微信支付配置及在网页中实现支付功能

总之,公众号开发涉及的主要功能都涉及了,包括签名失败的问题也搞了两天,各种填坑也没少。因此这个项目模板能省大家很多精力和时间,下载地址:https://ext.dcloud.net.cn/plugin?id=4829

收起阅读 »