- 【简单高效】全面深度解析微信生态应用安全防护策略
作为开发者,最令我们头疼的可能并不是产品需求开发,而是在产品上线后出现的各种安全风险问题。 这些年,我们收到很多开发者提供的真实案例: 投票功能,本来要提供公平公正的投票服务,结果因为有人雇佣水军刷赞,造成投票严重不公平;发放活动优惠券,本来是刺激用户活跃的好活动,好不容易申请了经费,结果被羊毛党用非法手段拿走了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
2024-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、自定义成功后即可和默认智能体一样的流程上线到小程序。 上线成功,来体验一下吧 [图片]
2024-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 - 公众号快速注册并认证小程序
为方便公众号/服务号快捷接入小程序,并在各功能中使用小程序的服务,上线复用公众号/服务号资质注册小程序流程。快速注册认证小程序,境内非个人主体小程序无需重新提交主体材料、无需对公打款、无需支付300元认证费用。境外主体小程序无须重复提交主体材料对小程序认证,无需支付99美元认证费用。 条件:1、境内主体:已认证的企业、媒体、政府、其他组织类型的公众号/服务号(包括企业和个体工商户); 2、境外主体:已认证的服务号(包括境外主体的企业和政府机构)。 限制:1、境内主体非个体工商户类型(企业、媒体、政府、其他组织类型)公众号或服务号一个月可以复用资质注册5个小程序,个体户一个月可以复用资质注册1个小程序; 2、境外主体服务号一个月可以复用资质注册5个小程序。 开通入口: 登录公众号/服务号后台->小程序管理->添加->快速注册并认证小程序 相关规则: 1、复用资质创建的小程序默认与该公众号/服务号关联; 2、复用资质创建的小程序默认关联该公众号/服务号,不占一个月新增关联13个小程序的限制; 3、复用资质创建的小程序默认关联公众号/服务号,不下发模板消息,不默认出现在公众号/服务号资料页; 4、一个公众号/服务号若存在“待完成注册”的小程序,不可发起复用资质创建小程序; 5、一个公众号/服务号一个月内可复用资质注册小程序不多于5个。(创建成功才占用); 6、使用复用公众号/服务号资质注册小程序,将以本公众号/服务号的主体作为该小程序的开发者,可选择以本公众号/服务号运营者作为该小程序的管理员; 7、若选择了复用认证资质,则小程序完成注册后即是“已认证”状态; 8、若选择了复用认证资质,小程序初始认证有效期与公众号/服务号认证有效期一致,后续小程序认证年审需要在小程序后台独立申请。 创建流程: 第一步:登录公众号/服务号后台->小程序管理->添加->快速注册并认证小程序 [图片] 第二步:同意协议 [图片] 第三步:管理员扫码验证 [图片] 第四步:勾需要选快速创建小程序的资质 [图片] 注:复用微信认证资质不需要再次支付认证审核服务费,也不需要审核。 如不复用运营者信息,后续登录小程序时需绑定管理员 第五步:填写小程序账号信息 [图片] 注:邮箱需要是未绑定任何个人微信、公众号、服务号、小程序、微信开放平台的邮箱。 第六步:邮件激活小程序账号,激活完成后即可使用邮箱账号密码登录小程序。 [图片] 第七步:绑定小程序管理员 [图片] 注:绑定管理员,如果有在第四步有勾选复用运营者信息。最终以绑定管理员信息为准。 以上注册流程创建的小程序,不用再走小额打款验证主体。生成的账号具有独立的邮箱账号、密码,跟走正常注册流程注册的小程序具有一样的能力权限。
07-30 - 小程序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 - 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