- (11)低功耗蓝牙能力
在无线通信领域,蓝牙是最基础又常用的能力。蓝牙组网十分简单,两设备间做个配对就可以建立起连接,其通信距离理论值为10米至100米以内,是近距离通信应用场景的首选。今天我们想跟大家分享小程序连接蓝牙的能力。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 目前蓝牙最为普遍的两种规格为蓝牙基础率/增强数据率 (BR/EDR) 和低功耗 (LE) 蓝牙。br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 蓝牙基础率/增强数据率 (BR/EDR) 是经典的蓝牙协议,常用在对数据传输带宽有一定要求的场景上,比如需要传输音频数据的蓝牙音箱等; br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 低功耗 (LE) 蓝牙是从蓝牙4.0起支持的协议,特点就是耗电极低、传输速度更快,常用在对续航要求较高且只需小数据量传输的各种智能电子产品中,包括心率监测仪器、体温计、血糖仪、智能穿戴设备、胎压监测和电子烟等等,应用场景广泛,所以小程序在很早的版本(基础库 1.1.0)就优先支持了低功耗蓝牙能力。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 我们在开发基于低功耗蓝牙接口的小程序时,需要先理解一下蓝牙在连接和通信过程中的一些概念。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 工作模式 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 低功耗蓝牙协议给设备定义了若干角色,其中最主要的角色是:外围设备(Peripheral)与中心设备(Central)。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 1 外围设备是用来提供数据,通过不停地向外广播数据,让中心设备发现自己。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 2 中心设备会扫描外围设备,发现有外围设备存在后,可以与之建立连接,之后就可以使用外围设备提供的服务(Service)。一般而言,手机会担任中心设备的角色,利用外围设备提供的数据进行处理或展示等等。因此,小程序提供低功耗蓝牙接口是默认设定手机为中心设备的。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 通信协议 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 在两个蓝牙设备建立连接之后,双方的数据交互是基于一个叫做 GATT (Generic Attribute Profile) 的规范,根据该规范可以定义出一个个配置文件(Profile),描述该蓝牙设备提供的服务(Service)。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 在整个通信过程中,有三个最主要的概念:配置文件(Profile)、服务(Service)、特性(Characteristic)。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 1 Profile 并不真实存在于蓝牙设备中,它只是被蓝牙标准预先定义的一些 Service 的集合,如果蓝牙设备之间要相互兼容,它们只要支持相同的 Profile 即可。一个蓝牙设备可以支持多个 Profile。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 2 Service 可以理解为蓝牙设备提供的服务,一个设备可以提供多个服务,比如电量信息服务、系统信息服务等。每个 Service 又包含多个 Characteristic 特性值,比如电量信息服务就会有个 Characteristic 表示电量数据,同时还会有一个 16bit 或 128bit 的 UUID 唯一标识该服务,像微信硬件平台的蓝牙智能灯的主服务 UUID 为 0xFEE7。16 bit 的 UUID 实际上是 128 bit 的缩短版,接收方收到后会补上蓝牙的 UUID 基数,目的是为了提高传输效率。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 3 Characteristic 是在 GATT 规范中最小的逻辑数据单元,由一个 value 和多个描述特性的 Desciptor 组成。实际上,在与蓝牙设备打交道,主要就是通过读写 Characteristic 的 value 完成。同样的,Characteristic 也是通过一个 16bit 或 128bit 的 UUID 唯一标识。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 总结一下,如下图所示,我们可以简单地理解为:每个蓝牙设备可能提供多个 Service,每个 Service 可能有多个 Characteristic,我们根据蓝牙设备的协议用对应的 Characteristic 进行读写即可达到与其通信的目的。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> [图片] br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 在理解了上面的模式和概念后,接下来我们看看如何可以使用小程序提供的蓝牙接口。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> Step 1 :扫描并发现蓝牙外围设备 扫描并发现蓝牙外设。如果蓝牙功能未开启,可监听蓝牙状态变化以便自动进入下一步,提升用户体验。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> [图片] br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> Step 2 :连接蓝牙外围设备 若之前连接过某个设备,可跳过扫描步骤,直接传入 deviceId 连接。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> [图片] br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> Step 3 :查找蓝牙外围设备的服务 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> [图片] br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> Step 4 : 读写指定服务的特性值 [图片] br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 基本上,小程序暴露出来的蓝牙接口都是系统级 API ,但在使用流程上对安卓和 iOS 两个平台做了统一,因此在使用这一套接口时也会出现一些因系统限制而导致的问题,在这里我们整理了一些常见的问题供开发者参考: br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 1 在安卓上,部分机型无定位权限或者是定位开关未打开时会搜不到设备。原因是蓝牙功能是可以获取到定位的,系统基于安全考量,使用蓝牙接口时必须要有定位权限,否则搜索不到; br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 2 在安卓上,部分机型获取设备服务时会多出 00001800 和 00001801 UUID 的服务,这是系统行为,注意不要使用这两个服务; br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 3 建立连接和关闭连接必须要成对调用。如果未能及时关闭连接释放资源,容易导致 state 133 GATT ERROR的异常; br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 4 与蓝牙设备通信的 MTU(最大传输单元)系统限定为 20 字节,如果超过则会出错,这里应该根据蓝牙设备协议进行分片传输。 br ="" class="" style="max-width: 100%; box-sizing: border-box; word-wrap: break-word !important;"> 更多有关小程序连接蓝牙功能的信息,可查阅[接口文档]。
2018-08-17 - 公众平台/小程序服务端API的access_token的内部设计
一、背景 对于使用过公众平台的API功能的开发者来说,access_token绝对不会陌生,它就像一个打开家门的钥匙,只要拿着它,就能使用公众平台绝大部分的API功能。因此,对于开发者而言,access_token的使用方式就变得尤其的重要。在日常API接口的运营中,经常遇到各种的疑问:为什么我的access_token突然非法了?为什么刚刚拿到的access_token,用了10min就过期了?对于这些疑问,我们提供出access_token的设计方案,便于开发者对access_token使用方式上的理解。 对于access_token的获取,可以参考公众平台的官方文档:auth.getAccessToken、获取Access token 二、access_token的内部设计 2.1 access_token的时效性 众所周知,access_token是通过appid和appsecret来生成的。内部设计的步骤如下: (1)开发者通过https请求方式: GET https://API.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,传入appid及apppsecret的参数 (2)公众平台后台会校验appid和哈希(appsecret)是否与存储匹配,若匹配,结合当前时间戳,生成新的access_token。 (3)生成新的access_token的同时,会对老的access_token的过期时间戳更新为当前时间戳。 (4)返回新的access_token给开发者。 这里以图示的方式说明一下,新旧token交替过程: [图片] 从上图需要注意的几点: (1)公众平台存储层只会存储新老两个access_token,意味着假设开发者重复调用3次接口,则会导致最早的access_token立刻失效。 (2)虽然请求新的access_token后,老的access_token过期时间会更新为当前时间,但也不会立刻失效,原理请参考 【2.2 access_token 的逐渐失效性】 (3)出于信息安全考虑,公众平台并不会明文存储appsecret,仅存储appid以及appsecret的哈希值。因此开发者要妥善保管appsecret。当appsecret疑似泄露时,需要及时登录mp.weixin.qq.com重置appsecret。 2.2 access_token 的逐渐失效性 从【access_token的时效性】了解到,当开发者请求获取新的access_token时,老的access_token过期时间会被更新为当前时间,但此时不会立刻失效,因为公众平台会提供【5分钟的新老access_token交替缓冲时间】,因此也称为access_token 的逐渐失效性。 实现的原理是: 1. 由于老的access_token过期时间戳已被刷新,所以在API接口请求期间,带上的access_token解开后,过期时间戳会加上5分钟,然后和当前设备时间进行比对,若超过当前设备时间,判断为失效。 2. 公众平台的设备会保持时钟同步,但设备之间仍然可能会存在1-2分钟的时间差异,所以【5分钟】并非绝对的时间值。当开发者获取到新的access_token后应该尽快切换到新的access_token。 [图片] 从上图需要注意的几点: (1)由于存在设备时间同步的差异,可能会导致开发者遇到拿着老的access_token请求API接口,部分请求成功,部分请求失败的情况,建议开发者获取到新的access_token后尽快使用。 (2)通过理解两个图示,对开发者来说,access_token是相当关键且不能乱调的接口,建议开发者统一管理access_token,以免造成多次请求导致access_token失效。
2021-05-11 - 订阅信息恶心至极?没有服务器的我们也能直接发消息到微信(公众号)! [即抄即用,拎包入住]
更新时间(2020/12/2) 大家好,众所周知,今年左右新出的订阅消息对商家和用户的友好度都极低,少了一个直接发信息到微信的最重要的渠道。 [图片] 那么我们动动歪心思,直接发消息到公众号(其实这是不是wx的本意???)。 所有服务号都可以在功能->添加功能插件处看到申请模板消息功能的入口,但只有认证后的服务号才可以申请模板消息的使用权限并获得该权限。 为方便公众号用户方便、快捷地接入小程序服务,公众号用户可复用公众号资质创建小程序。当前每个账号的模板消息的日调用上限为10万次,单个模板没有特殊限制。当账号粉丝数超过10W/100W/1000W时,模板消息的日调用上限会相应提升。这还不美滋滋吗,对于小商家来说等于无限次了。 所以我们一开始最好就在公众号进行微信认证,复用公众号的资质来注册小程序(注意,可以复用5个(好像))。 (我付出了¥300的惨痛代价)。 -------------------------------------------------------------------------------- 以上搞定后,流程走起 重点中的重点:为您的函数申请公网固定ip 有了这个ip之后,没有服务器的我们(穷)就能绕过ip白名单,这不正是真正的云开发精神吗? [图片] 0.用你的小程序账号登陆腾讯云,并在里面新建一个云函数 [图片]>>[图片] 选择你要发消息到公众号的小程序 [图片] [图片] -----------------我是2020/10/23的拎包哥----------------------- 创建并选择角色 记得在 https://console.cloud.tencent.com/cam/role 创建角色 [图片] 勾选tcb,scf [图片] 在搜索框里搜scf,tcb后,有什么策略就勾选什么策略 [图片] [图片] 创建角色名 [图片] 在云函数启用刚刚新建的角色 [图片] ps. 记得做好这一步,不然各种报错 missing authorationo key // 报错:缺失授权键 you are not authorized to xxx // 你没有权限去xxx 1.打开 https://cloud.tencent.com/document/product/583/38198 ,申请白名单 [图片] 2.审核通过后,再跟着步骤走。 [图片] 最后你的云函数会得到一个公网固定ip [图片] 3.开始码云函数的代码 如下,记得把wx-server-sdk和request-promise的包都npm下来。 依赖包可以通过这里上传上来 [图片] 我的做法 把获取的accessToken储存在云开发的数据库里。这样就不用担心access token的生成次数超过限制了 'use strict'; const cloud = require('wx-server-sdk') cloud.init() const db = cloud.database() const resInfo = db.collection('resInfo') const appid = '公众号的APPID'; // APPID const secret = '公众号的密钥'; // Secret const rp = require('request-promise') exports.main_handler = async (event, context, callback) => { var that = this var options = { url: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + appid + '&secret=' + secret, json: true } return await rp(options) .then(async res1 => { return await resInfo.where({name:'outInfo'}).update({ data: { access_token: res1.access_token } }).then(res2 => { return res2 }) }).catch(err => { return err }) } 公众平台以access_token为接口调用凭据,来调用接口,所有接口的调用需要先获取access_token,access_token在2小时内有效,过期需要重新获取,但1天内获取次数有限,开发者需自行存储,详见获取接口调用凭据(access_token)文档。4.设置触发器(触发器偶尔会失灵,所以最好是59min触发一次)。 [图片] 权限设置 由于云函数的访问不存在openid,所以安全规则必须为任何人可读可写。 [图片] 5.有了可以稳定刷新的access_token后,根据需求挑选你的公众号模板消息,开始你的表演。 例如:做餐饮小程序的朋友都想用户下单后发送订单信息到商户。那么就需要 获取商户的openid 步骤 注:公众号的openid在小程序开发工具就可以查出来 5.1 获取公众号openid列表 https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN 注意我没有加上next_openid = NEXT_OPENID,是为了取出公众号的所有的openidopenid列表在 res.data.openid5.2 for循环openid列表,根据商户的微信信息(nickname,city等等)找出只属于商户的openid https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN --------------------------------------- var openidList = openid列表 for(var i in openidList){ wx.request({ url:'https://api.weixin.qq.com/cgi-bin/user/info?access_token='+ openList[i] + '&lang=zh_CN', success(){ console.log(....) } }) } 这里就不用unionid了,不用浪费时间在上面), 就可以使用只发给商户的模板消息了。 公众号对应文档链接 https://developers.weixin.qq.com/doc/offiaccount/User_Management/Getting_a_User_List.htmlhttps://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId, -----------------------------------------效果图--------------------------------------- [图片] -------------------------------------------------------------------------------- 哎,差不多了,感觉是有点折腾,如果感觉还是不够直白的,可以指出来我继续补充 。 求点赞,你的评论就是对拎包哥最大的支持。 [图片][图片] ===================更新于2020/10/23======================
2020-12-02