- 【简单高效】全面深度解析微信生态应用安全防护策略
作为开发者,最令我们头疼的可能并不是产品需求开发,而是在产品上线后出现的各种安全风险问题。 这些年,我们收到很多开发者提供的真实案例: 投票功能,本来要提供公平公正的投票服务,结果因为有人雇佣水军刷赞,造成投票严重不公平;发放活动优惠券,本来是刺激用户活跃的好活动,好不容易申请了经费,结果被羊毛党用非法手段拿走了90%,变价买卖。信息发布应用,访问人数很少但是服务器压力很大,因为每天会收到几十个爬虫的千万次请求。 ......这些案例一次次的发生,让我们产生了思考,到底哪个环节出问题了? 风险在哪里? 用户在使用小程序或H5应用时,业务请求从客户端发起,经过网络链路,到服务端;然后服务端根据请求处理事项并返回相应的内容,这是一个正常预期内的过程。 这里的客户端、网络链路、服务端,每一个部分都会成为被攻击的对象。我们一个个来盘点: 1. 客户端 小程序本身有代码加密插件,可以对上传的小程序代码混淆加密,并且从小程序发送的请求有明显的特征,只要服务端对应配置可以识别这些特征,攻击者破解和伪造的难度是非常高的。 但从诸多案例中我们发现,大部分攻击者不会直接从源码中破解请求体,而是使用模拟器、群控及设备农场的方式,通过外部辅助脚本或物理外挂的形式来去攻击。 比如“跳一跳”小游戏,很多玩家为了拿高分,不是去搞小游戏代码包伪造请求,而是直接搬上摄像头识别,通过距离识别,停顿秒数的计算,物理触发屏幕完成刷高分的成就。(网络搜一搜跳一跳外挂,八仙过海各显神通) [图片] 一般来说群控设备的解法要比直接破解代码包去伪造请求隐蔽的多,如果我们开发者只做了简单的 header 特征的识别,是很难抓到群控设备发出的请求的,从特征看,这些就是正常的手机直接点击完成的。 2. 网络链路 从客户端到服务端,一定是要经过本地网络和运营商网络,运营商网络直接做攻击行为的可能性很小,绝大部分的网络链路攻击都来源于本地网络。 攻击者通过对你正常的请求域名进行DNS污染,或通过代理你的网络,对客户端发出的请求做劫持和重放等,来达到TA的目的。 比如,因为开发者的逻辑失误,导致一个游戏道具的领取接口没有做校验和限制,发一个请求就领取一个道具,那么攻击者可以直接通过在链路上劫持并重放接口请求来刷道具。 除此之外还有很多很多,一半以上的攻击者目的都是为了自身,而不是去偷他人的数据,因为主观能动性,本地网络的链路劫持基本都能轻松完成。 3. 服务端 服务端是最容易被攻击的,并且大部分的攻击行为都是绕开客户端和网络链路(从客户端发来的链路),直接去搞服务端。这里列举一些常见的攻击手段: DDos攻击:分布式拒绝服务攻击,攻击者直接不择手段想把你的服务器打挂掉,从而影响你的正常业务。CC攻击:人海攻击手段,通过绑架大量肉鸡或者号召一大波人,直接把你服务端挤爆,让你无法服务正常的用户。BOT攻击:一般不会对你的服务器造成影响,只是通过后端接口缺陷,批量自动化获取你的业务信息,或者定时来获取你的信息,有部分是爬虫。黑客攻击手段:比如SQL注入、0day漏洞、加密凭证破解、网络阻塞攻击等,这些就不是用户抢道具这种的目标行为,而是有预谋的直接攻击你的基建。应该如何防范? 针对不同层面的攻击,我们应该有不同的防范方法,在这里我们给开发者整理了一些有效的方法: 1. 客户端 应用中尽量使用代码保护插件,对小程序代码进行混淆和加密,增加逆向工程的难度。应用中设置合理的操作频率限制和阈值警报,比如在页面打开后不允许立刻点击按钮,按钮加上防抖和节流。实现基于时间或挑战-响应的动态令牌机制,防止请求重放攻击。结合多维度信息(如硬件ID、网络特征、行为模式等)生成唯一标识,识别和追踪异常设备行为。接入用户行为分析监听,检测异常操作模式;比如跳一跳长时间有节奏的操作停顿,点击位置无变化,可以判定物理外挂。2. 网络链路 小程序强制使用HTTPS协议,但在其他客户端也应全面采用HTTPS协议,防止中间人攻击和数据窃听;另外有条件可以采取证书固定,防止SSL劫持。有能力的话,对每个请求进行签名,包含时间戳、nonce 等信息,服务端验证签名有效性。有条件可以进行双向认证,服务端也要对客户端证书做认证,确保通信双方身份。扩展使用 DNSSEC 或 HTTP-DNS 技术,防止DNS污染。3. 服务端 使用专业的DDoS防护服务器,实现流量清洗和智能负载均衡;另外应用层面要基于IP或者用户openid做访问频率限制。使用验证码或其他人机交互验证来辅助判断,比如关键接口滑动验证,或使用短信验证码确认。API层面要做细粒度的接口权限控制,对敏感接口应该有更严格的认证和授权机制。引入一些BOT检测机制,通过特征标记来识别和阻止自动化脚本;配合动态黑名单系统,自动封禁异常IP。部署WAF,防御常见的Web攻击,如SQL注入、XSS等;另外对服务器和后端服务软件的安全更新和补丁要及时处理。使用API网关,集中管理和监控API调用,将多个服务受攻击面缩减到一个,集中精力防护。 通过实现上述手段,我们能阻止绝大部分的安全攻击,但也对各位开发者提出了更高的要求;如果因为自身理解或者配置不当,很有可能会遗漏一些重要的点,造成防护失效,对业务服务造成损失。 那么有没有什么方法,能够让开发者简单操作就能实现上述所有防护手段,从而高效的处理的自己的业务开发呢? 微信做了什么? 微信官方团队,在去年就推出了集API网关、网络加速、请求加密、安全防护、流量管控于一体的「安全网关」,有一套完整的端到端的防护体系。从客户端到服务端,全面覆盖业务服务过程,为开发者提供简单、高效的保护和治理。 [图片] 「安全网关」的防护能力分链路层面、客户端层面、服务端层面,我们分别来看下几个层面的防护特点。 在链路层面上,实现了三层防护 第一层:请求进入网关的微信私有协议时,可以精准识别协议外挂、爬虫特征、模拟器攻击、黑灰产IP、DDos和CC攻击等各种异常请求,并及时拦截。第二层:经过第一层的初步清洗,在这一层会对伪造、篡改协议的请求进行清洗;同时结合用户请求频率、权限校验等风控能力拦截掉非法请求、越权请求、高频请求等;前两层的清洗已经拦截90%的异常流量,将剩余正常流量转发给业务源站。第三层:为了防止漏网之鱼,开发者可以选择接入第三层,网关会结合请求特征、设备信息、账号信息形成多维智能分析模型,对请求进行风险的判别,并将判别结果一同提交给业务源站,开发者可以参照或结合自己的数据,综合判断请求的合法性。开发者也可以授权网关直接对高风险的请求直接拦截,不转发给业务源站。在客户端层面,请求加密和风险识别 「安全网关」提供微信私有协议,二次封装,100%加密数据和接口,全程无明文数据传输,极大的提高外部抓包破解门槛。 并且「安全网关」支持在小程序、WEB、H5、APP等多端场景接入。尤其在微信小程序中,平台能在 wx.request 中直接转发请求到网关安全链路,无需开发者改代码;支持一键断连,恢复为普通请求链路。 [图片] 风险识别上,「安全网关」在微信小程序中推出「安全检测插件」,插件会根据设备环境、网络环境、用户行为、账号风险等多维度综合判断当前运行环境的可信情况,给出判断结果;开发者接入后可以在敏感业务前调用检测,检测通过才进行业务请求。 该扩展插件可以帮助开发者拦截群控、模拟器、设备农场等端场景的攻击行为,极大降低了游戏刷高分,集赞水军,自动羊毛党对正常业务的影响。 服务端层面提供信任参考 「安全网关」之所以称之为网关,是因为TA代理了所有客户端发送的请求,集中转发到开发者业务服务器中。在这个集中处理的过程中,实现了加密、加速、安全防护等多个效果。 作为服务端的开发者,我们在接入「安全网关」后,可以充分利用网关转发请求的附加信息,比如请求来源小程序appid、用户openid、用户unionid、用户风险标识等等,根据这些网关标记结合自身业务需求予以处理。 你可以在服务端对「安全网关」转发流量以外的其他流量设置限制访问,只接受「安全网关」的IP发过来的请求,将自己服务器隐藏在安全网关后面,更加安全;也可以设置其他更丰富化的防护策略,一切自由决定。 [图片] 如何接入安全网关? 目前网关控制台(请在 PC 端访问:https://dev.weixin.qq.com/console/gateway )已支持自助接入。 我们针对微信小程序提供一键接入方式,你可以无需任何代码改动和版本发布就可以体验。支持全量、URL灰度、用户灰度等策略,体验出现问题也支持一键断连。 针对其他客户端,如WEB、H5、PC端场景,也提供手动接入方案。 我们还推出了系列视频课程,全面讲解「安全网关」的各方面使用细节,让开发者上手更容易:微信网关系列课程 如果你有企业级版本(预期 >1000 QPS)的接入需求,请邮件联系我们专业对接:donut@tencent.com
09-03 - 云模版初体验:小程序从 0 开始接入一个 AI 智能体
引言 在今年 4 月份的 Create 2024 百度 AI 开发者大会上,李彦宏介绍了百度的智能体开发工具 AgentBuilder,他表示:“智能体可能是未来离每个人最近、最主流的大模型使用方式,基于强大的基础模型,智能体可以批量生成,应用在各种各样的场景。百度刚刚升级了文心智能体平台。截至目前,已经有 3 万多个智能体被创建、5 万多名开发者和上万家企业入驻。我们的目标是,让每个人、每个组织都成为智能体的开发者,打造国内最完整的智能体生态。” 云开发的 AI 智能体应用平台大大降低了开发者接入大模型的难度,开发者可零代码安装一个智能体模板,支持发布到小程序、H5、微信客服、微信订阅号、微信服务号多个场景。并且支持编辑提示词训练一个专属自己的智能体。 下面就来体验一下。 安装智能体 1、 新注册一个小程序 2、点击云开发,需要开通云开发环境,首月免费。 [图片] 3、点击云模板,然后点击去使用,会进入到云模板控制台,然后进入模板中心。 [图片] 4、进入AI 智能体,点击安装。耐心等待…… 等待安装完成后,进入我的应用,即能看到自己已经安装的模板。 [图片] 5、进入 AI 智能体详情,能看到详细的集成文档。点击预览模拟效果就能先睹为快。 [图片] 6、点发现智能体,能看到默认加载的几个智能体。点击访问预览链接,能够在网页端体验智能体的效果。 [图片] 发布智能体到小程序 安装完 AI 智能体之后就可以发布到小程序了,这时候发布的即是默认加载的几个智能体。 1、点击添加至多平台,以子包的形式发布到小程序。点击添加至小程序,会生成添加方案。这里我目测根据小程序的结构不同,方案会不同,所以建议每次发布都重新生成一下方案,不要把其他小程序的方案复制过来直接使用。 [图片] [图片] 2、方案中提供了 javascript 添加或者 wxml 添加两种,根据自己的喜好即可。 编译小程序预览一下,集成成功了。 [图片] 小程序上线 在 AI 智能体使用须知这一章节中,文档中明确写明: 在发布 AI 智能体到小程序时,微信将在代码审核阶段核实小程序运营的内容与所选类目是否相符。AI 问答涉及深度合成技术,需补充【深度合成-AI 问答】服务类目。 目前,个人主体小程序尚未开放深度合成相关服务类目,建议申请企业主体类型小程序。 对于个人客户,考虑到类目限制,建议使用 H5 或公众号(订阅号/服务号均可)等其他方式实现 AI 智能体的功能。 所以只能是企业主体去申请小程序,并提供相关资料。 [图片] [图片] 搭建自定义智能体 如果想根据自己的业务场景搭建一个自定义的智能体,管理后台提供了便捷的操作方法。 1、从 AI 智能体详情中点击服务管理模块,在管理后台中点击访问,会从浏览器端打开管理后台。 [图片] 2、在管理后台中,可以选择1 分钟创建智能体或者从模板创建。 [图片] 3、在人设与回复逻辑当中输入自定义的提示词,即可训练一个专属自己的智能体。 [图片] 4、自定义成功后即可和默认智能体一样的流程上线到小程序。 上线成功,来体验一下吧 [图片]
06-25 - 小程序页面加水印,防止用户截图分享隐私数据
为了防止用户将小程序内的隐私数据进行截图或者录屏分享导致信息泄露,我们会在小程序全局添加一个水印浮层。这样即使被截图或者拍照,也能轻松地确定泄露的源头。 小程序防止用户截屏的方法有很多,其中一种常见的方法就是在小程序的页面中添加水印。具体实现方法如下: 在小程序中的页面中添加水印浮层,一般通过绝对定位来实现,这样可以使水印在页面的最上层,无法被其他元素覆盖。设计水印的样式和位置,通常可以在小程序的样式文件中设置,例如设置水印的位置为右下角,样式为半透明的字体,以免影响正常的内容展示。对于不同类型的页面,可以根据需要添加不同的水印,例如在敏感信息页面添加比较醒目的水印,而在其他普通页面只添加轻微的水印。如果需要防止用户截屏或者拍照,可以在小程序中添加截屏监听事件,并在用户进行截屏或者拍照操作时,自动添加水印。 总的来说,小程序防止用户截屏的方法还有很多,例如使用安全键盘等,但是添加水印仍然是最为常见的一种方法。通过添加水印,可以有效地防止用户截屏和分享敏感信息,保护用户和单位的信息安全。 下面是一个简单的示例,position选择固定定位fixed,固定定位会固定在浏览器窗口某个位置,不会随滚动条滚动。用z-index将元素的层级设置为最低,将view旋转45度,效果就出来啦 [图片] <view style="position: fixed;top: -10vh; left:-100vw;width: 250vw; height: 100vh; z-index: -999;transform: rotate(-45deg);"> <block wx:for="{{30}}" wx:key="index" wx:if="{{userInfo}}"> <view style="color:gray; margin:30rpx; padding:20rpx; opacity: 0.15;"> {{userInfo.user_name + ' ' + userInfo.user_phone}} {{userInfo.user_name + ' ' + userInfo.user_phone}} {{userInfo.user_name + ' ' + userInfo.user_phone}} {{userInfo.user_name + ' ' + userInfo.user_phone}} </view> </block> </view>
2023-02-23 - setData动态key的使用以及使用建议
相信每个小程序开发者用的最多的函数非setData莫属,setData是小程序开发中使用最频繁、也是最容易引发性能问题的接口。 本篇内容主要讲小程序setData的用法、注意事项、使用建议以及动态key的写法。 setData介绍 Page.prototype.setData(Object data, Function callback) [代码]setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。 [代码] 字段 类型 必填 描述 最低版本 data Object 是 这次要改变的数据 callback Function 否 setData引起的界面更新渲染完毕后的回调函数 1.5.0 Object 以 key: value 的形式表示,将 this.data 中的 key 对应的值改变成 value。 注意事项 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。 仅支持设置可 JSON 化的数据。 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。 请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题。 示例代码: 在开发者工具中预览效果 使用建议 1. data 应只包括渲染相关的数据 setData 应只用来进行渲染相关的数据更新。用 setData 的方式更新渲染无关的字段,会触发额外的渲染流程,或者增加传输的数据量,影响渲染耗时。 ✅ 页面或组件的 d- ata 字段,应用来存放和页面或组件渲染相关的数据(即直接在 wxml 中出现的字段); ✅ 页面或组件渲染间接相关的数据可以设置为「纯数据字段」,可以使用 setData 设置并使用 observers 监听变化; ✅ 页面或组件渲染无关的数据,应挂在非 data 的字段下,如 this.userData = {userId: ‘xxx’}; ❌ 避免在 data 中包含渲染无关的业务数据; ❌ 避免使用 data 在页面或组件方法间进行数据共享; ❌ 避免滥用 纯数据字段 来保存可以使用非 data 字段保存的数据。 2. 控制 setData 的频率 每次 setData 都会触发逻辑层虚拟 DOM 树的遍历和更新,也可能会导致触发一次完整的页面渲染流程。过于频繁(毫秒级)的调用 setData,会导致以下后果: 逻辑层 JS 线程持续繁忙,无法正常响应用户操作的事件,也无法正常完成页面切换; 视图层 JS 线程持续处于忙碌状态,逻辑层 -> 视图层通信耗时上升,视图层收到消息的延时较高,渲染出现明显延迟; 视图层无法及时响应用户操作,用户滑动页面时感到明显卡顿,操作反馈延迟,用户操作事件无法及时传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层。 因此,开发者在调用 setData 时要注意: ✅ 仅在需要进行页面内容更新时调用 setData; ✅ 对连续的 setData 调用尽可能的进行合并; ❌ 避免不必要的 setData; ❌ 避免以过高的频率持续调用 setData,例如毫秒级的倒计时; ❌ 避免在 onPageScroll 回调中每次都调用 setData。 3.setData 应只传发生变化的数据 setData 的数据量会影响数据拷贝和数据通讯的耗时,增加页面更新的开销,造成页面更新延迟。 ✅ setData 应只传入发生变化的字段; ✅ 建议以数据路径形式改变数组中的某一项或对象的某个属性,如 This.Setdata({‘Array[2].Message’: ‘Newval’, ‘A.B.C.D’: ‘Newval’}),而不是每次都更新整个对象或数组; ❌ 不要在 setData 中偷懒一次性传所有data:this.setData(this.data)。 修改数组动态key的写法以及修改对象的某个属性 在开发者工具中预览效果 动态修改数组的某个元素 用一个中括号修饰表达式即可 [代码]clickItem(e){ let item = e.currentTarget.dataset.item let index = e.currentTarget.dataset.index // 第一种 可以只改某个数组的元素 // item.selected =!this.data.list[index].selected // this.setData({ // ['list['+ index + ']']: item // }) //第二种 也可以直接修改某个数组的某个属性 this.setData({ ['list['+ index + '].selected']: !this.data.list[index].selected }) }, [代码] 以数据路径形式改变数组中的某一项或对象的某个属性 [代码]clickObject(e){ this.setData({ 'user.clickNum': this.data.user.clickNum + 1 }) }, [代码] 更多内容可以仔细查看官方文档: setData 函数详解(在文档的底部) 合理使用 setData
2023-04-24 - 小程序利用云开发实现图片安全检测(imgSecCheck,msgSecCheck)
最近在做一款拍照的小程序,审核时被拒绝,需要增加云安全检测,使用的方法流程是,小程序使用云上传,云平台下载图片在云检测,将检测结果返回给小程序,小程序通过结果来判断是否安全 // 小程序端 // 主方法 handleCamera: function () { let that = this this.selectImg().then(fileImg => { wx.showLoading({ title: '分析中', mask: true }) wx.cloud.uploadFile({ cloudPath, filePath: fileImg, success(res) { wx.cloud.callFunction({ name: "imgSecCheck", data: { fileID: res.fileID } }).then(res => { if (res.result.errCode !== 0) { wx.showToast({ title: '违规图片,请重新上传', icon: 'none' }) } else { wx.hideLoading() that.jumptoresult() } }).catch(err => { wx.showToast({ title: '违规图片,请重新上传', icon: 'none' }) console.log(err) }) }, fail(err) { console.log(err) wx.showToast({ title: '上传失败', icon: 'none' }) } }); }) }, // 选择图片 selectImg: function () { if(!this.data.isShowAdv){ return } let that = this return new Promise((resolve, reject) => { wx.chooseImage({ count: 1, sizeType: ["compressed"], sourceType: ["camera", "album"], success: function (chooseFile) { that.setData({ imagex: chooseFile.tempFiles[0].path, }) resolve(chooseFile.tempFilePaths[0]) }, }) }) } // 云开发端 // 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init() // 云函数入口函数 exports.main = async(event, context) => { const fileID = event.fileID const res = await cloud.downloadFile({ fileID: fileID, }) const buffer = res.fileContent try { var result = await cloud.openapi.security.imgSecCheck({ media: { contentType: 'image/png', value: buffer } }); return result } catch (err) { return err } } 试了一些其它方案没走下去,我列举下大家可以参考 1、用户拍完照使用云安全检测报错提示 data maxsize 等等 因为云安全检测的大小限制为1M 我们手机多数拍出来都比较大,所以更换了文中那种方案 2、使用canvas画图把图片搞小,然后在安全检测 失败告终,图片小了可以上传,但安全检测也识别不出来了 还有一个云文本安全检测,用法同云安全图片比图片还简单一些,大家改改就行,需要帮助也可以私聊我 下面是成品,可扫码测试 [图片]
2021-10-07 - 微信小程序的UnionID详解和使用场景
什么是UnionID ?(UnionID机制说明) 首先来看官方的定义: 如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 UnionID 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 UnionID 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,UnionID是相同的。(官方关于unionid原文档链接) 举个场景栗子:如果你有一个小程序A、一个小程序B、一个微信公众号【发发发】,并且将它们绑定到同一个微信开放平台账号下面。当微信号zhangsan666的用户进入到小程序A或者小程序B或者公众号发发发的时候,获取到的unionid是相同的。这样就可以根据unionid查询到当前微信用户在当前开放平台下的每个小程序或公众号里边的数据。对A小程序和B小程序和公众号的数据互通,提供了极大的便利。 UnionID获取途径 绑定了微信开放平台的小程序,可以通过以下途径获取 UnionID。 开发者可以直接通过 wx.login + [代码]code2Session[代码] 获取到该用户 UnionID,无须用户授权。小程序端调用云函数时,可在云函数中通过 Cloud.getWXContext 获取 UnionID。用户在小程序(暂不支持小游戏)中支付完成后,开发者可以直接通过[代码]getPaidUnionId[代码]接口获取该用户的 UnionID,无需用户授权。注意:本接口仅在用户支付完成后的5分钟内有效,请开发者妥善处理。 一般采用第一种途径获取用户的unionid,简单方便,在获取用户openid的同时,直接添加两个字段保存用户的session_key和unionid 微信开放平台的注册及绑定小程序、公众号... 如果想使用unionid,首先要注册微信开放平台,并且花300大洋进行开发者资质认证。微信开放平台访问地址: https://open.weixin.qq.com/ 认证通过后在 管理中心 — 小程序 — 绑定小程序 [图片] [图片] 如果感觉文章对你有帮助,请点个赞吧
2023-03-13 - 小程序app.onLaunch与page.onLoad异步问题的最佳实践
场景: 在小程序中大家应该都有这样的场景,在onLaunch里用wx.login静默登录拿到code,再用code去发送请求获取token、用户信息等,整个过程都是异步的,然后我们在业务页面里onLoad去用的时候异步请求还没回来,导致没拿到想要的数据,以往要么监听是否拿到,要么自己封装一套回调,总之都挺麻烦,每个页面都要写一堆无关当前页面的逻辑。 直接上终极解决方案,公司内部已接入两年很稳定: 1.可完美解决异步问题 2.不污染原生生命周期,与onLoad等钩子共存 3.使用方便 4.可灵活定制异步钩子 5.采用监听模式实现,接入无需修改以前相关逻辑 6.支持各种小程序和vue架构 。。。 //为了简洁明了的展示使用场景,以下有部分是伪代码,请勿直接粘贴使用,具体使用代码看Github文档 //app.js //globalData提出来声明 let globalData = { // 是否已拿到token token: '', // 用户信息 userInfo: { userId: '', head: '' } } //注册自定义钩子 import CustomHook from 'spa-custom-hooks'; CustomHook.install({ 'Login':{ name:'Login', watchKey: 'token', onUpdate(token){ //有token则触发此钩子 return !!token; } }, 'User':{ name:'User', watchKey: 'userInfo', onUpdate(user){ //获取到userinfo里的userId则触发此钩子 return !!user.userId; } } }, globalData) // 正常走初始化逻辑 App({ globalData, onLaunch() { //发起异步登录拿token login((token)=>{ this.globalData.token = token //使用token拿用户信息 getUser((user)=>{ this.globalData.user = user }) }) } }) //关键点来了 //Page.js,业务页面使用 Page({ onLoadLogin() { //拿到token啦,可以使用token发起请求了 const token = getApp().globalData.token }, onLoadUser() { //拿到用户信息啦 const userInfo = getApp().globalData.userInfo }, onReadyUser() { //页面初次渲染完毕 && 拿到用户信息,可以把头像渲染在canvas上面啦 const userInfo = getApp().globalData.userInfo // 获取canvas上下文 const ctx = getCanvasContext2d() ctx.drawImage(userInfo.head,0,0,100,100) }, onShowUser() { //页面每次显示 && 拿到用户信息,我要在页面每次显示的时候根据userInfo走不同的逻辑 const userInfo = getApp().globalData.userInfo switch(userInfo.sex){ case 0: // 走女生逻辑 break case 1: // 走男生逻辑 break } } }) 具体文档和Demo见↓ Github:https://github.com/1977474741/spa-custom-hooks 祝大家用的愉快,记得star哦
2023-04-23 - 微信红包封面定制个人学习总结
一、创建账号目前有两条注册路线,分别是个人和企业。 个人:需先开通微信视频号并获得有效粉丝数100个,然后申请封面定制平台账号,用视频号管理员验证完成注册。 *有效粉丝数,个人猜测应该是系统按特定规则计算,会排除刷粉等异常数据,规则不会对外公开。 [图片] 企业:需注册公众号,并进行微信认证,然后申请封面定制平台账号,用公众号管理员验证完成注册。 [图片] *目前仅面向大陆境内的认证企业公众号,或已完成视频号认证的个人用户开放。 *且暂不对宗教、烟草、医疗、特殊医学用途配方食品、医疗器械、农药、兽药、保健食品及药品相关的主体开放。 二、封面定制个人定制:定制页面如下, [图片] [图片] 1,红包封面简称最多8个字,可以使用视频号名称,或自行命名。注意起名也需要提供相关证明材料。 2,个人LOGO支持PNG、JPG,尺寸是200*200像素,文件小于100KB。 虽然可以直接使用视频号头像,但如果你视频号头像图片是网图,也会管你索要版权证明的。 建议不使用LOGO,直接文字命名。 3,样式(即封面图片)封面图片直接使用一张图片即可,红包各个阶段的页面,都是从这一张图片中截取。 支持PNG、JPG,尺寸是957*1278像素,文件小于500KB。 注意第1张示例图底部的“开”字部分,会遮挡图片下面一部分内容。 第2张示例图,实际效果是可以下拉的,需要考虑下拉后的顶部显示内容,如果不合适还可以单独调整封面图上传。 第3张示例图、第4张示例图,可以直接编辑选择显示位置。 4,封面故事在红包打开后的红包详情页展示,该页下拉时,直接以图片或视频方式展示封面故事。 图片和视频,最多可设置5个,左右滑动观看效果。 图片支持PNG、JPG,尺寸是750*1250像素,文件小于300K。 视频支持MP4格式,编码是H.264/AVC,宽度≥720像素,宽高比是3:5-16:9之间,小于15秒时长,码率不高于1600kbit/s,文件小于10M。 同时支持用视频号上传素材。 故事的文字描述不得超过40个汉字。 个人号,支持跳转到视频号或表情封面; 暂时个人号没有跳转公众号或小程序的链接。 5,证明材料整个设计中,出现的名称、LOGO、图片等美术作品,以及涉及人像、字体等,都需要提供相关权属证明文件,以证明你有资格使用这些内容。 *涉及注册商标的,需提供《商标注册证》的扫描件或商标使用授权书(在授权情况下); *美术作品涉及著作权的,需提供《作品登记证书》或《著作权登记证书》的扫描件;没有证书的,需提供该作品的psd格式文件,或人民法院确认权属的法律文书,或其他能证明作品权利人的发表链接等; *涉及肖像权的,需提供图中人物的身份证明,如身份证正反面或护照等扫描件或照片;或提供肖像权授权书。其中授权人为图中涉及肖像的人,被授权人为微信红包封面开放平台注册者; *涉及版权的,需提供作品版权证明,如著作权登记证、作品登记证;或版权授权书,其中授权人为版权所有者,被授权人是微信红包封面开放平台注册者; 以及版权所有者主体证明,企业请提交合法营业执照电子版扫描件或照片,个人请提交身份证正反面或护照等身份证明扫描件或照片; 没有上述证书,需提供该作品的psd格式文件,或人民法院确认权属的法律文书,或其他能证明作品权利人的发表链接等; 如果涉及资料文件较多,可打包上传。文件需小于25M(实际定制页面目前写的是小于80M); 如果证明材料过大,可以写邮件发往wxcover_support@tencent.com(邮件名为【证明材料补充】+封面名称),并在提交审核时在「证明材料」处上传说明文档,列明发至邮箱的证明材料所包括的内容。 6,手机预览填完资料的封面,可以点击底部的“手机预览”按钮,手机扫描弹出的二维码,在手机上预览红包封面效果。 企业定制:和个人封面定制大体流程一致,只是在封面故事部分增加了小程序或公众号的跳转。 [图片] *可以关联企业主体下的小程序或公众号,其中小程序可以设置指定界面路径跳转。 三、封面审核1,审核周期原审核周期是1个工作日,后改为从1月2日起,至2021年2月26日,审核周期调整为3个工作日。 并且对特定情形的封面定制,会延长审核周期为1个月。 特定情形:(1)封面中存在外文、少数民族语言文字内容的,需要提供完整、准确的中文翻译。 (2)封面中存在任何宗教、民族、政治性质的图腾、人物、神兽、符号、法器等元素的,需要提供该等元素的详细说明。 2,审核标准肯定以官方实际审核为准。 从官方公开的审核标准中,个人归纳如下: 综合标准:(1)不违法;(2)符合未成年人保护标准;(3)不违背社会善良风俗或各民族感情;(4)格调健康,积极向上;(5)不得过度营销;(6)不能直接使用中国地图(除非相关部门授权);(7)除党政和事业机关账号,其他不可使用政治军事以及其他主旋律推广内容;(8)不能使用全网封杀人物肖像 直接标准:(1)必须确保有权使用;(2)在先原则(不可与已发布封面雷同); 3,提审数量最多可同时在审3款红包封面,待审核完成后可继续提交。 四、封面购买TODO 五、封面发放TODO 六、封面违规与侵权处理从官方原始购买后,定制方不得以任何形式向用户售卖微信红包封面。 TODO 七、相关参考资料*微信红包封面开放平台-帮助中心 https://cover.weixin.qq.com/cgi-bin/mmcover-bin/readtemplate?t=page/index.html#/doc?page=introduce&index=-1 *封面审核周期调整公告 https://cover.weixin.qq.com/cgi-bin/mmcover-bin/readtemplate?t=page/index#/notice_detail?id=1609588007_3773_1102306322 ====================================== 附:常见审核驳回原因整理1,所提交的封面素材和他人已发布的作品存在较高相似度,侵权风险较大。请提供早于他人作品发布时间的作品版权证明。 2,红包封面的图案应尽量避开头像、昵称、祝福语的区域。若无法避开,需避免图案过于复杂,影响文字识别。 3,需补充提供【XXXX公司/网站】享有著作权的证明材料。(即使你有其他平台的版权授权书也不行,需要他们著作权证明) 4,所提供的《XX图片授权书》中被授权方为【张三】,无法体现被授权方与【张三视频号】视频号之间的关系。请提供授权范围包含【张三视频号】视频号之红包封面定制场景的授权书后,再上传系统进行审核。(授权书需要有身份证号或其他证明,能让官方确认是授权给你,只有名字不行) 5,所提交的封面素材涉及版权,需提供《作品登记证书》或《著作权登记证书》的扫描件、作品源文件等版权证明材料。 6,PSD文件需要详细分层。 7,红包封面简称仅可以使用主体名称中的字号、公众号名称或注册商标名称。如使用注册商标请上传《商标注册证》的扫描件。可使用【XXX】等命名。 8,所提交的封面素材涉及他人的作品,需提供以下材料:1)《作品登记证书》或《著作权登记证书》的扫描件、作品PSD源文件等版权证明材料; 2)版权授权书(企业需盖章);3)版权所有者是个人的,需提供身份证正反面或护照等扫描件。 9,不可出现除企业字号、商标名称、企业价值观、祝福语以外的文字。 10,红包封面的背景色不可与微信红包的文字色相接近,影响昵称、祝福语的识别。需更换背景色后再提交。 11,所提交的企业logo涉及他人的作品,需提供以下材料:1)《作品登记证书》或《著作权登记证书》的扫描件、作品PSD源文件等版权证明材料; 2)版权授权书(企业需盖章);3)版权所有者是个人的,需提供身份证正反面或护照等扫描件。 12,仅可使用定制主体法人代表的肖像定制封面,需提供企业营业执照、法人代表实名信息(需本人手持身份证拍照),且该等情形的微信红包封面,审核期限将延长至一个月。 13,封面素材不可展示微信红包的固有元素,如祝福语、“开”按钮、用户昵称头像、弧形阴影等,需删除后再提交。 14,所提交的作品创作源文件无法充分证明你享有该作品的著作权,请补充其他证明材料,如作品的《作品登记证书》或《著作权登记证书》的扫描件等。 15,不可出现和他人已发表的作品雷同,或权利归属情况不明的内容(如未获得著作人合法授权的二次创作、同人作品等)。 16,发红包页、红包消息气泡、拆红包页、红包详情页的素材图需属于原始封面样式图的一部分,保持内容、风格、主题一致。 17,品牌logo仅可以使用你的注册商标,且需上传《商标注册证》的扫描件。如使用其他主体的注册商标,需提供有效的授权证明材料。若未注册商标或未取得授权,可删除品牌logo后再提交。 18,证明材料未上传成功,请重新提交。若文件过大无法上传,请将证明材料发邮件至wxcover_support@tencent.com(邮件名为【证明材料补充】+封面名称),可在邮件中留下你的联系方式,我们将与你联系。 19,不可出现真实的人名和地址信息。 20,仅可使用定制主体本人的肖像定制封面,请提供本人实名信息(需本人手持身份证拍照),且该等情形的微信红包封面,审核期限将延长至一个月。 21,建议调整封面中祝福语文案的位置,以免影响在其他机型或者大字体情况下的体验效果。 22,红包封面简称可使用微信视频号账号名称。如果使用其他名称命名,请提供相应的证明材料。 23,请提供有效的版权证明材料。应注意,根据《“微信红包封面”定制功能使用条款》第3.3.3条的约定:定制方不得以任何形式向用户售卖微信红包封面。 24,非党政机关事业单位,不可使用天安门、人民大会堂、华表等国家民族标志物。 25,所提交的《作品登记书》证明材料,需将登记的作品复印件一起上传。 26,所提交的封面故事视频音乐作品和他人已发布的作品存在较高相似度,侵权风险较大。请提供早于他人作品发布时间的作品版权证明。 27,不可包含直接或间接表明产品或服务或其特性的文字。(包括封面故事图片) 28,所提交的封面素材涉及他人的作品,需提供版权授权书,其中被授权人为微信红包封面开放平台注册者。 29,不可出现商品图、店铺图、服务内容截图等广告性质的内容。 30,需提供有拍摄信息的照片源文件。 (不断更新中...欢迎提供!欢迎点赞支持!) ====================================== 重要事项更新日志: *2021.01.20 更新封面故事跳转内容,增加了视频号和表情封面跳转。 *2021.03.23 移除了个人主体必须视频号认证要求。
2021-03-23 - 微信小程序图表Demo(附上源码)
开源微信小程序图表Demo github地址 https://github.com/kesixin项目:WX-Graphic 线性图[图片] 滚动线性图[图片] 柱状图[图片] 扇形图[图片] 环形图[图片] 区域图[图片] 雷达图[图片] <!--index.wxml--> <view class="container"> <view bindtap="gotoPage" data-page="line" class="mt20 list-item">线性图</view> <view bindtap="gotoPage" data-page="scrollline" class="mt20 list-item">滚动线性图</view> <view bindtap="gotoPage" data-page="column" class="mt20 list-item">柱状图</view> <view bindtap="gotoPage" data-page="pie" class="mt20 list-item">扇形图</view> <view bindtap="gotoPage" data-page="ring" class="mt20 list-item">环形图</view> <view bindtap="gotoPage" data-page="area" class="mt20 list-item">区域图</view> <view bindtap="gotoPage" data-page="radar" class="mt20 list-item">雷达图</view> </view>
2020-07-03 - 微信开发者工具下载的 sourcemaps 怎么用。
什么是 Sourcemaps uglifyjs、bable 等工具会对 源代码 进行编译处理生成编译后的代码(下称目标代码),而 sourcemaps 就是保留了目标代码在源代码中的 位置信息 --------- 大神分割线 --------- 如何解读 Sourcemaps Sourcemaps 是一个 json [代码]{ "version": 3, "sources": ["a.js", "b.js"], // 源文件列表,这个表示是由 a.js 和 b.js 合并生成 "names": ["myFn", "test"], // 如果开启了变量名混淆,这里会保留变量名在源文件中名字信息 "sourcesContent: [], // 可选项,保存源码信息,顺序与 sources 字段对应,chrome 的 sources 面板中源码使用了这个字段的内容进行展示 "sourceRoot": "", // 源文件所在的目录信息 "file": "dist.js", // 可选,编译后的文件名 "mappings": "" // 这个是重点,是目标代码和源文件的位置的映射关系 } [代码] mappings 目标文件"行"的信息 mappings 是使用 ; 分隔的,每个部分对应目标代码的行 如: “;AAAA;AAAA,BBBB;;” 本例子目标文件有 4 行 第 0 行和第 3 行没有源文件对应信息,所以这两行是编译过程中加入的代码 目标文件的"列"信息 如: “AAAA,CAEA,CAEA;” ‘,’ 表示行内的位置信息分隔符 本例表示目标文件的这一行有三个有效的位置信息。 位置信息的第一位表示目标文件的列的 偏移 信息 本例中,表示列的信息是 ‘A’、‘C’、‘C’,对应的数字为 0、+1、+1,(vlq 编码,在线编解码工具) 注意,这个是偏移信息; 列数从 0 开始,依次累加偏移值可以算出当前的位置信息对应的真正的列 所以本例中表示的是目标文件的第 n 行中的第 0 列,第 1 列,第 2 列(没错是第 2 列) 源文件的信息 如:‘AAAA;ACAA;ADAA;’ 位置信息的第二位表示源文件的信息,本例子中是 ‘A’、‘C’、‘D’,对应数字是 0、+1、-1 如果 sourcemaps 中的 sources 字段只有一个文件的话,那么位置信息中第二位一直是 A(不需要偏移) 假设 sourcemaps 中 sources: [‘a.js’, ‘b.js’] 本例的意思是 AAAA: 目标文件第 0 行第 0 列 对应 第 0 个文件 a.js ACAA; 目标文件第 1 行第 0 列 对应 第 1 个文件 b.js ADAA; 目标文件第 2 行第 0 列 对了 第 0 个文件 a.js (偏移是 -1 又回到了 a.js) 源文件的行信息 位置信息的第三位表示源文件中的行的信息, 理解了位置偏移的概念,我们很容易理解 如:‘AACA,CACA;AACA;‘ 那么 AACA: 目标文件的第 0 行第 0 列 对应 第 0 个文件的第 1 行 CACA: 目标文件的第 0 行第 0+1 列 对应 第 0 个文件的第 1+1 行 AACA:目标文件的第 1 行第 0 列 对应 第 0 个文件的第 1 行 (注意:’;’ 后的行列偏移信息归 0) 源文件中的列信息 位置信息的第四位表示源文件中的列的信息 如:'AAAA,CAAC;' 那么 AAAA: 目标文件的第 0 行第 0 列 对应 第 0 个文件的第 0 行第 0 列 CAAC: 目标文件的第 0 行第 0+1 列 对应 第 0 个文件的第 0 行第 0+1 列 位置信息的第五位 第五位表示变量的偏移,对应 sourcemaps 中的 names 字段,表示目标文件中的变量名对应域源文件中的变量 如:’AAAA,CAACC;AAAAD;' sourcemaps 中 names 字段是 [‘a’, ‘b’] 那么 AAAA: 目标文件的第 0 行第 0 列 对应 第 0 个文件的第 0 行第 0 列,没有变量的信息 CAACC: 目标文件的第 0 行第 0+1 列 对应 第 0 个文件的第 0 行第 0+1 列,有变量信息,变量在源文件中是 ‘b’ (0+1=1) AAAAD: 目标文件的第 1 行第 0 列 对应 第 0 个文件的第 0 行第 0 列,有变量信息,变量在源文件中是 ‘a’ (1-1=0) --------- 大神分割线 --------- 怎么使用 Sourcemaps Q: 线上小程序报错,我怎么通过 sourcemaps 还原到源代码中? A: 如报错 appservice.js 1:15000, 表示目标文件第一行 第 15000 列位置报错。根据上文介绍的,通过 mappings 字段算。 Q: 不会。 A: 如果你会写代码的话,参考下边 [代码]import fs = require('fs') import {SourceMapConsumer} from 'source-map' async function originalPositionFor(line, column) { const sourceMapFilePath = '如果你不真的替换的成 sourcemaps 在硬盘中的位置,那你还是放弃自己写代码吧。 ' const sourceMapConsumer = await new SourceMapConsumer(JSON.parse(fs.readFileSync(sourceMapFilePath, 'utf8'))) return sourceMapConsumer.originalPositionFor({ line, column, }) } originalPositionFor(出错的行,出错的列) [代码] Q: 不会写代码 A: 下载最新版的开发者工具,菜单-设置-拓展设置-调试器插件 [图片] [图片] Q: 为啥都是 null? A: 每个小程序版本都应该对应一个sourcemap文件。 运营中心那里下载的 sourcemap 是对应线上最新的小程序版本。但运营中心的报错集合了多个小程序版本。拿旧小程序版本的报错信息,和最新版本的 sourcemap,是匹配不出的。开发者工具和ci 上传的时候,会提示下载对应版本的 sourcemap 信息,可以自助保存。 [图片] Q: 怎么确定有没有版本对应上 A: 下载的 sourcemap 中有个 wx 字段,标明了该 sourcemap 文件对应小程序版本号。 [图片] [图片] 前提 1.确保发生错误的小程序版本和下载回来的 sourcemap 版本是一致的。 a. 下载 sourceMap 文件,可在 mp 后台或开发者工具上传成功弹窗下载 2.确保 map 文件和发生错误的 js 文件是对应的。sourcemap 的目录和文件说明 a. APP 是主包,FULL 是整包(仅在不支持分包的低版本微信中使用),其他目录是分包 b. 每个分包下都有对应的 app-service.js.map 文件。 c. 如果是使用了按需注入特性(app.json中配置了lazyCodeLoading),那么每个分包下还会有 appservice.app.js.map(对应分包下非页面的js),和所有页面的 xxx.js.map 以上事情都确保正确之后,还是出现行列号匹配不出来的情况。那就需要进一步排查。 线上运行的小程序 sourcemap 文件是怎么生成的? 处理流程:源码 [ a.js a.js.map b.js b.js.map ] -> 开发者工具(JS转 ES5,压缩)-> 微信后台(合并 js 文件)[ appservice.app.js appservice.app.js.map]。 注意:如果源码在交给工具之前是经过了 webpack 等打包工具的处理,那源码这里需要有 map 文件。否则不需要存在 map 文件。 可以看出,map 文件经过三个步骤的处理,每个步骤都有可能导致出错,因此开发者需要先排查,是否是前两个步骤出错导致的 map 文件失效的。 如何排查前两个步骤产生的 map 文件是否有问题。 1.排查 a.js.map 文件是否有问题。 a. 可以在 a.js 的代码中写一下 throw new Error(‘test sourcemap’)。 b. 使用了 webpack 的情况下,要构建为生产环境的版本。 c. 在开发者工具模拟器中运行对应的页面,看看控制台中的报错,错误行列号是否能正常映射到源文件。 2.排查 开发者工具(JS转 ES5,压缩)步骤是否有问题。 在排查完第一步的基础上,点击预览,用微信上扫码预览,并打开调试 vConsole 功能,检查 vConsole 中是否有报错信息,检查报错信息中的行列号是否能正常映射到源文件。 如何排查 微信后台(合并 js 文件)是否有问题。 a. 一定要先排查完前两个步骤再来排查这一步,一般情况下,这一步是不会出错的。 b. 如果有问题,也只会导致 map 文件中的行号信息出现偏移。比如 Error 信息中显示报错地址是 100: 200,行号是 100。那么你可能直接用 100: 200 在 map 文件中搜索不出信息,但是如果 用 150: 200 就可以搜索出来,说明行号偏移了 50。那其他报错也可以偏移 50 后再进行搜索就找到结果。 c. 怎么排查偏移了多少?可以结合 error.message 的内容,初步判断大概错误的内容是什么。把对应的 map 文件放到这个网站上 source-map-visualization 进行搜索,找出哪些相同列号的地方。再结合 error.message 的内容进行判断。 d. 如果排查到是这一步导致的问题,请在社区上联系我们,我们会在后续版本进行修复。 依旧排查不出原因? 先整理一下按照上述步骤排查的结论,再在社区上联系我们协助
2023-02-10 - api.weixin.qq.com 请求超时
[图片] 今天从凌晨才开始 出现 访问 微信接口超时。 目前已经恢复。 请问是什么原因导致的。客户想知道确切原因,防患于未来。 appid是wxf55b4bc3eb2832c4
2020-01-14 - 小程序搜索优化指南(SEO)
2019年上半年微信发布了基于小程序页面的搜索,为了让我们更好地发现及理解小程序的页面,结合过去一段时间来我们遇到的各种情况,我们强烈建议各位开发者花一些宝贵的时间认真阅读本文:) 爬虫访问小程序内页面时,会携带特定的 user-agent "mpcrawler" 及场景值:1129 1. 小程序里跳转的页面 (url) 可被直接打开。 小程序页面内的跳转url是我们爬虫发现页面的重要来源,且搜索引擎召回的结果页面 (url) 是必须能直接打开,不依赖上下文状态的。特别的:建议页面所需的参数都包含在url 2. 页面跳转优先采用navigator组件。 小程序提供了两种页面路由方式: a.navigator 组件 b. 路由 API,包括 navigateTo / redirectTo / switchTab / navigateBack / reLaunch 建议使用 navigator 组件,若不得不使用API,可在爬虫访问时屏蔽针对点击设置的时间锁或变量锁。 3.清晰简洁的页面参数。 结构清晰、简洁、参数有含义的 querystring 对抓取以及后续的分析都有很大帮助,但是将 JSON 数据作为参数的方式是比较糟糕的实现。 4. 必要的时候才请求用户进行授权、登录、绑定手机号等。 建议在必须的时候才要求用户授权(比如阅读文章可以匿名,而发表评论需要留名)。 5. 我们不收录 web-view 中的任何内容。 我们暂时做不到这一点,长期来看,我们可能也做不到。 6. 利用 sitemap 配置引导爬虫抓取,同时屏蔽无搜索价值的路径。 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html 7. 设置一个清晰的标题和页面缩略图。 页面标题和缩略图对于我们理解页面和提高曝光转化有重要的作用。 通过wx.setNavigationBarTitle或 自定义转发内容onShareAppMessage对页面的标题和缩略图设置,另外也为 video、audio 组件补齐 poster /poster-for-crawler属性。 8. 使用页面路径推送能力 可极大丰富微信可以收录的内容,进而提高小程序内容的曝光机会。请参考: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/search/search.submitPages.html
2020-01-14 - 微信开放社区正确的提问方式
调侃 某萌新:为什么我在社区提问的问题都没人回答啊 某大佬:社区的问题质量是越来越低了,真不想看社区的问题了 如何提问 今天,在下就来告诉大家如何优雅的提问: 在提问之前,先想好自己遇到的问题是什么,让想要帮助你的人,知道你的问题所在 提问语言简洁明了,详细说明重现步骤及可能存在的问题 附上问题截图,比如调试工具报错信息、提审被驳回信息 写明代码环境,如工具版本、手机版本、基础库版本等 如果调用接口报错,请直接把接口的官方文档地址贴出来,标明调用接口地址,附上请求的参数以及返回的数据 必要时请提供代码截图或代码片段 点击查看如何创建代码片段 最重要的一点:提问时请务必注意礼貌。这一点特别重要,因为这关乎到回答者决定要不要回答以及以怎么样的态度来回答 依然是重要的一点:请务必给认真回答协助解决问题的回答者一个“赞”,这会更加激起他们回答的积极性 千万不要投机,把问题提到“文章”版块,这样会被直接隐藏。不仅不会加快被解答的速度,还会耽误解答机会 示例 (仅为示例,不代表该问题实际存在) 标题:picker组件多级联动会出现选项为 null 的情况? 内容: 使用picker组件,设定为多级联动,仅滚动一级栏后确定,后面的栏目获取到的值为 null,能麻烦帮忙看下吗?最新版开发者工具,基础库版本 2.9.2 代码片段:xxxxxxxxxxxxxxxx 继续调侃 某萌新:诶?真的诶,这样提问,好多问题都被解决了 某大佬:这问题问得是真的好,多来点这样的问题,回答也舒坦
2020-01-03 - 微信小程序自定义导航栏组件(完美适配所有手机),可自定义实现任何你想要的功能
背景 在做小程序时,关于默认导航栏,我们遇到了以下的问题: Android、IOS手机对于页面title的展示不一致,安卓title的显示不居中 页面的title只支持纯文本级别的样式控制,不能够做更丰富的title效果 左上角的事件无法监听、定制 路由导航单一,只能够返回上一页,深层级页面的返回不够友好 探索 小程序自定义导航栏已开放许久>>了解一下,相信不少小伙伴已使用过这个功能,同时不少小伙伴也会发现一些坑: 机型多如牛毛:自定义导航栏高度在不同机型始终无法达到视觉上的统一 调皮的胶囊按钮:导航栏元素(文字,图标等)怎么也对不齐那该死的胶囊按钮 各种尺寸的全面屏,奇怪的刘海屏,简直要抓狂 一探究竟 为了搞明白原理,我先去翻了官方文档,>>飞机,点过去是不是很惊喜,很意外,通篇大文尽然只有最下方的一张图片与这个问题有关,并且啥也看不清,汗汗汗… 我特意找了一张图片来 [图片] 分析上图,我得到如下信息: Android跟iOS有差异,表现在顶部到胶囊按钮之间的距离差了6pt 胶囊按钮高度为32pt, iOS和Android一致 动手分析 我们写一个状态栏,通过wx.getSystemInfoSync().statusBarHeight设置高度 Android: [图片] iOS:[图片] 可以看出,iOS胶囊按钮与状态栏之间距离为:4px, Android为8px,是不是所有手机都是这种情况呢? 答案是:苹果手机确实都是4px,安卓大部分都是7和8 也会有其他的情况(可以自己打印getSystemInfo验证)如何快速便捷算出这个高度,请接着往下看 如何计算 导航栏分为状态栏和标题栏,只要能算出每台手机的导航栏高度问题就迎刃而解 导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2 + 状态栏高度 注:由于胶囊按钮是原生组件,为表现一致,其单位在各种手机中都为px,所以我们自定义导航栏的单位都必需是px(切记不能用rpx),才能完美适配。 解决问题 现在我们明白了原理,可以利用胶囊按钮的位置信息和statusBarHeight高度动态计算导航栏的高度,贴一个实现此功能最重要的方法 [代码]let systemInfo = wx.getSystemInfoSync(); let rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null; //胶囊按钮位置信息 wx.getMenuButtonBoundingClientRect(); let navBarHeight = (function() { //导航栏高度 let gap = rect.top - systemInfo.statusBarHeight; //动态计算每台手机状态栏到胶囊按钮间距 return 2 * gap + rect.height; })(); [代码] gap信息就是不同的手机其状态栏到胶囊按钮间距,具体更多代码实现和使用demo请移步下方代码仓库,代码中还会有输入框文字跳动解决办法,安卓手机输入框文字飞出解决办法,左侧按钮边框太粗解决办法等等 胶囊信息报错和获取不到 问题就在于 getMenuButtonBoundingClientRect 这个方法,在某些机子和环境下会报错或者获取不到,对于此种情况完美可以模拟一个胶囊位置出来 [代码]try { rect = Taro.getMenuButtonBoundingClientRect ? Taro.getMenuButtonBoundingClientRect() : null; if (rect === null) { throw 'getMenuButtonBoundingClientRect error'; } //取值为0的情况 if (!rect.width) { throw 'getMenuButtonBoundingClientRect error'; } } catch (error) { let gap = ''; //胶囊按钮上下间距 使导航内容居中 let width = 96; //胶囊的宽度,android大部分96,ios为88 if (systemInfo.platform === 'android') { gap = 8; width = 96; } else if (systemInfo.platform === 'devtools') { if (ios) { gap = 5.5; //开发工具中ios手机 } else { gap = 7.5; //开发工具中android和其他手机 } } else { gap = 4; width = 88; } if (!systemInfo.statusBarHeight) { //开启wifi的情况下修复statusBarHeight值获取不到 systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20; } rect = { //获取不到胶囊信息就自定义重置一个 bottom: systemInfo.statusBarHeight + gap + 32, height: 32, left: systemInfo.windowWidth - width - 10, right: systemInfo.windowWidth - 10, top: systemInfo.statusBarHeight + gap, width: width }; console.log('error', error); console.log('rect', rect); } [代码] 以上代码主要是借鉴了拼多多的默认值写法,android 机子中 gap 值大部分为 8,ios 都为 4,开发工具中 ios 为 5.5,android 为 7.5,这样处理之后自己模拟一个胶囊按钮的位置,这样在获取不到胶囊信息的情况下,可保证绝大多数机子完美显示导航头 吐槽 这么重要的问题,官方尽然没有提供解决方案…竟然提供了一张看不清的图片??? 网上有很多ios设置44,android设置48,还有根据不同的手机型号设置不同高度,通过长时间的开发和尝试,本人发现以上方案并不完美,并且bug很多 代码库 Taro组件gitHub地址详细用法请参考README 原生组件npm构建版本gitHub地址详细用法请参考README 原生组件简易版gitHub地址详细用法请参考README 由于本人精力有限,目前只计划发布维护好这2种组件,其他组件请自行修改代码,有问题请联系 备注 上方2种组件在最下方30多款手机测试情况表现良好 iPhone手机打电话和开热点导致导航栏样式错乱,问题已经解决啦,请去demo里测试,这里特别感谢moments网友提出的问题 本文章并无任何商业性质,如有侵权请联系本人修改或删除 文章少量部分内容是本人查询搜集而来 如有问题可以下方留言讨论,微信zhijunxh 比较 斗鱼: [图片] 虎牙: [图片] 微博: [图片] 酷狗: [图片] 知乎: [图片] [图片] 知乎是这里边做的最好的,但是我个人认为有几个可以优化的小问题 打电话或者开启热点导致样式错落,这也是大部门小程序的问题 导航栏下边距太小,看起来不舒服 搜索框距离2侧按钮组距离不对等 自定义返回和home按钮中的竖线颜色重了,并且感觉太粗 如果您看到了此篇文章,请赶快修改自己的代码,并运用在实践中吧 扫码体验我的小程序: [图片] 创作不易,如果对你有帮助,请移步Taro组件gitHub原生组件gitHub给个星星 star✨✨ 谢谢 测试信息 手机型号 胶囊位置信息 statusBarHeight 测试情况 iPhoneX 80 32 281 369 48 88 44 通过 iPhone8 plus 56 32 320 408 24 88 20 通过 iphone7 56 32 281 368 24 87 20 通过 iPhone6 plus 56 32 320 408 24 88 20 通过 iPhone6 56 32 281 368 24 87 20 通过 HUAWEI SLA-AL00 64 32 254 350 32 96 24 通过 HUAWEI VTR-AL00 64 32 254 350 32 96 24 通过 HUAWEI EVA-AL00 64 32 254 350 32 96 24 通过 HUAWEI EML-AL00 68 32 254 350 36 96 29 通过 HUAWEI VOG-AL00 65 32 254 350 33 96 25 通过 HUAWEI ATU-TL10 64 32 254 350 32 96 24 通过 HUAWEI SMARTISAN OS105 64 32 326 422 32 96 24 通过 XIAOMI MI6 59 28 265 352 31 87 23 通过 XIAOMI MI4LTE 60 32 254 350 28 96 20 通过 XIAOMI MIX3 74 32 287 383 42 96 35 通过 REDMI NOTE3 64 32 254 350 32 96 24 通过 REDMI NOTE4 64 32 254 350 32 96 24 通过 REDMI NOTE3 55 28 255 351 27 96 20 通过 REDMI 5plus 67 32 287 383 35 96 28 通过 MEIZU M571C 65 32 254 350 33 96 25 通过 MEIZU M6 NOTE 62 32 254 350 30 96 22 通过 MEIZU MX4 PRO 62 32 278 374 30 96 22 通过 OPPO A33 65 32 254 350 33 96 26 通过 OPPO R11 58 32 254 350 26 96 18 通过 VIVO Y55 64 32 254 350 32 96 24 通过 HONOR BLN-AL20 64 32 254 350 32 96 24 通过 HONOR NEM-AL10 59 28 265 352 31 87 24 通过 HONOR BND-AL10 64 32 254 350 32 96 24 通过 HONOR duk-al20 64 32 254 350 32 96 24 通过 SAMSUNG SM-G9550 64 32 305 401 32 96 24 通过 360 1801-A01 64 32 254 350 32 96 24 通过
2019-11-17 - 怎么实现背景图片铺满手机屏幕包括导航栏?
就是这样的效果: [图片] 贴一下我的代码: [图片] [图片] [图片] [图片] 我是用了github上的一个自定义导航栏组件,但是只能实现这样的效果: [图片] 如果不使用自定义导航栏组件直接设置 "navigationStyle": "custom" 的话倒是可以全屏铺满,可是就没有导航栏了,只剩胶囊了。
2019-11-21 - 近期关于分享类问题的汇总,欢迎大家交流讨论~
规则相关 请问“再选一个” 是不算诱导分享的吗?类似文案“再领一次”能用吗,算诱导吗? 查看详情 玩家只是正常的分享,游戏里并没有诱导,高分享率会被封吗? 查看详情 请问类似于欢乐麻将这样的分享逻辑可不可以? 查看详情 案例交流 小游戏分享带量到底怎们做,有经验的同学进 查看详情 分享图素材各位有啥想法?查看详情 现在做分享都做不动了,哪位大佬有啥好想法?可以分享一下么? 查看详情 能力问题(定向分享) A向C定向分享邀请加入游戏,请问怎样才能知道C进入了游戏? 查看详情 定向分享后获得金币奖励能不能给个清晰的说明?查看详情 如有相关疑问,本帖下留言,小编会一一为您解惑哦~~
2019-11-19 - 【干货】微信内置浏览器缓存清理
之前做过很多公众号的项目,项目写完后给客户看项目,客户一而再再而三的修改元素向左挪1px,向右挪2px。改好之后让客户看,客户说我特泽发克,你啥都没有修改,你竟然骗我!!! 这其实就是微信内置浏览器的缓存在作祟啦,那么如何清理微信内置浏览器的缓存呢? 你们是否知道 ios版微信 和 android版微信 的内置浏览器的内核是不一样的呢? android版微信内置浏览器(X5内核) 在安卓版微信内打开链接 http://debugx5.qq.com 拉到调试页面的最底端,勾选上所有的缓存项目,点击清除。 [图片] 点击确定之后即可完成清除微信浏览器缓存的操作。 ios版微信内置浏览器(WKWebView) ios版微信内置浏览器内核并不是 X5内核,而是使用的ios的浏览器内核WKWebView,所以安卓手机的那种方案对ios手机用户不生效,因为那个链接压根打不开 只要微信用户退出登录,然后重新登录,ios版微信内置浏览器内核即可清除,不行的话,你们回来打我 有人说了:“IOS中 设置—通用----存储空间 就会看到“正在计算空间”计算完了会清理一点清理即可”,这种办法当然也可以,但是这种办法不光是清理微信内置浏览器的缓存,同时也清理其他的一些数据,比如朋友圈的视频图片和聊天记录等等缓存,而且容易误删某些想留下的数据,对于开发而言,我认为退出重新登录是最好的解决办法。
2020-01-08 - 2019年10月关于小程序搜索问题
9月27号以后就有很多童鞋提出过如下问题(也就这两类) 小程序发布上线后,可以扫码进入,可以分享进入,但是为什么就是搜索不到呢? 我小程序的名字叫ABCDE,之前搜索的时候搜索ABC或者搜索CDE就能搜索到我的小程序,为什么现在只能靠ABCDE才能搜索到? 微信于2019年9月27日对搜索功能进行升级维护,下面是官方发布的消息[图片] **关于第一个问题:**这个是因为搜过功能的升级和维护出现的不应该出现的情况,之前上线新的小程序,一般过十几分钟或者个把小时,就能在搜索中搜索到自己的小程序了,现在有的超过24小时还是搜索不到,对于这种情况,需要发帖子询问官方了,为了官方能尽快帮你解决问题,建议开发者在发帖提问的时候,贴出自己小程序的APPID,方便官方快速帮你查询并修复问题。 **关于第二个问题:**个人的看法是因为搜索功能的异常,本人也搜锁过之前搜索的关键词,搜索出来的结果和之前也是不一样的,包括排名的前后(我是不太相信排名突然间大变样)。只能说微信在搜索功能进行真实环境的测试,而且赶上这个关键的时期,你懂得(别说你不懂,其实我也不懂)。所以大家还是期望微信能尽快成功升级搜索功能,相信升级成功后官方会发公告和文档(感觉这次是大更新)。 对于有些朋友因为搜索的问题,没办法给客户一个合理的解释,大家不要自己强背锅啊,把上面的图发给客户,毕竟这些事情,我们也没办法左右的呀,您说是不? 10月9号更新: 现在好多人发帖说全拼都搜索不到自己的小程序了,首先登录自己的账号,看看有没有站内信,是否有违规被暂时隐藏了,如果没有的话,基本上都是因为小程序优化升级搞得鬼!建议发帖提问,找官方回答,先提供小程序全称和appid,方便官方帮你排查 10月11号更新: 今天看到有同学发帖子说搜索好像恢复了,我自己测试了一下,能搜索出部分小程序,然后过了一会,网络不可用…感觉还没有升级成功 大家都着急,技术小哥更着急,大家还是沉住气等好消息吧!
2019-10-11