- 沙箱退款报金额错误
refund_fee填写错误,refund_fee请与支付的total_fee保持一致,沙箱暂不支持多次退款退款参考免充值验收用例 1002/1004,按case中的金额(全额)进行退款,退款金额不需要剔除代金券金额
2021-04-19 - 在调试工具Console里怎么打印本页面的data数据?
想知道如何在调试的时候在Console工具里打印本页面的数据,包括data和非data的
2020-06-28 - 小程序官方地区选择器数据
用途: 后端需要完全匹配小程序的地址做一些操作时,可用到。产品有时需要自定义交互时,可重写地区选择器。来源: 数据来源于微信开发者工具Stable 1.03.2010240。 地址链接: https://static.bazhuay.com/region.zip 地址树形结构: https://static.yipintemian.com/json/region.json(json格式,解决乱码) https://img.bazhuay.com/region.js(可能乱码) 最新的开发工具最新稳定版(1.05.2112141):https://static.yipintemian.com/json/region2.json 温馨提示: 公司在自行开发、运营电商小程序,欢迎交流共同进步。不定期分享文章,欢迎关注哈。
2022-01-20 - 启动报错Uncaught (in promise) undefined?
小程序基础库选择2.26.1之后,启动就报这个错误 [图片]
2022-09-27 - 创建微信小程序时报Uncaught(in promise)undefined (env:Windows,mp ...)
创建小程序会报如下错误 [图片] 出现过程: 跟平常的创建微信小程序一样 不使用模板,不使用云服务等 1111111111111111111111111111111111111111111111111111111111111111111111111111111111 解决方法: 详情-本地设置-调试基础库-调到小一点的版本就行了 [图片] PS 该问题在2.27.1版本好像解决了,大家可以安心使用新版本了
2022-11-05 - 粉丝发来的消息最多保存多久?
接收到的订阅用户(粉丝)发送的消息,系统会保留最近5天的消息,超过时间的消息会自动清空(图片和语音只保留3天)。 温馨提示: 1)在“实时消息”中对订阅用户(粉丝)发送的消息进行标记为“星标消息”,将永久保存该信息。 2)与单个粉丝的实时聊天消息最多只保留20条。 3)图片需在有效期内标记为“星标消息”才有效,如果图片出现裂开将无法保存。 4)图片、语音在有效期内可另存为到素材里面。
2019-11-21 - 微信转发图标变色
安卓手机转发文章,每转一次分享图标每次都变淡一点,多转几次就完全变色了 [图片][图片]
2022-07-29 - 地理位置接口新增与相关流程调整
一、地理位置接口新增说明 由于精确地理位置接口只允许部分类目的小程序申请使用,为了满足开发者在更多场景使用地理位置接口,自 2022 年 7 月 14 日起,新增获取模糊地理位置接口(wx.getFuzzyLocation)。同时为保障用户合法权益,该接口调用前需进行准入开通申请,该接口准入规则与 wx.chooseLocation 一致。 wx.getFuzzyLocation 接口说明: 1、该接口返回的是经过模糊处理的经纬度坐标; 2、该接口支持返回 wgs84 或 gcj02 两种类型的坐标; 3、该接口需要用户授权 scope.userFuzzyLocation。 二、app.json 的配置指引 为了开发者能够正常使用获取模糊地理位置等接口,以及后续对于代码提审环节的优化(见「三、地理位置接口使用流程」),自 2022 年 7 月 14 日起,开发者在使用地理位置相关接口时(共计 8 个,见表1),需要提前在 app.json 中进行配置。 1、需配置的接口列表 [图片] 表1 2、配置规则 1)在代码中使用的地理位置相关接口(共计 8 个,见表1),开发者均需要在 app.json 中 requiredPrivateInfos 配置项中声明,代码格式如下: [图片] 2)表1中模糊位置信息(序号1)和精确位置信息(序号2-5)是互斥的,即声明了模糊位置信息就无法声明精确位置信息。若同时声明模糊位置信息和精确位置信息,则在编译代码时出现错误; 3)注意:自 2022 年 7 月 14 日后发布的小程序,如果未在 app.json 中声明表1中的相关接口,则小程序调用这些接口(表1)时会出现错误,在 2022 年 7 月 14 日之前发布的小程序不受影响; 4)对于第三方开发者,需要在上传代码时通过参数在 ext.json 中声明其需调用的地理位置相关接口,配置规则和普通小程序的配置规则相同。 三、地理位置接口使用流程 自 2022 年 7 月 14 日起,开发者如需在最新版本发布后使用地理位置相关接口,除需完成接口权限开通外,还需在 app.json(或ext.json)配置环节,具体如下: 1、接口权限开通 以下 8 个接口需完成准入开通流程:wx.getFuzzylocation、wx.getLocation、wx.onLocationChange、wx.chooseAddress、wx.choosePoi、wx.chooseLocation、wx.startLocationUpdate、wx.startLocationUpdateBackground 1)普通开发者:需要在 “小程序管理后台 -「开发」-「开发管理」-「接口设置」” 中完成权限申请; 2)第三方开发者:可通过 apply_privacy_interface 接口完成权限申请。 2、app.json(或 ext.json)配置 1)普通开发者:需在 app.json 中声明其需调用的地理位置相关接口,具体配置流程见「二、app.json 的配置指引」; 2)第三方开发者:需要在上传代码时通过参数在 ext.json 中声明其需调用的地理位置相关接口(配置方式:可通过 commit 接口配置)。 同时,为了提升开发者体验,平台在代码提审环节会协助开发者对地理位置接口进行检测,如检测出代码中包含未完成准入开通的地理位置接口,平台将再次提醒开发者确认是否需使用相关接口。 1)普通开发者:若无需使用,开发者可在提审时确认不使用该接口,即可正常进行代码提审。小程序审核通过且新版本发布完成后,平台将对小程序确认不使用的接口关闭使用权限; 2)第三方开发者:若无需使用,可在提审时通过参数声明不使用该接口(声明方式:可通过 submit_audit 接口配置),即可正常进行代码提审,审核通过后发布上线,将对其声明不使用的接口关闭使用权限。 以上调整将仅对所有小程序生效。 微信团队 2022年6月1日
2023-09-26 - 安全课堂|关于小程序AppSecret密钥泄露漏洞
为进一步提升小程序的安全性和用户体验,目前平台对提审的小程序均需进行安全检测,在检测过程中发现仍有许多小程序存在安全漏洞,其中涉及AppSecret密钥泄露漏洞,希望通过以下相关的漏洞介绍、案例分析和修复建议,开发者能更加了解如何对该漏洞进行防御。 一、漏洞介绍 AppSecret是小程序的唯一凭证密钥,也是获取小程序全局唯一后台接口调用凭证(access_token)的重要参数,需要开发者妥善保管至后台服务器中,并严格保密,不向任何第三方等透露。小程序若存在AppSecret密钥泄露漏洞的情况,会造成身份信息仿冒、敏感数据外泄等严重后果,开发者应及时发现该漏洞并快速修复相应问题。 二、漏洞案例 某小程序因为AppSecret泄露,导致攻击者可以通过调用API获取该小程序敏感数据,如接口调用凭证、用户信息、用户使用数据等,造成了极大的安全风险。 通过以下展示我们可以明晰该小程序敏感数据外泄的原因,测试者先对小程序网络请求进行抓包,发现请求响应中包含了appid和AppSecret敏感信息: [图片] 通过上述获取的appid和AppSecret敏感信息,可以利用接口获取到相应的access_token: [图片] [图片] 最后可以实现使用access_token调用该小程序所有后台接口的目的,后台服务端接口已涵盖数据、运维、消息等多方面场景能力。 [图片] 下面我们再具体举几个利用access_token调用小程序后台接口的例子: 1.获取小程序用户评论 [图片] 2.获取小程序用户访问数据 [图片] 3.冒用小程序身份给用户发送消息 [图片] [图片] AppSecret密钥泄露漏洞其他的危害包括但不限于:冒用小程序身份给用户发送客服消息/模板消息、获取小程序session_key(用于解密微信侧提供的用户敏感数据)、获取小程序运维信息、日志等敏感信息、更改小程序相关的配置等。 三、漏洞修复 若小程序存在相应的AppSecret密钥泄露漏洞问题,请开发者尽快根据以下修复指引进行调整,以便消除风险: 1.后端API接口请勿把AppSecret敏感信息返回给前端(包括前端请求或小程序代码内传输、记录AppSecret); 2.立即登录小程序管理后台,在【开发-开发管理-开发设置】中对AppSecret进行重置。由于Appsecret存在历史泄露且仍然有效,务必进行重置才可消除风险,以免被攻击者恶意利用,请尽快按指引进行修复; 3.对AppSecret进行重置后,请及时修改后台代码,以免无法使用微信API [图片] 其他常见问题 Q1: 小程序提审不通过,显示小程序AppSecret存在历史泄露且仍然有效,是否需要重置AppSecret? A1: 需要,请重置AppSecret后再提审,若审核通过,说明该问题已消除,若审核不通过,说明仍存在明文的AppSecret,需进一步排查并去除AppSecret字段及其对应值。 Q2: 重置小程序AppSecret会影响到线上小程序吗? A2: auth.getAccessToken需要使用AppSecret进行调用入参,重置AppSecret后,如果用新的AppSecret去获取access_token,那么旧的access_token会在5分钟内失效,如果未使用新的AppSecret,旧的access_token会在两小时内失效,故即使重置AppSecret,access_token仍有一定的缓冲期,可及时修改后台代码,不会对线上小程序造成影响。 相关文章 安全课堂|关于小程序session_key泄露漏洞安全课堂|关于小程序云AK/SK泄露漏洞 如有其他相关疑问,欢迎随时参与官方社区讨论。
2022-09-09 - #小程序云开发挑战赛#-小程序云开发挑战赛作品全收录-注定拿不到T恤的队伍
应用场景“小程序云开发挑战赛作品全收录”是小程序云开发大赛作品汇总,可按照参赛赛道查看作品即时浏览、点赞数,方便同学们使用哟! 目标用户官方的汇总页面太难用了,300多个链接看死人。 实现思路本小程序采用基于云开发的原生开发,用到了云数据库存储数据,使用云函数和小程序端进行数据交互。 A. 整体架构图如下: [图片] b. 爬虫 没啥好说的,golang爬虫获取社区参赛作品数据 c. 小程序端 大家都是大佬,就不介绍了吧 效果截图[图片] [图片] 小TIps: 1. 点击列头 ”编号“、”浏览“、”点赞“可以排序哟! 2. 部分手机可能顶部导航有些bug,请静待下个版本过审(下个版本可以跳转到社区文章页哟)。 作品体验二维码[图片] 团队简介本团队的核心成员来自注定拿不到T恤的队伍,在微信开放社区也积极活跃。 重要事情说三遍: 请素质三连! 请素质三连! 请素质三连! 不然小心你的作品在【小程序云开发作品全收录】里被硬编码!
2020-09-22 - 配置普通链接二维码规则时校验文件检查失败?如何解决?
今天在做微信小程序配置普通链接二维码规则时出现校验文件检查失败,实在是找不到原因,请高手指教。 [图片] [图片] [图片]
2021-07-01 - 你的小程序类目选正确了吗?
微信小程序的开发者们在发布小程序之前,需要给每个小程序设置好对应类目等信息,然后才能进行代码提审。 小程序的类目等基本信息是用户对一个小程序的初步认知,平台希望这些信息能够给予用户准确预期每个小程序的功能和内容。以及基于部分行业的法律法规要求,小程序提供的服务需要与小程序所选的类目一致。 后续如果小程序存在类目不符问题可能会在代码审核或已发布运营时,收到平台的审核通知或建议修改通知。因此小编整理了以下常见类目的建议及案例: 商家自营业务类 案例1:该小程序在线售卖进口零食饼干辣条等加工预包装食品,或鲜切水果生食产品需提供《食品经营许可证》资质文件,并重新提交审核补充商家自营-食品类目。 [图片] 案例2:该小程序涉及在线售卖图书报刊/音像/影视/游戏/动漫等书籍。零售类需提供县(区)级出版行政主观部门合法的《出版物经营许可证》资质文件;批发类需提供省级出版行政主管部门合法的《出版物经营许可证》资质文件,并重新提交审核补充商家自营-图书报刊/音像/影视/游戏/动漫类目。 [图片] 外卖&电商&点餐等平台型业务类 案例1:该小程序涉及为餐饮门店提供入驻渠道,提供外卖的平台型服务。需提供《增值电信业务经营许可证》资质文件,并重新提交审核补充餐饮-外卖平台类目。 [图片] 案例2:该小程序涉及为企业或个人提供网上交易的平台或涉及实物众筹。需提供《增值电信业务经营许可证》资质文件,并重新提交审核补充电商平台类目。 [图片] 案例3:该小程序涉及在线实物众筹,需提供《增值电信业务经营许可证》资质文件,并重新提交审核补充电商平台类目。 [图片] 案例4:该小程序涉及为餐饮门店提供线上点餐的平台型服务。需提供《增值电信业务经营许可证》资质文件,并重新提交审核补充餐饮-点餐平台类目。 [图片] 时政信息类 小程序内容涉及国家政治生活相关事实的文章/图片/视频/音频报道,主要表现为政党、社会集团、社会势力在处理国家生活和国际关系方面的方针、政策和活动,包括有关政治、经济、历史、军事、外交等社会公共事务的报道、评论。需补充时政信息-时政信息类目。 所需资质:新闻服务商:《互联网新闻信息服务许可证》;政府或监管机构:《非经营性互联网信息服务备案核准》(截图)和《组织机构代码证》 案例1:小程序中涉及现任及前任国家领导人相关的信息内容,需补充时政信息类目。[图片] 案例2:小程序中涉及发布当前港澳台、新疆西藏局势相关内容,包括但不限于视频、报道、评价、观点等形式,需补充时政信息类目。 [图片] 案例3:小程序中涉及解读国家外交部门或公职人员以国家层面发表的言论,需补充时政信息类目。 [图片] 案例4:小程序中涉及当前港澳台领导人、领导候选人与大陆相关时政言论,包括但不限于视频、报道、评价、观点等形式,需补充时政信息类目。 [图片] 案例5:小程序中涉及发布揭秘官方军事活动、军事改革、军队制度改革相关内容(除官方宣布外),需补充时政信息类目。 [图片] 案例6:小程序中涉及发布对反动组织、分裂邪教组织及相关人物进行报道、回顾的相关内容,需补充时政信息类目。 [图片] 在小程序首次提交代码审核时,审核人员会根据小程序初步提交的内容给出类目审核建议,开发者们可以根据建议重新提交审核。同时在小程序运营过程中,随着小程序内容或功能不断丰富,也请开发者及时提交对应类目资质。 目前全部已开放类目及对应资质要求可参考:https://developers.weixin.qq.com/miniprogram/product/material.html。 平台首次发现违规内容后将进行警告通知,警告到期后未整改将会进行相关能力封禁直至下架违规小程序。同时大家在使用小程序的过程中,如发现缺乏类目资质的小程序,欢迎通过手机端小程序的投诉渠道进行反馈和举报。
2020-03-18 - 什么小程序需要文娱相关类目?
什么内容或服务的小程序需要补充文娱相关类目? [图片] 1、小说:小程序中涉及提供电子小说在线阅读服务。需补充文娱-小说类目。 所需资质(2选1): (1)《网络出版服务许可证》 (2)《互联网出版许可证》 案例:如图可看到,该小程序主营业务涉及为用户提供在线观看小说服务,需补充文娱-小说类目。 [图片] 2、学术期刊:小程序中涉及提供学术期刊投稿、阅读等功能服务,需补充文娱学术期刊类目。 所需资质(2选1): (1)期刊出版单位:《期刊出版许可证》 (2)平台型:和两家及以上期刊的合作协议及期刊的《期刊出版许可证》 案例:如图可看到,该小程序涉及提供学术期刊在线阅读等功能,补充文娱- 学术期刊类目。 [图片] 3、其他视频:适用于提供视频播放、观看等服务,包括但不限于业务类型为自办节目、转播节目、节目集成运营服务,适用于除视频外还有其他类型的信息展示形式,包括但不限于图文、音频、动漫等、如提供时政信息服务,需补充:时政信息类目。 所需资质(6选1): 所需资质(6选1): (1)《信息网络传播视听节目许可证》 (2)《广播电视节目制作经营许可证》 (3)《广播电视频道许可证》(适用于电视台) (4)《广播电视节目播出机构许可证》(适用于电视台) (5)《统一社会信用代码》 及 《情况说明函件》(适用于政府主体) (6)《事业单位法人证书》及 该主体的主管部门许可文件(适用于事业单位主体) 案例:如图可看到,该小程序存在其他视频模块内容,需补充:文娱-其他视频类目。 [图片] 4、视频广场:适用于提供视频播放、观看等服务,包括但不限于业务类型为自办节目、转播节目、节目集成运营服务,适用于以视频为唯一信息展示形式的,集合多种行业相关的视频内容, 如提供时政信息服务,需补充:时政信息类目。 所需资质(二选一): 1、电视台、广播 、政府、事业单位主体提供(6选1): (1)《信息网络传播视听节目许可证》 (2)《广播电视节目制作经营许可证》 (3)《广播电视频道许可证》(适用于电视台) (4)《广播电视节目播出机构许可证》(适用于电视台) (5)《统一社会信用代码》及《情况说明函件》(适用于政府主体) (6)《事业单位法人证书》及该主体的主管部门许可文件(适用于事业单位主体) 2、企业主体提供(2选1): (1)《信息网络传播视听节目许可证》 (2)《全国网络视听平台信息登记管理系统》备案 案例:如图可看到,该小程序存在视频广场模块内容,需补充:文娱-视频广场类目。 [图片] 5、FM/电台:小程序内涉及提供电台/网络电台/FM/广播收听平台/音频节目等服务,或小程序名称含FM、电台、广播电台等关键词,需补充文娱-FM/电台类目。 所需资质(2选1): (1)《信息网络传播视听节目许可证》 (2)《广播电视节目制作经营许可证》 案例:如图可看到,该小程序提供的内容是电台音频或广播,属于电台节目服务,需补充文娱-FM/电台类目。 [图片] 6、音乐:小程序内涉及提供有版权音乐的相关服务,需补充文娱-音乐类目。 所需资质(2选1): (1)《信息网络传播视听节目许可证》 (2)《网络文化经营许可证》(经营范围须含有音乐娱乐产品) 案例:如图可看到,该小程序提供的音乐都是需要版权才可播放的内容,需补充文娱-音乐类目。 [图片] 7、有声读物:小程序内涉及提供有版权读物的语音播报服务,需补充文娱-有声读物类目。 所需资质(2选1): (1)《互联网出版许可证》 (2)《网络出版服务许可证》 案例:如图可看到,该小程序涉及提供“盗墓笔记、黄金时代”等有版权书籍的语音播放服务,需补充文娱-有声读物类目。 [图片] 8、动漫:小程序内涉及提供有版权动漫的阅读等服务,需补充文娱-动漫类目。 所需资质(2选1): (1)《互联网出版许可证》与《网络文化经营许可证》(经营范围须含有动漫产品) (2)《网络出版服务许可证》与《网络文化经营许可证》(经营范围须含有动漫产品) 案例:如图可看到,该小程序涉及提供版权动漫在线阅读服务,需补充文娱-动漫类目。 [图片] 9、宗教信息服务:小程序内涉及在线提供宗教信息服务,如:在线售卖宗教衍生品、播放宗教相关视频、音频解读等,需补充文娱-宗教信息服务类目。 所需资质:《省级以上政府宗教事务部门审批文件》 案例:小程序涉及在线售卖佛牌类宗教衍生品,需补充文娱-宗教信息服务类目。 [图片] 10、资讯:小程序内容涉及提供资讯内容,如互联网资讯、行业资讯等(时政信息除外),需补充文娱-资讯类目。 案例:如图可看到,该小程序内容为资讯内容等服务,需补充文娱-资讯类目。 [图片] 11、语音:小程序内容主要提供非节目形式,以语音为主表达形式的服务,需补充文娱-语音类目。 案例:如图可看到,该小程序涉及提供以语音为主表达服务,需补充文娱-语音类目。 [图片] 12、图片:小程序主要提供图片内容为主的服务,需补充文娱-图片类目。 案例:如图可看到,该小程序内容主要头像图片展示为主,需补充文娱-图片类目。 [图片]
2021-12-03 - 什么小程序需要社交相关类目?
什么内容或服务的小程序需要补充社交相关类目? [视频] [图片] 1、陌生人交友:小程序内涉及提供在线陌生人交友服务,需补充社交-陌生人交友类目。 所需资质:《增值电信业务经营许可证》(核准服务项目包含“互联网信息服务业务”) 案例:如下图小程序涉及通过展示用户微信号、电话等信息,提供陌生人交友服务,需补充社交-陌生人交友类目。 [图片] 2、熟人交友:小程序内涉及提供在线熟人交友服务,需补充社交-陌生人交友类目。 所需资质:《增值电信业务经营许可证》(核准服务项目包含“互联网信息服务业务”) 案例:如下图小程序通过用户分享好友关系群,提供熟人交友服务,需补充社交-熟人交友类目。 [图片] 3、社区/论坛:小程序内提供社区/论坛服务,包括UGC内容的发布与交流,如:论坛、贴吧、社群等,需补充社交-社区/论坛类目。 所需资质(2选1): ①《非经营性互联网信息服务备案核准》 ②《组织机构代码证》或《统一社会信用代码证》(适用于政府主体) 案例:如下图小程序用户可通过自定义发布帖子功能,提供论坛服务,需补充社交-社区/论坛类目。 [图片] 4、直播:小程序内涉及提供在线直播服务,需补充社交-直播类目。 所需资质(3选1): ①《信息网络传播视听节目许可证》 ②《网络文化经营许可证》(经营范围含网络表演)(适用于含表演性质的直播) ③《统一社会信用代码》《情况说明函件》(适用于政府主体) 案例:如下图小程序某个模块涉及提供在线产品直播服务,需补充社交-直播类目。 [图片] 5、笔记:小程序内涉及提供自定义内容的记录及分享,包括文字、图片、视频、音频等服务,需补充社交-笔记类目。 所需资质(2选1): ①《非经营性互联网信息服务备案核准》 ②《组织机构代码证》或《统一社会信用代码证》(适用于政府主体) 案例:如下图小程序提供自定义音频录制,需补充社交-笔记类目。 [图片] 6、婚恋:小程序内涉及提供婚恋交友服务,需补充社交-婚恋类目。 所需资质:《增值电信业务经营许可证》(核准服务项目包含“互联网信息服务业务”) 案例:如下图小程序涉及通过发布婚恋需求者个人信息提供婚恋交友服务,需补充社交-婚恋类目。 [图片] 7、问答:小程序内涉及提供用户可以根据自身的需求,有针对性地发布、提出和解决问题,或者搜索其他用户解答的平台服务,需补充社交-问答类目。 所需资质(2选1): ①《非经营性互联网信息服务备案核准》 ②《组织机构代码证》或《统一社会信用代码证》(适用于政府主体) 案例:如下图小程序支持用户自定义发布问题或答案,提供平台服务,需补充社交-问答类目。 [图片] 8、直播答题:小程序内涉及提供直播答题服务,需补充社交-直播答题类目。 所需资质:《信息网络传播视听节目许可证》 案例:如下图小程序涉及提供在规定时间点提供在线答题直播服务,需补充社交-直播答题类目。 [图片]
2020-12-11 - 微信开发者工具创建的插件报错:WebAssembly.instantiate()?
新创建的插件就报这个错: VM22 WAService.js:2 TypeError: WebAssembly.instantiate(): Argument 0 must be a buffer source or a WebAssembly.Module object 请问有什么解决办法没有?
2021-01-31 - 个人项目学习笔记
前言:看完了比赛项目,感觉像是经历了一场头脑风暴,项目的起名、涉足行业、内容、UI、架构,以及业务设计等,感到都有很多学习的地方。打算做一个学习笔记贴。 一、分类 *项目有点多,我自己做了一下分类,以便查找。 记账与备忘: 《大学生记账本》 《咸鱼记账》 《KrisQin记账本》 《MY备忘》 《家庭多用记事本》 《ygjtools》 《乐考吧》 《日程管家》 《YAccount记账助手》 《随变记账》 《待办事项工具》 《小婷和小天一起记账》 《初心日历》 《寝记账》 《智慧账本》 失物招领: 《爱心收发室》 《帮寻小站》 《月见》 《长大寻物》 《悦寻失物招领》 《校园寻回》 《失全拾美》 健身类: 《健身助手力量日记》 《活力健身房》 《RedPoint红点》 《健身小程序简介》 音乐影视: 《云享Music》 《king电影》 《無音不泉》 《电影周周荐》 AI识别: 《鹦鹉AI端侧识别》 《ai视觉测试》 《图文识别》 《AI物以类聚》 《AI写诗》 医疗健康: 《人体生理指标》 《吃药小助》 《己目》 《体重MM》 《菲特日记》 《医医查》 《全国核酸检测资质医院查询》 《糖友饮食助手》 《每日戒糖》 《自助心理成长》 《预约挂号小程序》 《蓝医先生》 社团活动: 《阮薇薇点名啦》 《山大clubs》 《素拓百分百》 《小小微距》 《娱乐投票小程序》 《活动栏》 《薇科技弹幕墙》 《头马报名》 《滑伴》 《科联答题》 《招新Plus》 《文艺比赛小行家》 《布告》 《BJUT活动助手》 《准到聚餐》 学习工具: 《错题小本本》 《为高考加分》 《分录英雄》 《口算助手》 《答案sou》 《教资易取》 《快刷题库answer question》 《拾一英语》 《魅力单词》 《魔方训练计时器》 《focusair》 《Y计算器》 《高级工匠心录》 《成长课程表》 《“倾听者”综合型语音评价系统》 《小青考证》 《IAI CDS》 教育培训: 《来这儿学》 《微学堂(在线学习平台)》 《大学生资源共享平台》 《袋鼠培培》 《宝贝积分管理》 时间管理: 《西瓜清单》 《语音倒计时器》 《西红柿时间管理》 《Do More打卡小程序》 《倒计时》 《tomato clock》 《step by step》 《BT清单》 《tusake Today》 《叮咚倒数日》 《FTodoList》 校园管理: 《班级价值分》 《校园缺勤录》 《教务小助手》 《工程课表》 《云迎新》 《CAN课程表》 《简单的课表小程序》 《运动会管理系统》 《重邮课后小程序》 《高校信息共享平台》 《校园简单易》 《中北请假助手》 《知侬》 《ITD智慧校园》 《We广油》 《江大电服》 校园介绍: 《阿里嘻嘻》 《民大新生助手》 《北邮宣讲通》 《志愿校园》 《浙里淘志愿》 《云校知》 《校拍》 校园社区: 《北院守夜人》 《校园墙》 《AIB校友会》 《校园小唤》 《xcu许院生活》 物流快递: 《高校联盟-快递代取》 《速派递》 《物流小程序》 预约与邀请: 《天翊图书馆预约》 《农大饭食》 《课室助手》 《会议邀请函》 《weSport》 《哪天约》 《定约》 《易约行》 《自闭间预定》 《简约约拍》 《实验室设备预约助手》 《QSCamera》 《预约班车》 《心暖农侬》 《书香长大》 《私约团课》 情侣婚礼: 《趣婚礼》 《小酒馆》 《恋人小清单》 《云表白》 《情侣券》 《旅梦恋爱》 《快表白》 《恋爱空间》 购物商城: 《微信云商城》 《吃否CHIFOU》 《云端商城小程序》 《购物》 《柠檬商城》 《武冈微商城》 《狗头的店,狗头管理》 《林林的妙妙屋》 《芳甸鲜花商城》 《优鲜配送联盟》 《汇尤e家》 《云开发带后台商城系统》 《预付费机票销售小程序》 《微购收单》 知识普及: 《科普小程序》 《百词百科》 《BOSS百科》 《球员搜搜》 《火查查》 《急速查病》 《趣答星球》 《铁路生涯》 《趣酿》 《吃吃等你》 《男人买菜》 《诗华社》 《天天诗词》 《心跑道》 程序员: 《sentry 小程序客户端》 《GitPark》 《码农SHOW营》 《OTP动态验证码》 《微源库》 《LE编程》 《一起来学计组叭》 《统一运维平台》 《见字如面》 图像处理: 《莉龙美颜工具》 《图像复原微信小程序》 《Hi头像》 《我是主角》 《修补匠》 《祥云》 《抽屉表情》 《人脸识别虚拟仿真实验》 《照片时光机》 语言翻译: 《CEnews》 《多源在线翻译》 《汉泰小词典》 《识译小程序》 社区周边: 《社区速修》 《虚拟社区》 《简物业》 《租户在线》 《美今管家》 《顾家》 《雨中送伞》 《盲小鹿》 树洞与留言: 《海豚时光瓶》 《树洞》 《苦海匿舟》 《深大小树洞》 《LMSH7TH》 简历与工作: 《个人简历Plus》 《快速找工作》 《猿宝典》 《云线名片》 《InterviewHub》 《企业招聘》 《JF校园云招聘平台》 《普罗名特》 《校园招聘》 资讯与娱乐: 《Killkinfe》 《开心小杜》 《旅小布短视频》 《心灵鸡汤大全》 《轨道nighty night》 《拯救不开心》 《大宗交易数据查询分析助手》 《糗事》 旅行: 《我的旅行箱》 《云航助手》 《宝塔出行》 《PicGo图旅》 城市宣传与服务: 《数字余杭》 《哏儿通》 《联系群众客户端》 《城市预警系统》 《郑州限行查询》 《佤山行》 商业工具: 《软著助手》 《义思丽代办平台》 《契约farm》 办事工具: 《省计数字监理》 《OA外勤管家》 《报工小助手》 《make的测评程序》 《实验室管理小程序》 《星河意见箱》 《梦凡云OA》 《微助helper》 《群消息公示》 《安全帽智慧监控小程序》 地图打卡: 《高级打卡鸡》 《摄影地图游客版》 《同学在哪儿》 《每日步数打卡》 《生活智打卡》 《打卡日历》 《Mayday Online》 《嘿!我在这儿!》 《心里有树》 《地图留言》 《印纪》 天气与日历: 《一眼天气》 《历史日历》 《7日天气》 《历史上的今天TIH》 《实用小工具》 游戏娱乐: 《趣味游乐城》 《假如生命很短暂》 《磁力积木3D预览》 《MusicColorBlock-Detail》 《消灭癌细胞》 《红小包抽奖》 《大师请提笔》 《画画的北鼻》 《东方小游戏》 存储与分享: 《酷传CoolTran》 《我存》 《次元乌托邦云网盘》 《闪加》 《悦分享》 《云享坊》 生活工具: 《WiFi生成码》 《古老的API小工具》 《日常工具box》 《柠檬收纳》 《买它or not》 《我车呢》 《微信小程序工具箱》 《小记易》 《电魔方智能家居》 《缸中之鱼导购系统》 《格式转换工厂》 《小神助手》 《我家的WIFI》 二手交易与租赁: 《大学校园闲置物品交易平台》 《宝宝约玩》 《精简之校园二手交易平台》 《学辰ing》 《二手市场》 《虾麦》 《校园二手购》 《零工哥》 《易珠》 《瓜大e拼车》 外卖点单收银: 《来一杯a》 《美食屋》 《外卖系统》 《便利下单助手》 《云智慧收银》 《超市Boss助手(零售助手)》 《为特餐饮助手》 《Holly食刻》 《微信自助点餐小程序》 《餐饮流水记账》 《seven取餐小程序》 《校内外卖》 《秀食餐饮小程序》 《校云通》 日记博客论坛: 《博客系统》 《天天读书》 《myVlog》 《红推》 《论坛小程序》 《一瞬相册》 《席博》 《一只书匣》 《社交平台》 《图迹圈》 《MallBook》 《青存纪》 《酒肆 家谱》 《比斯兔u》 《校园书友》 《CC交个朋友》 《点滴互助》 《广大搜搜》 《社交点评》 《迷你论坛》 《Simple Note 短记》 垃圾分类: 《垃圾问问》 《垃圾分类小程序》 《垃圾分类赢好礼》 宠物: 《萌宠创造营》 《宠幸治疗》 《宠物营地》 《流浪猫速查手册》 《泊宠》 物联网: 《lononiot》 《LoRa智能家居管理》 《温湿度实时监控及开关控制小demo的设计》 《HomeAssistant》 《流量计设备性能测试平台》 疫情防控: 《行程助手Plus》 《每天都要上报体温》 《校园疫情管理小程序》 《CUMTB疫情管控期间学生外出申请系统》 《疫简签》 地摊: 《地摊生活》 《逛逛地摊》 《迷你小摊》 二、学习笔记 (一)名词解释 1,分录: 会计分录亦称“记账公式”,简称“分录”。它根据复式记账原理的要求,对每笔经济业务列出相对应的双方账户及其金额的一种记录。 2,文玩: 指的是文房四宝及其衍生出来的各种文房器玩。这些文具造型各异,雕琢精细,可用可赏,使之成为书房里、书案上陈设的工艺美术品。 3,sentry: Sentry是一个开源的实时错误追踪系统,可以帮助开发者实时监控并修复异常问题。 4,GitHub: 是一个面向开源及私有软件项目的托管平台,因为只支持Git作为唯一的版本库格式进行托管,故名GitHub。 5,软著: 全称是计算机软件著作权,是指软件的开发者或者其他权利人依据有关著作权法律的规定,对于软件作品所享有的各项专有权利。 6,打卡: 网络流行词,原指上下班时刷卡记录考勤。现衍生指到了某个地方或拥有某个事物(一般会向他人展示)。网红、圣地打卡。 7,番茄工作法: 是简单易行的时间管理方法。使用番茄工作法,选择一个待完成的任务,将番茄时间设为25分钟,专注工作,中途不允许做任何与该任务无关的事,直到番茄时钟响起,然后进行短暂休息一下(5分钟就行),然后再开始下一个番茄。每4个番茄时段多休息一会儿。 8,码农: 可以指在程序设计某个专业领域中的专业人士,或是从事软体撰写,程序开发、维护的专业人员。但一般Coder特指进行编写代码的编码员。 9,树洞: 来源于童话故事《皇帝长了驴耳朵》,意思是一个可以袒露心声的地方,是指可以将秘密告诉它而绝对不会担心会泄露出去的地方。 10,AI: 全程人工智能(Artificial Intelligence),英文缩写为AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 11,OA: 办公自动化(Office Automation,简称OA)是将现代化办公和计算机技术结合起来的一种新型的办公方式。办公自动化没有统一的定义,凡是在传统的办公室中采用各种新技术、新机器、新设备从事办公业务,都属于办公自动化的领域。 12,素拓: “素质拓展训练”的简称。素质拓展起源于国外风行了几十年的户外体验式训练,通过设计独特的富有思想性、挑战性和趣味性的户外活动,培训人们积极进取的人生态度和团队合作精神,是一种现代人和现代组织全新的学习方法和训练方式。 13,磁力积木: 由若干个不同形状的积木单体组成。在各个单体的边沿嵌有磁铁或磁片,磁铁上履盖有一层搪瓷,利用磁力使各单体紧密连接在一起。 14,教资: 指教师资格证考试,是由教育部考试中心官方设定的教师资格考试。 15,Instagram: 又叫照片墙,是一款运行在移动端上的社交应用,以一种快速、美妙和有趣的方式将你随时抓拍下的图片彼此分享。 16,Redpoint: 攀岩术语,是指事前曾练习爬过该路线,以先锋攀登的方式、无坠落地完攀该路线。 17,头马: 是Toastmasters的中文简称,于1924年在美国加州成立。是一个非盈利性的、由会员自行管理的组织,目前已在全球一百多个国家成立了上万个俱乐部。 *上述名词介绍来自百度百科与知乎。 (二)出现的学校 河北科技大学(河北-石家庄) 电子科技大学(四川-成都) 重庆邮电大学(重庆) 哈尔滨理工大学(黑龙江-哈尔滨) 桂林航天工业学院理学院(广西-桂林) 河南理工大学(河南-焦作) 河北北方学院(河北-张家口) 北方民族大学(宁夏-银川) 山西大学(山西-太原) 西安交通大学(陕西-西安) 西安电子科技大学(陕西-西安) 华中科技大学(湖北-武汉) 深圳大学(广东-深圳) 浙江大学(浙江-杭州) 湖南大学(湖南-长沙) 武汉大学(湖北-武汉) 广东技术师范大学(广东-广州) 西北民族大学(甘肃-兰州) 北京邮电大学(北京) 中国民航大学(天津) 广东机电职业技术学院(广东-广州) 长江大学(湖北-荆州) 华南理工大学(广东-广州) 包头铁道职业技术学院(内蒙古-包头) 重庆工程职业技术学院(重庆) 江苏大学(江苏-镇江) 南京邮电大学(江苏-南京) 华南理工大学广州学院(广东-广州) 长安大学(陕西-西安) 泉州师范学院(福建-泉州) 桂林电子科技大学(广西-桂林) 广西医科大学(广西-南宁) 华南农业大学(广东-广州) 山西农业大学(山西-晋中、太原) 南京大学金陵学院(江苏-南京) 广东石油化工学院(广东-茂名) 兰州交通大学(甘肃-兰州) 东华理工大学(江西-南昌、抚州) 中山大学南方学院(广东-广州) 广州大学(广东-广州) 中国矿业大学(北京) 南京工业大学(江苏-南京) 中北大学(山西-太原) 华中农业大学(湖北-武汉) 东莞理工学院(广东-东莞) 广东工业大学(广东-广州) 上海电机学院(上海) 南宁职业技术学院(广西-南宁) 台州职业技术学院(浙江-台州) 福州大学(福建-福州) 厦门理工学院(福建-厦门) 美国纽约大学(美国) 英国曼彻斯特大学(英国) 昆明理工大学(云南-昆明) 天津城建大学(天津) 北京工业大学(北京) 广东建设职业技术学院(广东-广州) 湖北师范大学(湖北-黄石) 许昌学院(河南-许昌) 西北工业大学(陕西-西安) (三)个人认为的特别题材 动物保护-鹦鹉AI端侧识别 健康管理-吃药小助 学习工具-口算助手 商业工具-软著助手 图像处理-摄影地图游客版 AI换脸-我是主角 个性服务-雨中送伞 情侣生活-恋人小清单 心情宣泄-苦海匿舟 走失找回-月见 AR躲猫猫-萌宠创造 文艺共鸣-轨道nighty night 心里健康-心暖农侬 模拟红包-红小包抽奖 攀岩健身-RedPoint 职校沟通-铁路生涯 酿酒乐趣-趣酿 盲人助力-盲小鹿 历史日历-历史上的今天 消防检查-火查查 情侣福音-情侣券 家庭互助-顾家 宠物关注-流浪猫速查手册 停车助手-我车呢 诗歌创作-AI写诗 智能家居-LoRa智能家居管理 智能招领-悦寻失物招领 你画我猜-画画的北鼻 随手反馈-城市预警系统 仿真识别-人脸识别虚拟仿真实验 智慧校园-ITD智慧校园 活动协调-哪天约 家庭物联-HomeAssistant 地热监测-流量计设备性能测试平台 (四)官方公布的复赛名单 校园赛道: [图片] 职业赛道: [图片] (五)官方公布的决赛名单 校园赛道: [图片] 职业赛道: [图片] (六)最终决赛成绩 校园赛道: [图片] 职业赛道: [图片]
2020-11-14 - 请教各位大佬,wx.getUserProfile接口获取信息问题?
想问各位大佬,wx.getUserProfile这个接口最近如何获取用户全部信息,我只获取了头像和昵称,
2021-11-12 - wx.getUserProfile(Object object)接口调用频率是什么呀?
wx.getUserProfile(Object object)最近在开发微信小程序绑定,请求比较频繁,报错VM886 WAService.js:2 invoke wx.getUserProfile too frequently 所以想问一下这个接口的请求频率是怎样的呢?
2022-03-25 - 获取小程序二维码getwxacodeunlimit出现41030?
返回报文如下:{"errcode":41030,"errmsg":"invalid page rid: 60ed0729-6826af96-2768e17d"} 确认 小程序页面没有问题!别的页面都能生成,就这个页面不行??
2021-07-13 - 教你怎么监听小程序的返回键
更新:2020年7月28日08:51:11 基础库2.12.0起,可以调用wx.enableAlertBeforeUnload监听原生右上角返回、物理返回以及wx.navigateBack时弹框提示 AIP详情请看: https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.enableAlertBeforeUnload.html //======================================== 怎么监听小程序的返回键? 应该有很多人想要监听用户的这个动作吧,但是很遗憾,小程序不会给你这个API的,那是不是就没辙了? 幸好我们还可以自定义导航栏,这样一来我们就可以监听用户的这一动作了。 什么?这你已经知道啦? 那好咱们就不说自定义导航栏的返回监听了,说一下物理返回和左滑?右滑?(不管了,反正是滑)返回上一页怎么监听。 监听物理返回 首先说一下这个监听方法的缺点,虽说是监听,但是还是无法真正意义上的监听并拦截来阻止页面跳转,页面还是会返回上一页,而后重新载入刚刚的页面,如果这不是你想要的,那可以不用往下看了 其次说一下用到什么东西: wx.onAppRoute、wx.showModal 最后是一些主要代码: 重写wx.showModal,主要是加个confirmStay参数和使wx.showModal Promise化 [代码]const { showModal } = wx; Object.defineProperty(wx, 'showModal', { configurable: false, // 是否可以配置 enumerable: false, // 是否可迭代 writable: false, // 是否可重写 value(...param) { return new Promise(function (rs, rj) { let { success, fail, complete, confirmStay } = param[0] param[0].success = (res) => { res.navBack = (res.confirm && !confirmStay) || (res.cancel && confirmStay) wx.setStorageSync('showBackModal', !res.navBack) success && success(res) rs(res) } param[0].fail = (res) => { fail && fail(res) rj(res) } param[0].complete = (res) => { complete && complete(res) (res.confirm || res.cancel) ? rs(res) : rj(res) } return showModal.apply(this, param); // 原样移交函数参数和this }.bind(this)) } }); [代码] 使用wx.onAppRoute实现返回原来的页面 [代码]wx.onAppRoute(function (res) { var a = getApp(), ps = getCurrentPages(), t = ps[ps.length - 1], b = a && a.globalData && a.globalData.pageBeforeBacks || {}, c = a && a.globalData && a.globalData.lastPage || {} if (res.openType == 'navigateBack') { var showBackModal = wx.getStorageSync('showBackModal') if (c.route && showBackModal && typeof b[c.route] == 'function') { wx.navigateTo({ url: '/' + c.route + '?useCache=1', }) b[c.route]().then(res => { if (res.navBack){ a.globalData.pageBeforeBacks = {} wx.navigateBack({ delta: 1 }) } }) } } else if (res.openType == 'navigateTo' || res.openType == 'redirectTo') { if (!a.hasOwnProperty('globalData')) a.globalData = {} if (!a.globalData.hasOwnProperty('lastPage')) a.globalData.lastPage = {} if (!a.globalData.hasOwnProperty('pageBeforeBacks')) a.globalData.pageBeforeBacks = {} if (ps.length >= 2 && t.onBeforeBack && typeof t.onBeforeBack == 'function') { let { onUnload } = t wx.setStorageSync('showBackModal', !0) t.onUnload = function () { a.globalData.lastPage = { route: t.route, data: t.data } onUnload() } } t.onBeforeBack && typeof t.onBeforeBack == 'function' && (a.globalData.pageBeforeBacks[t.route] = t.onBeforeBack) } }) [代码] 改造Page [代码]const myPage = Page Page = function(e){ let { onLoad, onShow, onUnload } = e e.onLoad = (() => { return function (res) { this.app = getApp() this.app.globalData = this.app.globalData || {} let reinit = () => { if (this.app.globalData.lastPage && this.app.globalData.lastPage.route == this.route) { this.app.globalData.lastPage.data && this.setData(this.app.globalData.lastPage.data) Object.assign(this, this.app.globalData.lastPage.syncProps || {}) } } this.useCache = res.useCache res.useCache ? reinit() : (onLoad && onLoad.call(this, res)) } })() e.onShow = (() => { return function (res) { !this.useCache && onShow && onShow.call(this, res) } })() e.onUnload = (() => { return function (res) { this.app.globalData = Object.assign(this.app.globalData || {}, { lastPage: this }) onUnload && onUnload.call(this, res) } })() return myPage.call(this, e) } [代码] 在需要监听的页面加个onBeforeBack方法,方法返回Promise化的wx.showModal [代码]onBeforeBack: function () { return wx.showModal({ title: '提示', content: '信息尚未保存,确定要返回吗?', confirmStay: !1 //结合content意思,点击确定按钮,是否留在原来页面,confirmStay默认false }) } [代码] 运行测试,Oj8K 是不是很简单,马上去试试水吧,效果图就不放了,静态图也看不出效果,动态图懒得弄,想看效果的自己运行代码片段吧 代码片段 https://developers.weixin.qq.com/s/hc2tyrmw79hg
2020-07-28 - 同一用户获取到的unionId不相同
这个问题可以按以下方式自查,举个例子: 1.小程序APPID:wx**********6c86a7 ——账号A 公众号APPID:wx**********8d6f47 ——账号B; 2.需要拿到相同的unionID,核实账号A和账号B 绑定同一个微信开放平台账号是:dl******fpt@sina.com ,所以同一个用户的unionid相同; 3.一般出现unionid不同的原因是:该openid不属于账号A,也不属于账号B,而是属于账号C或账号D,而账号C或账号D并没有绑定在同一个微信开放平台账号下,所以unionid不同。
2019-08-28 - 部分小程序用户auth.code2Session接口获取不到unionid的问题?
小程序和公众号都绑定了同一个开放平台。但是有部分用户通过auth.code2Session拿不到unionid。
2020-08-06 - 微信十年的产品思考
[视频] 微信十年,你和微信又有哪些故事呢? 欢迎在评论区分享交流。
2021-09-22 - 流量主一天你们能赚多少钱?
[图片] 小程序流量主的出现,无疑是解决小程序变现难的一个绝佳渠道。其意义不下于公众号流量主广告的上线。“有流量、变现难”本来是小程序开发者面前挥之不去的重重迷雾,而现在腾讯开放了小程序流量主,瞬间将小程序开发者们面前的迷雾拨开,他们能放心大胆地往前走。 我自认为我运营到很高了,但是有人一天1.9W+,将近2万,他们是怎么运营的?粉丝都是怎么来的? 有没有大神一起来探讨一下?
2020-01-06 - 请问 如何申请长期订阅消息?
我们小程序资质是私立医疗机构;现在一次性订阅消息不能满足我们的需求;请问如何申请长期订阅消息,申请长期订阅消息的模板是患者复诊提醒 [图片][图片][图片]
2021-06-04 - 区分小程序正式版,体验版,开发版
使用 wx.getAccountInfoSync 判断
2020-07-28 - 云函数“层”功能开发小结
项目中如果有多个云函数,它们经常会用到很多公共的代码模块,比如查询用户信息、鉴权等等。在小程序中,我们可以通过require导入这些公共模块。但云函数之间是互相独立的,每个云函数只能访问自己的代码包,我们需要手动把这些公共的代码模块复制到每个云函数中,容易造成文件混乱。“层”正是为了解决云函数间代码复用的问题。 “层”是什么 小程序开发文档中并没有“层”的介绍,不过我们可以在腾讯云开发文档中找到相关的介绍(传送门)。之前社区里也有大神分享过相关的文章(传送门),可以看到当时开发者工具创建的云开发环境并不能很好地支持“层”功能,这可能也是小程序开发文档没有“层”的相关介绍的原因。幸好,最近实测,开发者工具创建的云开发环境也可以正常使用“层”功能了。 简而言之,“层”就是每个云函数都可能访问的一个公共空间,它会在云函数启动时加载到云函数中。这样就可以保证每个云函数访问的都是同一个代码模块,不需要我们去手动同步代码文件。 “层”的创建和绑定 开发者工具并没有集成“层”功能,我们需要到腾讯云控制台来创建和管理。 第一步:使用小程序账号登录腾讯云控制台 [图片] 第二步:点击云开发CloudBase,选择环境 [图片] [图片] 第三步:选择云函数>层管理>新建 注意“层”的运行环境要和云函数相同,一般是Nodejs12.16,可以在“云函数管理”中查看云函数的运行环境。 [图片] [图片] 第四步:点击云函数管理,选择要绑定的云函数 [图片] 第五步:选择层管理>绑定,选择对应的层 [图片] [图片] “层”的访问 云函数触发时,“层”的代码包会加载到云函数中,这时云函数的目录结构是: [代码]var user 云函数代码(/var/user/) opt 层代码(/opt/) [代码] 这样我们就可以require导入我们的公共模块了。 举个例子,云函数的目录结构如下: [代码]var user index.js opt common.js [代码] 我们要在index.js中访问common.js文件,可以: [代码]const common = require('../../opt/common.js') // 云函数不支持“/”访问根目录 [代码] 因为云函数的环境变量包括“层”的路径,所以也可以: [代码]const common = require('common.js') // 直接引用文件名 [代码] “层”的调试 很可惜,开发者工具并不支持本地调试“层”,而且本地调试和云端运行的目录结构并不相同。下面是我的调试思路: 把“层”代码包放在云函数的根目录 [代码]opt common.js index.js [代码] 自定义环境变量ENV,根据ENV选择require的路径 [代码]// DEV:调试环境,引入云函数代码包里的opt文件夹 // PRO:生产环境,引入真正的“层” // 注意:本地调试不能获取环境变量 const common = require(process.env.ENV == 'PRO' ? '' : './opt/' + 'common.js') [代码] 不知大家还有没有其它思路,欢迎一起讨论。 多翻翻腾讯云的文档,说不定还有惊喜~ 相关文档 云开发层管理
2021-12-21 - 云开发入门
重磅打造的小程序学习路径课,从微信小程序到微信云开发体系化的学习,带来更加顺畅的学习体验。
2021-11-19 - 小程序微信认证认证审核问题汇总
1、微信认证申请入口 入口一:小程序账号后台:功能->微信认证 [图片] 入口二:小程序账号后台:设置->基本信息->微信认证->去认证; [图片] 入口三:小程序发布流程页 [图片] 2、小程序微信认证所需资料 微信认证选择对应认证主体类型,并提交相应的认证材料: [图片] 3、微信认证审核时间 微信认证费用支付完成之后1-3个工作日内完成。 4、认证状态和结果查看方式 请登录公众平台,从“设置->微信认证->查看“查看进度。 也可以拨打第三方审核公司的客服热线咨询审核进度。 5、微信审核失败费用是否退回? 除政府或部分组织(基金会、外国政府机构驻华办事处)可免费申请外,其他类型申请微信认证均需支付审核服务费用。这是用户基于腾讯提供的资质审核服务而支付的一次性费用,用户每申请一次认证服务需要支付一次审核服务费。无论认证成功或失败,都需要支付审核服务费。
2023-11-09 - 小程序基础库 2.20.1 更新
各位微信开发者: 小程序基础库 2.20.1 已经开始灰度开发者,请大家基于业务情况关注相关变更。如遇问题请及时在该帖下方留言或在小程序交流专区发表标题包含「基础库2.20.1」的帖子反馈。本次更新如下: 新增 API 小程序安卓端支持启停截屏/录屏接口 wx.setVisualEffectOnCapture 详情新增 API 小程序内嵌小程序能力 wx.openEmbeddedMiniProgram 详情新增 API getSystemInfo拆分为 wx.getSystemSetting / wx.getAppAuthorizeSetting / wx.getDeviceInfo / wx.getWindowInfo / wx.getAppBaseInfo新增 API 支持跳转系统设置 wx.openSystemBluetoothSetting / wx.openAppAuthorizeSetting新增 API 蓝牙主机模式支持获取 MTU 详情新增 API 支持获取局域网IP地址 wx.getLocalIPAddress 详情新增 API 查询蓝牙是否配对 wx.isBluetoothDevicePaired 详情更新 API 服务市场 invokeService 新增代扣参数 详情更新 API 蓝牙从机模式支持以 Beacon 模式广播 详情更新 API 地图组件叠加热力图、航线图、蜂窝图效果 详情更新 API 剪切板为空时,小程序粘贴不弹提示修复 框架 现网小游戏插件里wasm无法instantiate初始化修复 框架 工具上wx.onShow接口不在启动时触发修复 框架 工具地图 view 节点无法响应事件修复 组件 iOS 上增强 scroll-view scrollTo 部分机型失效修复 框架 工具上 scrollTo 不生效 微信团队 2021年10月21日
2021-10-25 - 获取小程序任何页面链接的方法
小程序不像网站,任何页面都可以复制出来链接。要访问某个页面,直接点击链接就可以了。其实小程序也是可以复制出链接。 不废话,马上上干货~! 1、首先进入小程序后台,把要获取链接的微信添加到项目成员。 [图片] [图片] 2、进入生成小程序码工具,添加获取链接的微信号。 不知道怎么进入生成小程序码工具,请看来一间上一篇文章:一个独特的小程序码生成方法。 [图片] 点“获取更多页面路径”打开窗口,然后输入上面添加的微信号点击“开启”按钮。如上图“开启入口成功”字样就会显示出来。这时代表这个微信号能复制出当前小程序的任意可显示页面的链接。 3、进入当前小程序,就可以获取到当前显示页面的链接。 [图片] 获取到小程序链接有什么用?请看看来一间上一篇文章。 最后再送出一个小彩蛋:其实小程序有个大原则:所见即所得! 就是你进入的页面,转发出去的页面也是当前你打开的页面。
2019-11-19 - 一个独特的小程序码生成方法
众所周知,小程序搭建好之后小程序码会在线上/线下频繁展示。但是很多时候不是每个人都有小程序后台下载权限。所以这个方法你务必掌握!不然说你玩过小程序,那只能呵呵了。 一般正常的小程序码下载都在这里: [图片] 不废话,干货马上开始! 1、你要知道这个小程序叫啥名字。 通过搜索进入小程序,然后获取到小程序的APPID。 [图片] [图片] [图片] 温馨提醒:这个APPID是可以长按复制的。 2、然后进入任意一个小程序后台。 这时小编想起周星驰电影的一个桥段:这是一只不一般的电筒,需要另一只电筒亮起它才能亮。 [图片] 然后粘贴上面复制出来的APPID,现在新版本名字也是可以搜索名称了。其实小编是想借个地方告诉你APPID的获取方法。 [图片] 点击进入下一步,就是进入显示小程序哪个页面了。 [图片] page/tabBar/index/index 复制上面这个路径进去点击确定,就是生成小程序主页的小程序码。下次教程小编再告诉大家怎么获取任意小程序页面的页面路径,从而生成小程序码。以防丢失重要教程,记得先关注我们哦!我们来一间每次发文章,系统都会通知你。 [图片] 到这一步你不会跟我说怎么没有下载按钮吧?如果真是这样,那你可以发明很多文中说到的“电筒”了!
2019-11-18 - 非常简单的长列表(无限上拉触底加载 onReachBottom)实现方案
我们知道小程序针对长列表有两个硬杠杠,一旦越界直接给白屏: 1、setData的数组数据不能超过1M。 2、DOM数不能太多,具体数据未知。 官方这样处理也不无道理,太长了本身性能确实也有问题。所以长列表一定要人为干预处理,不处理一直上拉加载肯定是不行的。 目前主流的处理方法有三种: 1、二维数组,就是把数据改为二维的,每一个分页数据作为一个一维数组的元素。这样处理,只解决了setData的问题,DOM的问题并未解决。并且把本来是一维的数据强行二维化,在很多逻辑处理上变得复杂。 2、官方提供了一个扩展组件recycle-view,但它要求item等高,存在局限性。https://developers.weixin.qq.com/miniprogram/dev/extended/component-plus/recycle-view.html 3、自行搭建骨架屏,类似于方案2的自研版本,根据自己的实际需要编写代码。实现成本非常高。 实现方案如下(太简单了,不提供代码示例): 1、思路:只保留最新的n页数据进行setData,每新加载一页数据,就舍弃最前面一页的数据。同时把第1页的数据保存起来,监听onPageScroll,如果发现用户拉回到了页面顶部,则舍弃所有数据,把第1页的数据setData回来。 2、举个例子:假设n=5,那么当加载了第6页数据时,第6页数据合并到数组尾部,把数组头部的第1页数据去掉,让setData的数据始终保持5页。这里有个细节要处理好,就是去除数据的时候先setData一次,新数据加载合并后,再setData一次,这样可以保证用户的scrollTop不会走位,停留在最新一条数据那个位置。 3、这个方案也存在一些弊端,看你实际项目中能否接受,主要有两个问题:a、用户如果倒着往回逐条浏览,体验是不连续的,因为中间一段我们已经舍弃掉了,如果拉到页面顶部时,将会出现直接回到第一条数据。b、去除数据的setData操作时,存在一定程度的闪屏现象。(针对问题a,应该可以解决,无非就是把数据再逐页塞回来,而不是像我的方案简单粗暴的回到第一页数据,如果项目有需要可以自行尝试。) 4、适用范围:比较适合信息处理类应用,比如后台管理系统。这类应用,往往头几屏内容就能找到信息,或者借助搜索,比较少会拉很多屏。而且往往处理完毕时是直接回到顶部的,不会逐条翻回去。所以这类应用只要保证不出白屏,一些小概率场景下存在一些几乎可以忽略的体验小瑕疵可以接受。信息浏览类应用,比如新闻应用,往往都是长列表浏览,小瑕疵就不一定能接受。
2020-10-28 - 写给学弟学妹的学习小程序经验总结
写给学弟学妹的学习小程序经验总结 此篇文章面向前端入门以及小程序新手,入门爬坑可以观看 我个人跟着教程写过一个电影小程序,然后就直接开始写比赛的小程序了,对小程序有一定认识,但理解还是比较浅的,如有错误欢迎批评指正。 学习小程序的前置知识 前端使用的是微信自定义的一套规范[代码]wxml[代码]+[代码]wxss[代码]+[代码]json[代码]+[代码]js[代码],其本质还是[代码]html[代码]+[代码]css[代码]+[代码]javascript[代码].打好基础才能快速学好框架。 编译器推荐:VS Code,有非常多的插件,代码补全,格式修正,颜色高亮,版本控制 推荐网站:MDN有标准语法文档方法函数忘记了可以去这个网站查,freecodecamp编程闯关、完成挑战 第一阶段:html,css,推荐书籍:Head First HTML与CSS(第2版)HTML5权威指南 CSS揭秘 CSS世界可以边看书或者视频边写代码。快速熟悉网页框架结构。 第二阶段:JavaScript,http这一阶段基础一定要打牢,前端的绝大部分都是以javascript为基本的。推荐书籍:JavaScript DOM编程艺术 (第2版)JavaScript高级程序设计(第3版)JavaScript语言精粹ES6标准入门(第3版)深入理解ES6如果觉得难可以先看视频,再看书,中间跟着写一些小demo,学完后做一个完整的网页(学习所有知识都可以按照此路径,视频:快速了解 > 书籍:深入探究 > 实践:理解巩固)。 扩展知识:学一点点linux和git对合作开发有更高的效率。 先学会了一些框架(vue,react)可以更快地上手小程序。 小程序的学习 官方学习视频《学做小程序》 官方学习文档《小程序微信官方文档》 通过看文档和教学视频学习小程序 入门指导 1.申请账号 进入小程序注册页 可以在小程序后台,依次点击「设置」->「开发设置」获取到这个「AppID」自己保存:AppID相当于小程序平台的身份证 2.安装开发工具 前往 开发者工具下载页面 稳定版 Stable Build (1.02.1904090) Windows 64 、 Windows 32 、 macOS 根据不同操作系统下载相应版本 3.创建项目 [图片] 4.在VS Code中编写代码,在小程序开发者工具里调试 VS Code官网下载:code.visualstudio.com/ 点击「扩展」,安装小程序插件推荐「minapp」「wxml」「wechat-snippet」,其他插件自行选择 [图片] 文件构成 小程序一般由下面四类文件组成: json:配置文件 小程序全局配置:「[代码]app.json[代码]」 [代码] //配置页面路径 "pages": [ "pages/index/index", "pages/logs/logs" ], //配置窗体样式 "window": { "backgroundTextStyle": "light", //顶部导航样式 "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" }, [代码] 开发工具配置:「[代码]project.config.json[代码]」 开发者工具的统一配置,界面设置以及云函数相关 单页面配置:「[代码]page.json[代码]」 对本页面的窗口表现进行配置,会覆盖app.json的window中相同的配置项 wxml:模板文件,AS:HTML 1.跟html很像,类比[代码]<div>[代码]=[代码]<view>[代码],[代码]<p>[代码]=[代码]<text>[代码],[代码]<a>[代码]=[代码]<navigator>[代码]等 2.与html不同的是,可以在标签中加判断或循环语句[代码]wx:if、else/wx:for[代码]还可以使用三元运算符等 3.在标签里使用[代码]{{motto}}[代码]可以读取当前页面JS文件[代码]data:{motto:'hello World'}[代码]data对象中的数据 4.在标签中通过[代码]bindtap/catch="functionName"[代码]冒泡/捕获绑定事件 wxss:样式文件,AS:CSS 1.[代码]2rpx[代码]=[代码]1px[代码]小程序根据不同屏幕大小,底层来换算像素单位 2.flex布局:推荐阮一峰老师的博客Flex 布局教程:语法篇 Flex 布局教程:实战篇 js:脚本逻辑文件 1.页面生命周期** [代码]// pages/life.js 页面初始化时,小程序自动给我们创立了生命周期函数 Page({ /** * 页面的初始数据,可以使用this.setData({ msg: "Hello World" })传入data对象wxml可以从中获取数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady: function () { }, /** * 生命周期函数--监听页面显示 */ onShow: function () { }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () { }, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { } }) [代码] 很多人说[代码]this.setData()[代码]传不进数据,有人回答在函数里先申明个[代码]var that=this[代码],这种回答很敷衍,提问人还是不会懂,治标不治本。推荐不懂的同学去了解一下this指向原理:this 永远指向最后调用它的那个对象,多看几篇技术文章this、apply、call、bind、Javascript 深入浅出 this 2.发起http请求 [代码]//仅为示例 wx.request({ url: 'http:'//test.php, data: { x: '', y: '' }, method:'GET'\'POST', header: { 'content-type': 'application/json' }, success (res) { console.log(res.data) } }) [代码] 通过请求后台接口,发送获取数据 3.用户登陆 基本每个小程序都少不了登陆流程 彻底搞懂小程序登陆流程 [图片] 个人小结 之前喜欢计算机,但是摸不到门路,大约一年前加入工作室,因为比较喜欢写完代码就看到界面交互的效果,确立了学习方向:前端。上学期入门了html,CSS ,JavaScript期间写了几个网页,巩固了一下基础.这学期写完工作室官网,刚学完ES6就开始小程序大赛了。 我们工作室是独立非学校、非盈利的计算机学习组织,主要学习互联网开发,前端后端,设计,三个方向,每周30小时学习打卡,一次学习经验分享会,让我们互相学习监督,共同成长。感谢前辈创业,学长引路,让我从单喜欢计算机到有了专业方向。 前辈传给我们,我们再教学弟学妹,我们有共同理想,共同爱好,并为之付出努力。我记得王小波在维也纳看三个青年在街头演奏的一席话:青年的动人之处,就在于勇气,和他们的远大前程。 希望能给学弟学妹们,前端刚入门者一些指导。 喜欢前端、计算机志同道合的朋友可以加WX交流学习经验:Jason-JCWu 更新分割线 几年前写的,目前已进入tx
2021-09-22 - 如何开通微信支付特约商户?
现在很多年轻人都选择在互联网创业, 创业想要实现收入, 那么势必要接入支付. 现在市面上使用支付的产品, 无疑是微信支付 和 支付宝支付. 大家都知道, 不管是微信支付, 还是支付宝支付, 他们的费率都是0.6%, 也就是你收款1万元, 支付宝或者微信公司 就要收取60元手续费, 可以说手续费还是不低的. 那么又能有可能降低手续费呢? 答案当然是有, 大家都应该知道, 线下零售超市, 他们的收款费率大都是0.38, 也就是1万元收费38元, 都低于0.6%, 作为互联网创业者, 还不如线下零售商, 那岂不是很low! 那么0.38%就是底线了吗? 其实不管是微信支付还是支付宝支付, 他们能开通的最低费率都是0.2%, 但是普通用户是申请不了的, 0.2%的费率 官方只授权自己的服务商, 服务商才能给商户开通最低0.2%的费率, 当然一般服务商是不会给商户开通0.2%最低费率的. 那样服务商就不赚钱了, 一般开通0.38%的费率, 服务商还能赚0.38%-0.2%=0.18%(万18元). 什么是"特约商户"? 服务商推荐开通的商户, 就不再是普通商户, 官方称之为"特约商户", 顾名思义 就是特别邀请的优质商户. 已经有商户了, 还能开通特约商户吗? 完全没有问题, 不管是个体户, 还是公司/企业, 一个营业执照可以开很多商户 ,一个主体有多个商户时, 会出现下面的选择. 登录微信支付后台的时候, 会让您选择进入那个商户. 开发接入的时候, 需要穿一个mch_id(商户号), 传入那个商户号, 收的钱就到那个商户里面. 小伙伴你懂了没? 下面有图可以看! 如何开通微信支付-特约商户, 并直接开通0.2%费率. 微信有一个名为[惠银助手]的小程序, 开通特约商户0.2%费率, 下面是一些开通流程, 给你最低费率, 希望您创业成功!!!! 步骤1 - 打开 [惠银助手] 小程序 微信搜索: 惠银助手, 打开惠银助手小程序, 或者直接扫码即可.
2021-05-21 - 微信小微商户/特约商户进件V3版本对接
今天我们来讲一下微信小微商户进件V3版本的接口对接。 首先我们来看一下官方的文档: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment/chapter3_1.shtml 根据文档提示,小微商户进件对接协议和特约商户是一样的,只是参数不一样。我们这里以小微商户说明。 首先引入JRE包,后面会用到。这里使用的是maven。 [图片] 上代码 ApplymentBo.java package com.pay.wechat.bo.small.v3; import java.io.ByteArrayInputStream; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Component; import com.util.OrderIDUtil; import com.pay.wechat.bo.small.v3.util.CertUtil; import com.pay.wechat.bo.small.v3.util.HttpUrlUtil; import com.pay.wechat.bo.small.v3.util.RsaEncryptUtil; import com.pay.contrib.apache.httpclient.util.PemUtil; import net.sf.json.JSONObject; /** * 小微商户进件V3版本<br> * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/applyment/chapter3_1.shtml * * @author libaibai * @version 1.0 2020年9月3日 */ @Component public class ApplymentBo { String business_code = OrderIDUtil.getOrderID(null); public void exe() throws Exception { // 获取微信平台证书 并解析方法在后面 String certString = CertUtil.getCertStr(); ByteArrayInputStream stringStream = new ByteArrayInputStream(certString.getBytes()); // 下面所有加密参数需要的对象 X509Certificate certx = PemUtil.loadCertificate(stringStream); // 超级管理员信息 Map<String, Object> contact_info = new HashMap<String, Object>(); String contact_name = RsaEncryptUtil.rsaEncryptOAEP("张三", certx); // 超级管理员姓名 String contact_id_number = RsaEncryptUtil.rsaEncryptOAEP("000000000000000000", certx); // 超级管理员身份证件号码 String mobile_phone = RsaEncryptUtil.rsaEncryptOAEP("13600000000", certx);// 联系手机 String contact_email = RsaEncryptUtil.rsaEncryptOAEP("zhangsan@sina.com", certx);// 联系邮箱 contact_info.put("contact_name", contact_name); contact_info.put("contact_id_number", contact_id_number); contact_info.put("mobile_phone", mobile_phone); contact_info.put("contact_email", contact_email); // 主体资料 String subject_type = "SUBJECT_TYPE_MICRO"; // 主体类型 String micro_biz_type = "MICRO_TYPE_STORE"; // 小微经营类型 String micro_name = "生态园停车"; // 门店名称 String micro_address_code = "440300"; // 门店省市编码 String micro_address = "南山区沙河西路科技生态园"; // 门店街道名称 String store_entrance_pic = "oO5EoYZsdukezw2NXUxEkb9vTU7PgOu5GyMpNVdMVj5aJAwD85_8kNpakg-s4917roa97XFJf0GPdBNHEvkyf0XPzrOjeKjoBYmEL_eSk7I"; // 门店门口照片 String micro_indoor_copy = "oO5EoYZsdukezw2NXUxEkb9vTU7PgOu5GyMpNVdMVj5aJAwD85_8kNpakg-s4917roa97XFJf0GPdBNHEvkyf0XPzrOjeKjoBYmEL_eSk7I"; // 店内环境照片 // 证件类型,IDENTIFICATION_TYPE_IDCARD String id_doc_type = "IDENTIFICATION_TYPE_IDCARD"; String id_card_copy = "oO5EoYZsdukezw2NXUxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdafxs"; // 身份证人像面照片 String id_card_national = "oO5EoYZsdukezwdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddHj3QDW_E"; // 身份证国徽面照片 String id_card_name = RsaEncryptUtil.rsaEncryptOAEP("张三", certx); // 身份证姓名 String id_card_number = RsaEncryptUtil.rsaEncryptOAEP("000000000000000000", certx); // 身份证号码 String card_period_begin = "2026-06-06"; // 身份证有效期开始时间示例值:2026-06-06 String card_period_end = "2026-06-06"; // 身份证有效期结束时间示例值:2026-06-06 Map<String, Object> subject_info = new HashMap<String, Object>(); // 主体资料 Map<String, Object> micro_biz_info = new HashMap<String, Object>(); // 小微商户辅助材料 Map<String, Object> micro_store_info = new HashMap<String, Object>(); // 门店场所信息 Map<String, Object> identity_info = new HashMap<String, Object>(); // 经营者身份证件 Map<String, Object> id_card_info = new HashMap<String, Object>(); // 身份证信息 micro_store_info.put("micro_name", micro_name); micro_store_info.put("micro_address_code", micro_address_code); micro_store_info.put("micro_address", micro_address); micro_store_info.put("store_entrance_pic", store_entrance_pic); micro_store_info.put("micro_indoor_copy", micro_indoor_copy); micro_biz_info.put("micro_biz_type", micro_biz_type); micro_biz_info.put("micro_store_info", micro_store_info); id_card_info.put("id_card_copy", id_card_copy); id_card_info.put("id_card_national", id_card_national); id_card_info.put("id_card_name", id_card_name); id_card_info.put("id_card_number", id_card_number); id_card_info.put("card_period_begin", card_period_begin); id_card_info.put("card_period_end", card_period_end); identity_info.put("id_doc_type", id_doc_type); identity_info.put("id_card_info", id_card_info); subject_info.put("subject_type", subject_type); subject_info.put("micro_biz_info", micro_biz_info); subject_info.put("identity_info", identity_info); // 经营资料 String merchant_shortname = "张三停车场"; // 商户简称 String service_phone = "0755222222"; // 客服电话 Map<String, Object> business_info = new HashMap<String, Object>(); business_info.put("merchant_shortname", merchant_shortname); business_info.put("service_phone", service_phone); // 结算规则 // 入驻结算规则ID;请选择结算规则ID,详细参见《费率结算规则对照表》 示例值:小微商户:703 String settlement_id = "703";// String qualification_type = "停车缴费"; // 所属行业;请填写所属行业名称,建议参见《费率结算规则对照表》 示例值:餐饮 Map<String, Object> settlement_info = new HashMap<String, Object>(); settlement_info.put("settlement_id", settlement_id); settlement_info.put("qualification_type", qualification_type); // 收款银行卡 // 账户类型 若主体为小微,可填写:经营者个人银行卡 枚举值: // BANK_ACCOUNT_TYPE_PERSONAL:经营者个人银行卡 // 示例值:BANK_ACCOUNT_TYPE_CORPORATE String bank_account_type = "BANK_ACCOUNT_TYPE_PERSONAL"; String account_name = RsaEncryptUtil.rsaEncryptOAEP("张三", certx); // 开户名称(该字段需进行加密处理) String account_bank = "建设银行"; // 开户银行开户银行,详细参见《开户银行对照表》 示例值:工商银行 String bank_address_code = "440300"; // 开户银行省市编码至少精确到市,详细参见《省市区编号对照表》 示例值:110000 // 1、“开户银行”为17家直连银行无需填写 // 2、“开户银行”为其他银行,则开户银行全称(含支行)和开户银行联行号二选一 // 3、需填写银行全称,如"深圳农村商业银行XXX支行",详细参见《开户银行全称(含支行)对照表》 // 示例值:施秉县农村信用合作联社城关信用社 String bank_name = ""; // 开户银行全称(含支行] String account_number = RsaEncryptUtil.rsaEncryptOAEP("62122xxxxxxxxxx332", certx); // 银行账号(该字段需进行加密处理) Map<String, Object> bank_account_info = new HashMap<String, Object>(); bank_account_info.put("bank_account_type", bank_account_type); bank_account_info.put("account_name", account_name); bank_account_info.put("account_bank", account_bank); bank_account_info.put("bank_address_code", bank_address_code); bank_account_info.put("bank_name", bank_name); bank_account_info.put("account_number", account_number); Map<String, Object> map = new HashMap<String, Object>(); map.put("business_code", business_code); map.put("contact_info", contact_info); map.put("subject_info", subject_info); map.put("business_info", business_info); map.put("settlement_info", settlement_info); map.put("bank_account_info", bank_account_info); try { String body = JSONObject.fromObject(map).toString(); String str = HttpUrlUtil.sendPost(body); System.out.println(str); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { ApplymentBo t = new ApplymentBo(); try { t.exe(); } catch (Exception e) { } } } httpUrlUtil.java package com.pay.wechat.bo.small.v3.util; import java.security.PrivateKey; import java.security.Signature; import java.util.Base64; import javax.ws.rs.core.Response; import org.apache.cxf.jaxrs.client.WebClient; import com.util.Config; import com.util.UUIDUtil; import okhttp3.HttpUrl; /** * HttpUrl工具类 * * @author libaibai * @version 1.0 2020年9月4日 */ public class HttpUrlUtil { public static String SCHEMA = "WECHATPAY2-SHA256-RSA2048"; public static String merchantId = Config.MCHIDSP; // 服务商 public static String POST = "POST"; public static String GET = "GET"; public static String host = "https://api.mch.weixin.qq.com"; public static String APPLY_PATH = "/v3/applyment4sub/applyment/"; // 申请单url public static String CERT_PATH = "/v3/certificates"; // 获取微信平台证书url public static String APPLY_QUERY_PATH = "/v3/applyment4sub/applyment/applyment_id/"; // 查询申请状态 /** * POST请求 */ public static String sendPost(String body) { String url = host + APPLY_PATH; try { // 获取微信平台商户证书序列号 String wxSerialNo = CertUtil.getCertSerialNo(); String authorization = getToken(POST, url, body); WebClient client = WebClient.create(host); client.reset(); client.header("Content-Type", "application/json; charset=UTF-8"); client.header("Accept", "application/json"); client.header("user-agent", "application/json"); client.header("Wechatpay-Serial", wxSerialNo); client.header("Authorization", authorization); client.path(APPLY_PATH); Response r = client.post(body); return r.readEntity(String.class); } catch (Exception e) { return null; } } /** * get请求 */ public static String sendGet() { // 请求URL String url = host + CERT_PATH; try { String authorization = getToken(GET, url, ""); WebClient client = WebClient.create(host); client.reset(); client.header("Content-Type", "application/json; charset=UTF-8"); client.header("Accept", "application/json"); client.header("User-Agent", "application/json"); client.header("Authorization", authorization); client.path(CERT_PATH); Response r = client.get(); return r.readEntity(String.class); } catch (Exception e) { e.printStackTrace(); return null; } } /** * get请求 */ public static String sendGet(String applymentId) { // 请求URL String url = host + APPLY_QUERY_PATH + applymentId; try { String authorization = getToken(GET, url, ""); WebClient client = WebClient.create(host); client.reset(); client.header("Content-Type", "application/json; charset=UTF-8"); client.header("Accept", "application/json"); client.header("User-Agent", "application/json"); client.header("Authorization", authorization); client.path(APPLY_QUERY_PATH + applymentId); Response r = client.get(); return r.readEntity(String.class); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取加密串 * * @param method * @param url * @param body * @return */ public static String getToken(String method, String url, String body) { String nonceStr = UUIDUtil.getUUID32(); long timestamp = System.currentTimeMillis() / 1000; HttpUrl httpUrl = HttpUrl.parse(url); String message = buildMessage(method, httpUrl, timestamp, nonceStr, body); String signature = null; String certificateSerialNo = null; try { signature = sign(message.getBytes("utf-8")); certificateSerialNo = CertUtil.getSerialNo(""); } catch (Exception e) { e.printStackTrace(); } return SCHEMA + " mchid=\"" + merchantId + "\"," + "nonce_str=\"" + nonceStr + "\"," + "timestamp=\"" + timestamp + "\"," + "serial_no=\"" + certificateSerialNo + "\"," + "signature=\"" + signature + "\""; } /** * 得到签名字符串 */ public static String sign(byte[] message) throws Exception { Signature sign = Signature.getInstance("SHA256withRSA"); PrivateKey privateKey = CertUtil.getPrivateKey(); sign.initSign(privateKey); sign.update(message); return Base64.getEncoder().encodeToString(sign.sign()); } public static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) { String canonicalUrl = url.encodedPath(); if (url.encodedQuery() != null) { canonicalUrl += "?" + url.encodedQuery(); } return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n"; } } CertUtil.java package com.pay.wechat.bo.small.v3.util; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import org.apache.commons.codec.binary.Base64; import net.sf.json.JSONArray; import net.sf.json.JSONObject; /** * 证书工具类 * * @author libaibai * @version 1.0 2020年9月4日 */ public class CertUtil { // 微信证书私钥路径(从微信商户平台下载,保存在本地) public static String APICLIENT_KEY = "G:\\workspace\\dlysw\\src\\main\\resources\\conf\\cert\\apiclient_key.pem"; // 微信商户证书路径(从微信商户平台下载,保存在本地) public static String APICLIENT_CERT = "G:\\workspace\\dlysw\\src\\main\\resources\\conf\\cert\\apiclient_cert.pem"; /** * 获取私钥。 * * @param apiclient_key 私钥文件路径 (required) * @return 私钥对象 */ public static PrivateKey getPrivateKey() throws IOException { String content = new String(Files.readAllBytes(Paths.get(APICLIENT_KEY)), StandardCharsets.UTF_8); try { String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", ""); KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey))); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("当前Java环境不支持RSA", e); } catch (InvalidKeySpecException e) { throw new RuntimeException("无效的密钥格式"); } } /** * 获取商户证书。 * * @param filename 证书文件路径 (required) * @return X509证书 */ public static X509Certificate getCertificate(String filename) throws IOException { InputStream fis = new FileInputStream(APICLIENT_CERT); try (BufferedInputStream bis = new BufferedInputStream(fis)) { CertificateFactory cf = CertificateFactory.getInstance("X509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(bis); cert.checkValidity(); return cert; } catch (CertificateExpiredException e) { throw new RuntimeException("证书已过期", e); } catch (CertificateNotYetValidException e) { throw new RuntimeException("证书尚未生效", e); } catch (CertificateException e) { throw new RuntimeException("无效的证书文件", e); } } /** * 获取商户证书序列号 * * @param certPath 获取商户证书序列号 传递商号证书路径 apiclient_cert * @return * @throws IOException */ public static String getSerialNo(String certPath) throws IOException { X509Certificate certificate = getCertificate(certPath); return certificate.getSerialNumber().toString(16).toUpperCase(); } /** * 获取微信平台证书序列号 * * @return * @throws Exception */ public static String getCertSerialNo() throws Exception { try { String str = HttpUrlUtil.sendGet(); System.out.println(str); JSONObject json = JSONObject.fromObject(str); JSONArray jsonArray = JSONArray.fromObject(json.optString("data")); JSONObject jsonObject = jsonArray.getJSONObject(0); return jsonObject.optString("serial_no"); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 获取微信平台证书 * * @return * @throws Exception */ public static String getCertStr() throws Exception { try { String str = HttpUrlUtil.sendGet(); JSONObject json = JSONObject.fromObject(str); JSONArray jsonArray = JSONArray.fromObject(json.optString("data")); JSONObject jsonObject = jsonArray.getJSONObject(0); JSONObject jsonCert = JSONObject.fromObject(jsonObject.optString("encrypt_certificate")); String certKeyString = AesUtil.decryptToString(jsonCert.getString("associated_data").getBytes(), jsonCert.getString("nonce").getBytes(), jsonCert.getString("ciphertext")); return certKeyString; } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { try { System.out.println(CertUtil.getCertStr()); } catch (Exception e) { e.printStackTrace(); } } } AesUtil.java package com.dlysw.pay.wechat.bo.small.v3.util; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import com.dlyspublic.util.Config; /** * * @author libaibai * @version 1.0 2020年9月8日 */ public class AesUtil { public static final int TAG_LENGTH_BIT = 128; public static byte[] aesKey = Config.AES_KEY_APIV3.getBytes(); // APIv3密钥 public static String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws Exception { try { Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); SecretKeySpec key = new SecretKeySpec(aesKey, "AES"); GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce); cipher.init(Cipher.DECRYPT_MODE, key, spec); cipher.updateAAD(associatedData); return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8"); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new IllegalStateException(e); } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { throw new IllegalArgumentException(e); } } } ok,直接运行ApplymentBo.java里面的main方法,得到返回结果 {"applyment_id": xxxxxxxxxxxxxx} 就表示进件成功了,我们登陆到商户平台看看。创建员工=API的就是刚才我们申请成功的。 [图片] 最后,我们也把状态查询的代码也贴一下 ApplymentQueryBo.java package com.pay.wechat.bo.small.v3; import org.springframework.stereotype.Component; import com.pay.wechat.bo.small.v3.util.HttpUrlUtil; /** * 小微商户进件查询 * * @author libaibai * @version 1.0 2020年9月8日 */ @Component public class ApplymentQueryBo { /** * 执行 * * @param applymentId 申请单号 * @return */ public String query(String applymentId) { String str = HttpUrlUtil.sendGet(applymentId); System.out.println(str); return str; } public static void main(String[] args) { String applymentId = "200000xxxxxxxxxx"; ApplymentQueryBo b = new ApplymentQueryBo(); b.query(applymentId); } } 返回成功: {"applyment_id":200000xxxxxxxxxx,"applyment_state":"APPLYMENT_STATE_TO_BE_SIGNED","applyment_state_msg":"请超级管理员使用微信打开返回的“签约链接”,根据页面指引完成签约","audit_detail":[],"business_code":"WEB|1590030703","sign_url":"https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQGb7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyeWZaMDl3b3JlUjIxbG9PLU52Y1YAAgRY5VZfAwQAjScA","sub_mchid":"15947111111"}
2020-09-11 - 个人微信支付新手攻略整理
前言: 虽然有部分微信支付对接经验,但在整个微信支付生态中,我自己也是新手。 此文用来制作新手攻略,以及微信支付知识的梳理记录。 一、【入门问题篇】 入门级的几个初级问题。 1,申请接入微信支付要花钱吗? 申请费用:无 交易服务费:根据商家经营类目判定,0.6%-1%不等 费率与结算周期说明:https://kf.qq.com/faq/140225MveaUz1501077rEfqI.html 2,我该去哪申请? 微信支付商户平台:https://pay.weixin.qq.com/ 3,我们有APP、公众号、小程序等多个应用,需要申请几个商户号? 申请1个商户号即可,都关联同一个商户号。 4,需要写代码进行支付对接吗? 多数支付都需要商家有开发能力,进行代码研发; 也有无需开发的,比如微信收款商业版。 5,申请微信支付需要哪些企业信息? 一般需要营业执照、对公账号、法人证件等。 6,各种微信支付对接都涉及哪些平台网站? 微信商户平台(商户号):https://pay.weixin.qq.com/ 微信公众平台(公众号、小程序):https://mp.weixin.qq.com/ 企业微信平台:https://work.weixin.qq.com/ 二、【场景选择篇】 这需要根据你们的业务场景,申请接入对应的微信支付。 官方指引截图:https://pay.weixin.qq.com/static/applyment_guide/applyment_index.shtml [图片] 场景 前提 对接支付 是否需开发 文档地址 线下场所 付款码支付 需要 开发文档 JSAPI支付 需要 开发文档 微信收款商业版 不需要 文档地址 公众号 已做微信认证;服务号、政府或媒体订阅号。 JSAPI支付 需要 开发文档 小程序 已做微信认证的小程序。 小程序支付 需要 开发文档 PC网站 网站域名已ICP备案。 JSAPI支付 需要 开发文档 Native支付 需要 开发文档 APP 微信开放平台创建APP,且平台已认证。 APP支付 需要 开发文档 企业微信 企业微信平台注册,且平台已认证。 向员工发红包 需要 开发文档 向员工付款 需要 开发文档 向员工收款 需要 开发文档 手机网站(非微信环境) H5支付 需要 开发文档 三、【业务流程篇】 简要业务实现逻辑描述。 大体流程: 商家系统:通过各种处理(预订单、二维码等),向用户展示收款页面; 用户:付款支付; 微信系统:异步通知商家服务器; 商家系统:处理用户付款后续。 以JSAPI支付为例,下图来自官方。 [图片] 四、【运营工具篇】 你可能感兴趣的: 现金红包: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=hongbao 代金券: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=coupon 立减与折扣: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=minus 企业付款到零钱: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=wallet 分账: https://pay.weixin.qq.com/static/product/product_intro.shtml?name=cmn 五、【高手进阶篇】 社区网友文章推荐: 1,如何用十个月时间,做出一款迄今为止无法超越的微信支付SDK基础开发包? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/000886b054c7708ae8ebcc04b5b013 2,ASP.NET Core 微信支付? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/0000aef5b20b002a02fb5a9f75b013 3,微信支付商户入门(合集)最后更新时间2021年4月5号? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/000ce0be104fe8db37fbf478b5b813 4,「干货分享」一文了解微信优惠券产品(卡券、代金券、商家券)? - 微信开放社区 https://developers.weixin.qq.com/community/pay/article/doc/000460b5934fd0f7f1eb902a251013 5,真香:一行命令即可体验「微信支付」全系接口能力? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000e264b100a88609bebe202856413 6,订单支付成功,但是一直未收到微信的支付成功回调通知? - 微信开放社区 https://developers.weixin.qq.com/community/develop/doc/000a8e42b54488af574b1f48156809 7,搞懂微信支付 v3 接口规则-【附Java源码】? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000cca8440c6a0dca61a3efb053c13 8,微信支付后默认关注公众号与推荐关注公众号规则? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0008c6203446a0dc706ba798f51c13 9,微信支付普通分账、服务商分账申请高比例流程及材料(4月8号更新)? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00042e3a5b4d78f5f06bcdfb951c13 10,云开发微信支付配置添加商户号后,绑定状态为“待模板消息确认”如何处理?? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0004e0e32bcf006ab06bdca4f56813 11,微信支付商户免充值代金券接口升级验收指引(一)用例组合1003+1004+1005? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0000c6941647a085d6fbe0fb256013 12,申请退款API 所使用资金对应的资金账户类型区别? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00042215948a6895ecfb44b935d013 13,创建代金券接口报错:“可用商户不符合规则,请检查” 是什么原因? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00064aac3c00b075e8fb57c0c54c13 14,发送失败,此请求可能存在风险,已被微信拦截,是什么原因? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0004c65f0640804db3fba1feb56413 15,V3调起支付报错:“支付失败,请稍后重试” 解决方案? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000482f9ce03e847faebc2c0756413 16,公众号支付报错:“当前页面的URL未注册”? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0002cc472406c8f0e7eb09cfa54c13 17,企业付款到零钱API钱没到账该如何处理? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00082a437648f8b0daebad6b05b013 18,收不到微信支付回调通知解决方案? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000cc28e044630e65deba58ad56c13 19,openid和appid不匹配该如何解决? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/00080a39a30378f34eebe89575b013 20,图片上传(营销)demo_PHP版本? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0008aea4170db86b1aeba260a5b413 六、【社区支付专区篇】 有支付问题可以到微信开放社区发问。 专区地址:https://developers.weixin.qq.com/community/pay 官方介绍:【微信支付新人必读】智慧的提问,快速的解答? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/0004a8c574082063ab3b2703751813 感谢阅读!
2021-05-10 - 微信支付服务商新手宝典
如何成为微信支付服务商?特约商户快速如何进件?快来看看服务商新手宝典。
2021-11-23 - 微信公众平台用户信息相关接口调整公告
微信公众平台为开发者提供了用户授权登录功能及相关接口,以便开发者为用户提供便捷的使用体验。 根据相关法律法规,为进一步规范开发者调用用户信息相关接口或功能,保障用户合法权益,平台将对用户信息相关功能及接口进行调整,具体如下: 一、相关接口调整: 1、小程序与小游戏获取用户信息相关接口:不再返回用户性别及地区信息; 能力参考:小程序用户信息 、小游戏用户信息; 2、 公众号用户信息获取接口:不再返回用户性别及地区信息; 能力参考:公众号用户信息; 3、 Open平台授权接口:包括App授权登录、公众号H5授权登录、网站扫码授权登录,不再返回用户性别及地区信息; 能力参考:移动应用、网站应用、第三方平台; 本次改造调整生效后,所述涉及字段返回值将按如下规则生效: [图片] *注:字段名均保持不变,小程序与小游戏获取用户信息接口“用户性别”字段名为gender;Open 平台授权接口“用户性别”字段名为 sex 二、相关功能调整: 1、 公众号个性化菜单功能:不再提供基于性别/地区设置个性化菜单的能力; 能力参考:个性化菜单接口; 2、公众号后台粉丝列表:粉丝列表等不再展示用户的性别信息; 涉及功能页面:公众平台帐号管理后台-用户管理/留言管理/赞赏/视频弹幕/消息; 3、服务号粉丝列表筛选:不再提供基于地区筛选粉丝的能力; 涉及功能页面:公众平台帐号管理后台-对话能力-客户管理。 平台预计10月20日完成调整,请开发者及时进行调整适配,避免影响相关服务及用户体验。 微信团队 2021年09月26日
2023-09-26 - 小程序导航栏出现返回首页按钮
目前返回首页按钮出现的条件为(需同时满足): 1. 使用了默认导航栏样式(非 custom) 2. 不是首页或 tabbar 页面(在 app.json 中定义的) 3. 是页面栈最底层页面 如果是开发者自己手写的 tabbar 导致的问题,需要在页面的 onShow 中调用 wx.hideHomeButton() https://developers.weixin.qq.com/miniprogram/dev/api/ui/navigation-bar/wx.hideHomeButton.html手动隐藏返回首页按钮。
2019-09-27 - (3)强制更新
背景 此前有开发者反馈小程序发布新版本后,新版本覆盖率比较慢,因为小程序的更新机制是异步的,部分用户不会马上应用上新版本。 小程序启动会有两种情况,一种是「冷启动」,一种是「热启动」。 假如用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需将后台态的小程序切换到前台,这个过程就是热启动;冷启动指的是用户首次打开或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动。 小程序的异步更新发生在冷启动过程,当发现新版本后,会异步下载新版本的代码包,但不会马上应用上最新版本,需要等小程序下一次冷启动,才会应用上新版本。 解决思路为了解决这个问题,我们内部也经历了数个方案的讨论,这里简单介绍下: 1. 同步检查更新(放弃):可能是最直接的解决思路,但主要问题是会影响小程序的启动速度,当下小程序的更新迭代是非常频繁的,部分用户可能每次启动都命中更新,如果需要同步检查更新+同步下载新的版本,那将会影响这部分用户的启动体验。 2. 模块热替换(放弃):从技术上来说,这是最好的方案,小程序运行起来后,在打开新页面时,马上应用新版本里的页面,但这就会存在新旧逻辑、页面共存问题,对于开发者来说,反而更不好处理,特别是涉及到全局变量时,情况会更复杂,对于我们已有的框架来说,也是一个大挑战,不过这个也是我们之后努力的方向。 3. 定时 check 新版本(目前方案):6.6.3 及以上版本的客户端,会定时 check 最近使用过的小程序是否有发布新版本;如果有,下次打开的时候会同步更新新版本再打开。这可以保证在新版本发布 24 小时后,所有小程序都能使用最新版本。(这部分是微信客户端自身优化,开发者无需关心) 4. 异步更新 + 强制更新(目前方案):同步检查更新与模块热替换两者之间的折衷方案,即还是维持异步更新机制,在异步下载完小程序代码包后,提供重启小程序的能力,这样在遇到紧急问题时可以马上解决。 异步更新 + 强制更新方案介绍从基础库 1.9.90 开始,我们提供了 wx.getUpdateManager 接口,使用该接口,可以获知是否有新版本小程序、新版本是否下载好以及应用新版本的能力。 当小程序冷启动时,会自动向微信后台请求新版本信息,如果有新版本,会马上触发新版本的下载。开发者可以通过 wx.getUpdateManager,获知当前更新的状态。 wx.getUpdateManager 接口会返回一个 UpdateManager 实例,UpdateManager 包含了三个回调: 1. onCheckForUpdate:当小程序向后台请求完新版本信息,会通知这个版本告知检查结果 2. onUpdateReady:当新版本下载完成,会回调这个事件 3. onUpdateFailed: 当新版本下载失败,会回调这个事件 还有重启应用新版本的接口: 1. applyUpdate:当新版本下载完成(onUpdateReady),调用该方法会强制当前小程序应用上新版本并重启 具体示例: [代码]// wx.getUpdateManager 在 1.9.90 才可用,请注意兼容[代码] [代码]const updateManager = wx.getUpdateManager()[代码] [代码]updateManager.onCheckForUpdate(function[代码] [代码](res) {[代码] [代码] // 请求完新版本信息的回调[代码] [代码] console.log(res.hasUpdate)[代码] [代码]})[代码] [代码]updateManager.onUpdateReady(function[代码] [代码]() {[代码] [代码] wx.showModal({[代码] [代码] title: '更新提示',[代码] [代码] content: '新版本已经准备好,是否马上重启小程序?',[代码] [代码] success: function[代码] [代码](res) {[代码] [代码] if[代码] [代码](res.confirm) {[代码] [代码] // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启[代码] [代码] updateManager.applyUpdate()[代码] [代码] }[代码] [代码] }[代码] [代码] })[代码] [代码]})[代码] [代码]updateManager.onUpdateFailed(function[代码] [代码]() {[代码] [代码] // 新的版本下载失败[代码] [代码]})[代码] 更详细信息可以参考 UpdateManager 的详细文档 最佳实践从用户体验上来说,我们还是建议只在非常必要时才强制用户重启更新,例如出现线上紧急 BUG。通常情况下,可以选通过 wx.showModal 弹出选择框让用户选择是否重启更新(实现请参考示例代码)。 如何调试最新版本的微信开发者工具提供了强制更新的调试能力,通过编译模式 - 编辑编译模式 - 勾上「下次编译时模拟更新」即可在开发者工具上调试强制更新功能。 最新开发者工具下载链接 点我。
2022-08-08 - 社区每周 |基础库2.18.0更新、IOS和安卓新版众测及上周问题反馈(6.14-6.18)
各位微信开发者: 以下是微信云托管启动公测、小程序基础库2.18.0更新、IOS和安卓新版众测及上周我们在社区收到的问题反馈与需求的处理进度,希望同大家一同打造小程序生态。 微信云托管启动公测:宣讲会预约中微信云托管是由微信团队联合腾讯云推出的后端项目全托管服务。对于微信生态应用开发采用前后端分离架构的场景,云托管可做到免运维免服务器管理,从代码管理到CI/CD流水线部署发布,提供全链路、低成本、企业级的云原生解决方案。 [图片] 小程序基础库2.18.0更新 小程序基础库 2.18.0 已经开始灰度开发者,请大家基于业务情况关注相关变更。如遇问题请及时在该帖下方留言或在小程序交流专区发表标题包含「基础库2.18.0」的帖子反馈。本次更新如下: 新增 API 新增 wx.createWebAudioContext 接口新增 API 支持 TCP socket 接口更新 API wx.getGroupEnterInfo 新增支持在群聊小程序消息卡片、群待办小程序启动时使用更新 API getLaunchOptionsSync & getEnterOptionsSync 新增 chatType 字段用于聊天场景打开小程序区分聊天类型更新 API 支持订阅消息语音提醒更新 API 扩展 UDP 接口,增加 setTTL 接口更新 API wx.createInnerAudioContext 支持使用 WebAudio 作为底层音频驱动修复 框架 暗黑模式下,input 样式会被 color 属性值覆盖修复 框架 修复 App.onShow 的参数 encode 问题点击查看原公告 微信团队邀请开发者参与内部体验(安卓微信8.0.7) 本次更新概要如下小程序 fix 社区反馈:小程序分享图片不显示video播放流量优化等,需关注video功能是否正常小程序wasm注入优化,使用了wasm能力的小程序开发者需关注启动阶段表现优化MediaContainer容器导出速度小游戏 小游戏直播部分bugfix,需关注直播部分体验小游戏性能优化方案物理部分bugfix,使用了该方案的开发者需关注游戏运行情况小游戏wasm注入优化,使用了wasm能力的小游戏开发者需关注启动阶段表现video播放流量优化等,需关注video功能是否正常请基于以下提供的资源体验。使用过程中若发现问题,欢迎点击进入微信开放社区 #微信客户端内测 主页发表标题包含「微信8.0.7」的问答帖子反馈交流。 [图片] (扫描二维码下载) 如有需要,可查看并转发原公告:《微信团队邀请开发者参与内部体验(安卓微信8.0.7)》 微信团队邀请开发者参与内部体验(iOS微信8.0.8) 本次更新概要如下 直播SDK底层重构录音和音乐混合使用的场景需要关注一下是否符合预期开屏广告优化,流量主需要关注一下开屏广告是否正常wcwss优化 * 体验需识别下方二维码报名,若报名成功,则三天内会收到内测推送,内测名额8000人 [图片] 请基于以上提供的资源体验。使用过程中若发现问题,欢迎点击进入微信开放社区 #微信客户端内测 主页发表标题包含「微信iOS 8.0.8」的问答帖子反馈交流,发帖时建议提供以下信息方便定位问题: 1.手机型号 2.手机操作系统版本 3.必要时可提供代码片段 如有需要,可查看并转发原公告:《微信团队邀请开发者参与(iOS微信8.0.8内部体验)》 上周问题反馈和处理进度(6.14-6.18) 已修复的问题调试器查看样式时无法点击wxss文件跳转的问题 查看详情 公众号编辑页面空白的问题 查看详情 文章里的音乐无法播放或点开的问题 查看详情 修复中的问题 部分安卓手机chooseVideo和chooseMedia选择视频时可以通过选择界面右上角的搜索选择照片 查看详情 安卓点击 input 搜狗输入法悬浮态闪退 查看详情 需求反馈需求评估中官方什么时候能 100% 支持 TypeScript 查看详情 微信团队 2021.6.25
2021-06-25 - 搞懂微信支付 v3 接口规则-【附Java源码】
简介 为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付API v3。 其实还要一个主要因素是「为了符合监管的要求」。 主要是为了符合监管的要求,保证更高的安全级别。《中华人民共和国电子签名法》、《金融电子认证规范》及《非银行支付机构网络支付业务管理办法》中规定 “电子签名需要第三方认证的,由依法设立的电子认证服务提供者提供认证服务。”,所以需使用第三方 CA 来确保数字证书的唯一性、完整性及交易的不可抵赖性。 支付宝支付也是如此,从之前的「普通公钥方式」新增了 「公钥证书方式」。今天的主角是微信支付 Api v3 这里就不展开讲支付宝支付了。 微信支付 Api v3 接口规则 官方文档 v2 与 v3 的区别 V3 规则差异 V2 JSON 参数格式 XML POST、GET 或 DELETE 提交方式 POST AES-256-GCM加密 回调加密 无需加密 RSA 加密 敏感加密 无需加密 UTF-8 编码方式 UTF-8 非对称密钥SHA256-RSA 签名方式 MD5 或 HMAC-SHA256 微信支付 Api-v2 版本详细介绍请参数之前博客 微信支付,你想知道的一切都在这里 干货多,屁话少,下面直接进入主题,读完全文你将 Get 到以下知识点 如何获取证书序列号 非对称密钥 SHA256-RSA 加密与验证签名 AES-256-GCM 如何解密 API 密钥设置 请登录商户平台进入【账户中心】->【账户设置】->【API安全】->【APIv3密钥】中设置 API 密钥。 具体操作步骤请参见:什么是APIv3密钥?如何设置? 获取 API 证书 请登录商户平台进入【账户中心】->【账户设置】->【API安全】根据提示指引下载证书。 具体操作步骤请参见:什么是API证书?如何获取API证书? 按照以上步骤操作后你将获取如下内容: apiKey API 密钥 apiKey3 APIv3 密钥 mchId 商户号 apiclient_key.pem X.509 标准证书的密钥 apiclient_cert.p12 X.509 标准的证书+密钥 apiclient_cert.pem X.509 标准的证书 请求签名 如何生成签名参数?官方文档 描述得非常清楚这里就不啰嗦了。 示例代码 构造签名串 [代码] /** * 构造签名串 * * @param method {@link RequestMethod} GET,POST,PUT等 * @param url 请求接口 /v3/certificates * @param timestamp 获取发起请求时的系统当前时间戳 * @param nonceStr 随机字符串 * @param body 请求报文主体 * @return 待签名字符串 */ public static String buildSignMessage(RequestMethod method, String url, long timestamp, String nonceStr, String body) { return new StringBuilder() .append(method.toString()) .append("\n") .append(url) .append("\n") .append(timestamp) .append("\n") .append(nonceStr) .append("\n") .append(body) .append("\n") .toString(); } [代码] 构造 HTTP 头中的 Authorization [代码]/** * 构建 v3 接口所需的 Authorization * * @param method {@link RequestMethod} 请求方法 * @param urlSuffix 可通过 WxApiType 来获取,URL挂载参数需要自行拼接 * @param mchId 商户Id * @param serialNo 商户 API 证书序列号 * @param keyPath key.pem 证书路径 * @param body 接口请求参数 * @param nonceStr 随机字符库 * @param timestamp 时间戳 * @param authType 认证类型 * @return {@link String} 返回 v3 所需的 Authorization * @throws Exception 异常信息 */ public static String buildAuthorization(RequestMethod method, String urlSuffix, String mchId, String serialNo, String keyPath, String body, String nonceStr, long timestamp, String authType) throws Exception { // 构建签名参数 String buildSignMessage = PayKit.buildSignMessage(method, urlSuffix, timestamp, nonceStr, body); // 获取商户私钥 String key = PayKit.getPrivateKey(keyPath); // 生成签名 String signature = RsaKit.encryptByPrivateKey(buildSignMessage, key); // 根据平台规则生成请求头 authorization return PayKit.getAuthorization(mchId, serialNo, nonceStr, String.valueOf(timestamp), signature, authType); } /** * 获取授权认证信息 * * @param mchId 商户号 * @param serialNo 商户API证书序列号 * @param nonceStr 请求随机串 * @param timestamp 时间戳 * @param signature 签名值 * @param authType 认证类型,目前为WECHATPAY2-SHA256-RSA2048 * @return 请求头 Authorization */ public static String getAuthorization(String mchId, String serialNo, String nonceStr, String timestamp, String signature, String authType) { Map<String, String> params = new HashMap<>(5); params.put("mchid", mchId); params.put("serial_no", serialNo); params.put("nonce_str", nonceStr); params.put("timestamp", timestamp); params.put("signature", signature); return authType.concat(" ").concat(createLinkString(params, ",", false, true)); } [代码] 拼接参数 [代码] public static String createLinkString(Map<String, String> params, String connStr, boolean encode, boolean quotes) { List<String> keys = new ArrayList<String>(params.keySet()); Collections.sort(keys); StringBuilder content = new StringBuilder(); for (int i = 0; i < keys.size(); i++) { String key = keys.get(i); String value = params.get(key); // 拼接时,不包括最后一个&字符 if (i == keys.size() - 1) { if (quotes) { content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"'); } else { content.append(key).append("=").append(encode ? urlEncode(value) : value); } } else { if (quotes) { content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"').append(connStr); } else { content.append(key).append("=").append(encode ? urlEncode(value) : value).append(connStr); } } } return content.toString(); } [代码] 从上面示例来看我们还差两个参数 serial_no 证书序列号 signature 使用商户私钥对待签名串进行 SHA256 with RSA 签名 如何获取呢?不要着急,容我喝杯 「89年的咖啡」提提神。 获取证书序列号 通过工具获取 openssl x509 -in apiclient_cert.pem -noout -serial 使用证书解析工具 https://myssl.com/cert_decode.html 通过代码获取 [代码]// 获取证书序列号 X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream("apiclient_cert.pem 证书路径")); System.out.println("输出证书信息:\n" + certificate.toString()); System.out.println("证书序列号:" + certificate.getSerialNumber().toString(16)); System.out.println("版本号:" + certificate.getVersion()); System.out.println("签发者:" + certificate.getIssuerDN()); System.out.println("有效起始日期:" + certificate.getNotBefore()); System.out.println("有效终止日期:" + certificate.getNotAfter()); System.out.println("主体名:" + certificate.getSubjectDN()); System.out.println("签名算法:" + certificate.getSigAlgName()); System.out.println("签名:" + certificate.getSignature().toString()); /** * 获取证书 * * @param inputStream 证书文件 * @return {@link X509Certificate} 获取证书 */ public static X509Certificate getCertificate(InputStream inputStream) { try { CertificateFactory cf = CertificateFactory.getInstance("X509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); cert.checkValidity(); return cert; } catch (CertificateExpiredException e) { throw new RuntimeException("证书已过期", e); } catch (CertificateNotYetValidException e) { throw new RuntimeException("证书尚未生效", e); } catch (CertificateException e) { throw new RuntimeException("无效的证书", e); } } [代码] SHA256 with RSA 签名 获取商户私钥 [代码] /** * 获取商户私钥 * * @param keyPath 商户私钥证书路径 * @return 商户私钥 * @throws Exception 解析 key 异常 */ public static String getPrivateKey(String keyPath) throws Exception { String originalKey = FileUtil.readUtf8String(keyPath); String privateKey = originalKey .replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s+", ""); return RsaKit.getPrivateKeyStr(RsaKit.loadPrivateKey(privateKey)); } public static String getPrivateKeyStr(PrivateKey privateKey) { return Base64.encode(privateKey.getEncoded()); } /** * 从字符串中加载私钥 * * @param privateKeyStr 私钥 * @return {@link PrivateKey} * @throws Exception 异常信息 */ public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception { try { byte[] buffer = Base64.decode(privateKeyStr); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); return keyFactory.generatePrivate(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("无此算法"); } catch (InvalidKeySpecException e) { throw new Exception("私钥非法"); } catch (NullPointerException e) { throw new Exception("私钥数据为空"); } } [代码] 私钥签名 [代码]/** * 私钥签名 * * @param data 需要加密的数据 * @param privateKey 私钥 * @return 加密后的数据 * @throws Exception 异常信息 */ public static String encryptByPrivateKey(String data, String privateKey) throws Exception { PKCS8EncodedKeySpec priPkcs8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey)); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey priKey = keyFactory.generatePrivate(priPkcs8); java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA"); signature.initSign(priKey); signature.update(data.getBytes(StandardCharsets.UTF_8)); byte[] signed = signature.sign(); return StrUtil.str(Base64.encode(signed)); } [代码] 至此微信支付 Api-v3 接口请求参数已封装完成。 执行请求 [代码]/** * V3 接口统一执行入口 * * @param method {@link RequestMethod} 请求方法 * @param urlPrefix 可通过 {@link WxDomain}来获取 * @param urlSuffix 可通过 {@link WxApiType} 来获取,URL挂载参数需要自行拼接 * @param mchId 商户Id * @param serialNo 商户 API 证书序列号 * @param keyPath apiclient_key.pem 证书路径 * @param body 接口请求参数 * @param nonceStr 随机字符库 * @param timestamp 时间戳 * @param authType 认证类型 * @param file 文件 * @return {@link String} 请求返回的结果 * @throws Exception 接口执行异常 */ public static Map<String, Object> v3Execution(RequestMethod method, String urlPrefix, String urlSuffix, String mchId, String serialNo, String keyPath, String body, String nonceStr, long timestamp, String authType, File file) throws Exception { // 构建 Authorization String authorization = WxPayKit.buildAuthorization(method, urlSuffix, mchId, serialNo, keyPath, body, nonceStr, timestamp, authType); if (method == RequestMethod.GET) { return doGet(urlPrefix.concat(urlSuffix), authorization, serialNo, null); } else if (method == RequestMethod.POST) { return doPost(urlPrefix.concat(urlSuffix), authorization, serialNo, body); } else if (method == RequestMethod.DELETE) { return doDelete(urlPrefix.concat(urlSuffix), authorization, serialNo, body); } else if (method == RequestMethod.UPLOAD) { return doUpload(urlPrefix.concat(urlSuffix), authorization, serialNo, body, file); } return null; } [代码] 网络请求库默认是使用的 Hutool 封装的一套 Java 工具集合来实现 GET 请求 [代码]/** * @param url 请求url * @param authorization 授权信息 * @param serialNumber 公钥证书序列号 * @param jsonData 请求参数 * @return {@link HttpResponse} 请求返回的结果 */ private HttpResponse doGet(String url, String authorization, String serialNumber, String jsonData) { return HttpRequest.post(url) .addHeaders(getHeaders(authorization, serialNumber)) .body(jsonData) .execute(); } [代码] POST 请求 [代码] /** * @param url 请求url * @param authorization 授权信息 * @param serialNumber 公钥证书序列号 * @param jsonData 请求参数 * @return {@link HttpResponse} 请求返回的结果 */ private HttpResponse doPost(String url, String authorization, String serialNumber, String jsonData) { return HttpRequest.post(url) .addHeaders(getHeaders(authorization, serialNumber)) .body(jsonData) .execute(); } [代码] DELETE 请求 [代码]/** * delete 请求 * * @param url 请求url * @param authorization 授权信息 * @param serialNumber 公钥证书序列号 * @param jsonData 请求参数 * @return {@link HttpResponse} 请求返回的结果 */ private HttpResponse doDelete(String url, String authorization, String serialNumber, String jsonData) { return HttpRequest.delete(url) .addHeaders(getHeaders(authorization, serialNumber)) .body(jsonData) .execute(); } [代码] 上传文件 [代码] /** * @param url 请求url * @param authorization 授权信息 * @param serialNumber 公钥证书序列号 * @param jsonData 请求参数 * @param file 上传的文件 * @return {@link HttpResponse} 请求返回的结果 */ private HttpResponse doUpload(String url, String authorization, String serialNumber, String jsonData, File file) { return HttpRequest.post(url) .addHeaders(getUploadHeaders(authorization, serialNumber)) .form("file", file) .form("meta", jsonData) .execute(); } [代码] 构建 Http 请求头 [代码]private Map<String, String> getBaseHeaders(String authorization) { String userAgent = String.format( "WeChatPay-IJPay-HttpClient/%s (%s) Java/%s", getClass().getPackage().getImplementationVersion(), OS, VERSION == null ? "Unknown" : VERSION); Map<String, String> headers = new HashMap<>(3); headers.put("Accept", ContentType.JSON.toString()); headers.put("Authorization", authorization); headers.put("User-Agent", userAgent); return headers; } private Map<String, String> getHeaders(String authorization, String serialNumber) { Map<String, String> headers = getBaseHeaders(authorization); headers.put("Content-Type", ContentType.JSON.toString()); if (StrUtil.isNotEmpty(serialNumber)) { headers.put("Wechatpay-Serial", serialNumber); } return headers; } private Map<String, String> getUploadHeaders(String authorization, String serialNumber) { Map<String, String> headers = getBaseHeaders(authorization); headers.put("Content-Type", "multipart/form-data;boundary=\"boundary\""); if (StrUtil.isNotEmpty(serialNumber)) { headers.put("Wechatpay-Serial", serialNumber); } return headers; } [代码] 构建 Http 请求返回值 从响应的 HttpResponse 中获取微信响应头信息、状态码以及 body [代码]/** * 构建返回参数 * * @param httpResponse {@link HttpResponse} * @return {@link Map} */ private Map<String, Object> buildResMap(HttpResponse httpResponse) { Map<String, Object> map = new HashMap<>(); String timestamp = httpResponse.header("Wechatpay-Timestamp"); String nonceStr = httpResponse.header("Wechatpay-Nonce"); String serialNo = httpResponse.header("Wechatpay-Serial"); String signature = httpResponse.header("Wechatpay-Signature"); String body = httpResponse.body(); int status = httpResponse.getStatus(); map.put("timestamp", timestamp); map.put("nonceStr", nonceStr); map.put("serialNumber", serialNo); map.put("signature", signature); map.put("body", body); map.put("status", status); return map; } [代码] 至此已完成构建请求参数,执行请求。接下来我们就要实现响应数据的解密以及响应结果的验证签名 对应的官方文档 证书和回调报文解密 签名验证 验证签名 构建签名参数 [代码]/** * 构造签名串 * * @param timestamp 应答时间戳 * @param nonceStr 应答随机串 * @param body 应答报文主体 * @return 应答待签名字符串 */ public static String buildSignMessage(String timestamp, String nonceStr, String body) { return new StringBuilder() .append(timestamp) .append("\n") .append(nonceStr) .append("\n") .append(body) .append("\n") .toString(); } [代码] 证书和回调报文解密 官方文档文末有完整的源码这里就不贴了。贴一个示例大家参数一下 [代码]try { String associatedData = "certificate"; String nonce = "80d28946a64a"; String cipherText = "DwAqW4+4TeUaOEylfKEXhw+XqGh/YTRhUmLw/tBfQ5nM9DZ9d+9aGEghycwV1jwo52vXb/t6ueBvBRHRIW5JgDRcXmTHw9IMTrIK6HxTt2qiaGTWJU9whsF+GGeQdA7gBCHZm3AJUwrzerAGW1mclXBTvXqaCl6haE7AOHJ2g4RtQThi3nxOI63/yc3WaiAlSR22GuCpy6wJBfljBq5Bx2xXDZXlF2TNbDIeodiEnJEG2m9eBWKuvKPyUPyClRXG1fdOkKnCZZ6u+ipb4IJx28n3MmhEtuc2heqqlFUbeONaRpXv6KOZmH/IdEL6nqNDP2D7cXutNVCi0TtSfC7ojnO/+PKRu3MGO2Z9q3zyZXmkWHCSms/C3ACatPUKHIK+92MxjSQDc1E/8faghTc9bDgn8cqWpVKcL3GHK+RfuYKiMcdSkUDJyMJOwEXMYNUdseQMJ3gL4pfxuQu6QrVvJ17q3ZjzkexkPNU4PNSlIBJg+KX61cyBTBumaHy/EbHiP9V2GeM729a0h5UYYJVedSo1guIGjMZ4tA3WgwQrlpp3VAMKEBLRJMcnHd4pH5YQ/4hiUlHGEHttWtnxKFwnJ6jHr3OmFLV1FiUUOZEDAqR0U1KhtGjOffnmB9tymWF8FwRNiH2Tee/cCDBaHhNtfPI5129SrlSR7bZc+h7uzz9z+1OOkNrWHzAoWEe3XVGKAywpn5HGbcL+9nsEVZRJLvV7aOxAZBkxhg8H5Fjt1ioTJL+qXgRzse1BX1iiwfCR0fzEWT9ldDTDW0Y1b3tb419MhdmTQB5FsMXYOzqp5h+Tz1FwEGsa6TJsmdjJQSNz+7qPSg5D6C2gc9/6PkysSu/6XfsWXD7cQkuZ+TJ/Xb6Q1Uu7ZB90SauA8uPQUIchW5zQ6UfK5dwMkOuEcE/141/Aw2rlDqjtsE17u1dQ6TCax/ZQTDQ2MDUaBPEaDIMPcgL7fCeijoRgovkBY92m86leZvQ+HVbxlFx5CoPhz4a81kt9XJuEYOztSIKlm7QNfW0BvSUhLmxDNCjcxqwyydtKbLzA+EBb2gG4ORiH8IOTbV0+G4S6BqetU7RrO+/nKt21nXVqXUmdkhkBakLN8FUcHygyWnVxbA7OI2RGnJJUnxqHd3kTbzD5Wxco4JIQsTOV6KtO5c960oVYUARZIP1SdQhqwELm27AktEN7kzg/ew/blnTys/eauGyw78XCROb9F1wbZBToUZ7L+8/m/2tyyyqNid+sC9fYqJoIOGfFOe6COWzTI/XPytCHwgHeUxmgk7NYfU0ukR223RPUOym6kLzSMMBKCivnNg68tbLRJHEOpQTXFBaFFHt2qpceJpJgw5sKFqx3eQnIFuyvA1i8s2zKLhULZio9hpsDJQREOcNeHVjEZazdCGnbe3Vjg7uqOoVHdE/YbNzJNQEsB3/erYJB+eGzyFwFmdAHenG5RE6FhCutjszwRiSvW9F7wvRK36gm7NnVJZkvlbGwh0UHr0pbcrOmxT81xtNSvMzT0VZNLTUX2ur3AGLwi2ej8BIC0H41nw4ToxTnwtFR1Xy55+pUiwpB7JzraA08dCXdFdtZ72Tw/dNBy5h1P7EtQYiKzXp6rndfOEWgNOsan7e1XRpCnX7xoAkdPvy40OuQ5gNbDKry5gVDEZhmEk/WRuGGaX06CG9m7NfErUsnQYrDJVjXWKYuARd9R7W0aa5nUXqz/Pjul/LAatJgWhZgFBGXhNr9iAoade/0FPpBj0QWa8SWqKYKiOqXqhfhppUq35FIa0a1Vvxcn3E38XYpVZVTDEXcEcD0RLCu/ezdOa6vRcB7hjgXFIRZQAka0aXnQxwOZwE2Rt3yWXqc+Q1ah2oOrg8Lg3ETc644X9QP4FxOtDwz/A=="; AesUtil aesUtil = new AesUtil(wxPayV3Bean.getApiKey3().getBytes(StandardCharsets.UTF_8)); // 平台证书密文解密 // encrypt_certificate 中的 associated_data nonce ciphertext String publicKey = aesUtil.decryptToString( associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), cipherText ); // 保存证书 FileWriter writer = new FileWriter(wxPayV3Bean.getPlatformCertPath()); writer.write(publicKey); // 获取平台证书序列号 X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes())); return certificate.getSerialNumber().toString(16).toUpperCase(); } catch (Exception e) { e.printStackTrace(); } [代码] 验证签名 [代码]/** * 验证签名 * * @param signature 待验证的签名 * @param body 应答主体 * @param nonce 随机串 * @param timestamp 时间戳 * @param certInputStream 微信支付平台证书输入流 * @return 签名结果 * @throws Exception 异常信息 */ public static boolean verifySignature(String signature, String body, String nonce, String timestamp, InputStream certInputStream) throws Exception { String buildSignMessage = PayKit.buildSignMessage(timestamp, nonce, body); // 获取证书 X509Certificate certificate = PayKit.getCertificate(certInputStream); PublicKey publicKey = certificate.getPublicKey(); return RsaKit.checkByPublicKey(buildSignMessage, signature, publicKey); } /** * 公钥验证签名 * * @param data 需要加密的数据 * @param sign 签名 * @param publicKey 公钥 * @return 验证结果 * @throws Exception 异常信息 */ public static boolean checkByPublicKey(String data, String sign, PublicKey publicKey) throws Exception { java.security.Signature signature = java.security.Signature.getInstance("SHA256WithRSA"); signature.initVerify(publicKey); signature.update(data.getBytes(StandardCharsets.UTF_8)); return signature.verify(Base64.decode(sign.getBytes(StandardCharsets.UTF_8))); } [代码] 至此微信支付 Api-v3 接口已介绍完,如有疑问欢迎留言一起探讨。 完整示例 SpringBoot 参考资料 你真的了解 HTTPS 吗? WechatPay-API-v3
2021-03-02 - 小程序登录、用户信息相关接口调整说明
公告更新时间:2021年04月15日考虑到近期开发者对小程序登录、用户信息相关接口调整的相关反馈,为优化开发者调整接口的体验,回收wx.getUserInfo接口可获取用户授权的个人信息能力的截止时间由2021年4月13日调整至2021年4月28日24时。为优化用户的使用体验,平台将进行以下调整: 2021年2月23日起,若小程序已在微信开放平台进行绑定,则通过wx.login接口获取的登录凭证可直接换取unionID2021年4月28日24时后发布的小程序新版本,无法通过wx.getUserInfo与<button open-type="getUserInfo"/>获取用户个人信息(头像、昵称、性别与地区),将直接获取匿名数据(包括userInfo与encryptedData中的用户个人信息),获取加密后的openID与unionID数据的能力不做调整。此前发布的小程序版本不受影响,但如果要进行版本更新则需要进行适配。新增getUserProfile接口(基础库2.10.4版本开始支持),可获取用户头像、昵称、性别及地区信息,开发者每次通过该接口获取用户个人信息均需用户确认。具体接口文档:《getUserProfile接口文档》由于getUserProfile接口从2.10.4版本基础库开始支持(覆盖微信7.0.9以上版本),考虑到开发者在低版本中有获取用户头像昵称的诉求,对于未支持getUserProfile的情况下,开发者可继续使用getUserInfo能力。开发者可参考getUserProfile接口文档中的示例代码进行适配。请使用了wx.getUserInfo接口或<button open-type="getUserInfo"/>的开发者尽快适配。开发者工具1.05.2103022版本开始支持getUserProfile接口调试,开发者可下载该版本进行改造。 小游戏不受本次调整影响。 一、调整背景很多开发者在打开小程序时就通过组件方式唤起getUserInfo弹窗,如果用户点击拒绝,无法使用小程序,这种做法打断了用户正常使用小程序的流程,同时也不利于小程序获取新用户。 二、调整说明通过wx.login接口获取的登录凭证可直接换取unionID 若小程序已在微信开放平台进行绑定,原wx.login接口获取的登录凭证若需换取unionID需满足以下条件: 如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用2月23日后,开发者调用wx.login获取的登录凭证可以直接换取unionID,无需满足以上条件。 回收wx.getUserInfo接口可获取用户个人信息能力 4月28日24时后发布的新版本小程序,开发者调用wx.getUserInfo或<button open-type="getUserInfo"/>将不再弹出弹窗,直接返回匿名的用户个人信息,获取加密后的openID、unionID数据的能力不做调整。 具体变化如下表: [图片] 即wx.getUserInfo接口的返回参数不变,但开发者获取的userInfo为匿名信息。 [图片] 此外,针对scope.userInfo将做如下调整: 若开发者调用wx.authorize接口请求scope.userInfo授权,用户侧不会触发授权弹框,直接返回授权成功若开发者调用wx.getSetting接口请求用户的授权状态,会直接读取到scope.userInfo为true新增getUserProfile接口 若开发者需要获取用户的个人信息(头像、昵称、性别与地区),可以通过wx.getUserProfile接口进行获取,该接口从基础库2.10.4版本开始支持,该接口只返回用户个人信息,不包含用户身份标识符。该接口中desc属性(声明获取用户个人信息后的用途)后续会展示在弹窗中,请开发者谨慎填写。开发者每次通过该接口获取用户个人信息均需用户确认,请开发者妥善保管用户快速填写的头像昵称,避免重复弹窗。 插件用户信息功能页 插件申请获取用户头像昵称与用户身份标识符仍保留功能页的形式,不作调整。用户在用户信息功能页中授权之后,插件就可以直接调用 wx.login 和 wx.getUserInfo 。 三、最佳实践调整后,开发者如需获取用户身份标识符只需要调用wx.login接口即可。 开发者若需要在界面中展示用户的头像昵称信息,可以通过<open-data>组件进行渲染,该组件无需用户确认,可以在界面中直接展示。 在部分场景(如社交类小程序)中,开发者需要在获取用户的头像昵称信息,可调用wx.getUserProfile接口,开发者每次通过该接口均需用户确认,请开发者妥善处理调用接口的时机,避免过度弹出弹窗骚扰用户。 微信团队 2021年4月15日
2021-04-15 - 通过分享进入小程序获取不了参数了
我分享小程序时带上了参数,但是通过分享进入的时候获取不了数据了 [图片] [图片] [图片] 以前都可以,今天突然就不行了,是为什么?
2018-05-18 - 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 Canvas 功能生成一张带有小程序码的图片,然后引导用户下载图片到本地后再分享到朋友圈。相信大家在绘制分享图中应该踩到 Canvas 的各种(坑)彩dan了吧~ 这里首先推荐一个开源的组件:painter(通过该组件目前我们已经成功在支付宝小程序上也应用上了分享图功能) 咱们不多说,直接上手就是干。 [图片] 首先我们新增一个自定义组件,在该组件的json中引入painter [代码]{ "component": true, "usingComponents": { "painter": "/painter/painter" } } [代码] 然后组件的WXML (代码片段在最后) [代码]// 将该组件定位在屏幕之外,用户查看不到。 <painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" /> [代码] 重点来了 JS (代码片段在最后) [代码]Component({ properties: { // 是否开始绘图 isCanDraw: { type: Boolean, value: false, observer(newVal) { newVal && this.handleStartDrawImg() } }, // 用户头像昵称信息 userInfo: { type: Object, value: { avatarUrl: '', nickName: '' } } }, data: { imgDraw: {}, // 绘制图片的大对象 sharePath: '' // 生成的分享图 }, methods: { handleStartDrawImg() { wx.showLoading({ title: '生成中' }) this.setData({ imgDraw: { width: '750rpx', height: '1334rpx', background: 'https://qiniu-image.qtshe.com/20190506share-bg.png', views: [ { type: 'image', url: 'https://qiniu-image.qtshe.com/1560248372315_467.jpg', css: { top: '32rpx', left: '30rpx', right: '32rpx', width: '688rpx', height: '420rpx', borderRadius: '16rpx' }, }, { type: 'image', url: this.data.userInfo.avatarUrl || 'https://qiniu-image.qtshe.com/default-avatar20170707.png', css: { top: '404rpx', left: '328rpx', width: '96rpx', height: '96rpx', borderWidth: '6rpx', borderColor: '#FFF', borderRadius: '96rpx' } }, { type: 'text', text: this.data.userInfo.nickName || '青团子', css: { top: '532rpx', fontSize: '28rpx', left: '375rpx', align: 'center', color: '#3c3c3c' } }, { type: 'text', text: `邀请您参与助力活动`, css: { top: '576rpx', left: '375rpx', align: 'center', fontSize: '28rpx', color: '#3c3c3c' } }, { type: 'text', text: `宇宙最萌蓝牙耳机测评员`, css: { top: '644rpx', left: '375rpx', maxLines: 1, align: 'center', fontWeight: 'bold', fontSize: '44rpx', color: '#3c3c3c' } }, { type: 'image', url: 'https://qiniu-image.qtshe.com/20190605index.jpg', css: { top: '834rpx', left: '470rpx', width: '200rpx', height: '200rpx' } } ] } }) }, onImgErr(e) { wx.hideLoading() wx.showToast({ title: '生成分享图失败,请刷新页面重试' }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') }, onImgOK(e) { wx.hideLoading() // 展示分享图 wx.showShareImageMenu({ path: e.detail.path, fail: err => { console.log(err) } }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') } } }) [代码] 那么我们该如何引用呢? 首先json里引用我们封装好的组件share-box [代码]{ "usingComponents": { "share-box": "/components/shareBox/index" } } [代码] 以下示例为获取用户头像昵称后再生成图。 [代码]<button class="intro" bindtap="getUserInfo">点我生成分享图</button> <share-box isCanDraw="{{isCanDraw}}" userInfo="{{userInfo}}" bind:initData="handleClose" /> [代码] 调用的地方: [代码]const app = getApp() Page({ data: { isCanDraw: false }, // 组件内部关掉或者绘制完成需重置状态 handleClose() { this.setData({ isCanDraw: !this.data.isCanDraw }) }, getUserInfo(e) { wx.getUserProfile({ desc: "获取您的头像昵称信息", success: res => { const { userInfo = {} } = res this.setData({ userInfo, isCanDraw: true // 开始绘制海报图 }) }, fail: err => { console.log(err) } }) } }) [代码] 最后绘制分享图的自定义组件就完成啦~效果图如下: [图片] tips: 文字居中实现可以看下代码片段 文字换行实现(maxLines)只需要设置宽度,maxLines如果设置为1,那么超出一行将会展示为省略号 代码片段:https://developers.weixin.qq.com/s/J38pKsmK7Qw5 附上painter可视化编辑代码工具:点我直达,因为涉及网络图片,代码片段设置不了downloadFile合法域名,建议真机开启调试模式,开发者工具 详情里开启不校验合法域名进行代码片段的运行查看。 最后看下面大家评论问的较多的问题:downLoadFile合法域名在小程序后台 开发>开发设置里配置,域名为你图片的域名前缀 比如我文章里的图https://qiniu-image.qtshe.com/20190605index.jpg。配置域名时填写https://qiniu-image.qtshe.com即可。如果你图片cdn地址为https://aaa.com/xxx.png, 那你就配置https://aaa.com即可。
2022-01-20 - 微信开发小技巧:小程序页面间如何进行通信
FlashEvent FlashEvent 小程序页面间的通信工具 - 类似于EventBus FlashEvent 在小程序中 能够简化各页面间的通信,让代码书写变得简单,能有效的解耦事件发送方和接收方,能避免复杂和容易出错的依赖性和生命周期问题。 github add: https://github.com/wuyajun7/FlashEvent 使用方式: 前置:将FlashEvent.js导入到项目的utils文件中 1、接收方js代码中 1.1 引入该类,如:let flashEvent = require(‘你的路径/utils/FlashEvent.js’); 1.2 注册FlashEvent,如:在onLoad中 [代码] flashEvent.register(flashEvent.EVENT_KEYS.FIRST_EVENT, this, function (data) { this.setData({ eventCallBack: data }) }) [代码] 1.3 注销FlashEvent,如:在onUnload中调用 flashEvent.unregister(flashEvent.EVENT_KEYS.FIRST_EVENT, this); 2、发送方js代码中 2.1 引入该类,如:let flashEvent = require(‘你的路径/utils/FlashEvent.js’); 2.2 发送事件,如:flashEvent.post(flashEvent.EVENT_KEYS.FIRST_EVENT, ‘发送的数据’); flashEvent 简单接入、方便使用
2019-03-28 - 社区每周 |位置接口增加频率限制、服务商小程序新能力、新版众测及上周问题反馈(3.08-3.12)
各位微信开发者: 以下是getLocation增加调用频率限制、服务商小程序风险用户扫码能力公测启动、IOS和安卓新版众测及上周我们在社区收到的问题反馈的处理进度,希望同大家一同打造小程序生态。 getLocation增加调用频率限制 当前小程序频繁调用wx.getLocation接口会导致用户手机电量消耗较快,请开发者改为使用持续定位接口wx.onLocationChange,该接口会固定频率回调,使用效果与跟频繁调用getLocation一致。 从基础库2.17.0版本起(预计发布时间2021.4.9),将对getLocation接口增加频率限制,包括: 在开发版或体验版中,30秒内调用getLocation,仅第一次有效,剩余返回与第一次定位相同的信息。正式版中,为保证小程序正常运行同时不过度消耗用户电量,一定时间内(根据设备情况判断)调用getLocation,仅第一次会返回实时定位信息,剩余返回与第一次定位相同的信息。未做好兼容调整可能会影响用户体验,请开发者尽快适配。 服务商小程序风险用户扫描能力公测启动 为提高微信开放平台生态安全性,针对小程序各应用场景中可能存在的恶意注册、营销作弊等黑产风险和安全问题,平台将通过开放API的方式向服务商提供快速查询风险用户的接口,协助服务商保障小程序正常安全运营。 目前风险用户扫描接口支持以下两种应用场景: 1. 营销作弊场景:在首单优惠和特价优惠等营销活动中有效识别刷单、虚假交易、恶意骗保骗补贴等破坏运营秩序和安全的行为。 2. 恶意注册:识别并拦截机器批量注册、垃圾小号、伪造身份等恶意注册行为。 接口具体功能介绍请参考《小程序风险用户扫描功能介绍》。 接入指引及详细信息参考原公告:《服务商小程序风险用户扫描能力公测启动》 微信团队邀请开发者参与内部体验(安卓微信8.0.2) 本次更新概要如下小程序 video组件相关优化需关注地理位置等授权是否正常需关注临时文件相关功能是否正常需关注文件存储空间限制相关是否正常live-pusher组件相关bugfix,需关注麦克风相关功能是否正常蓝牙相关bugfix,需关注蓝牙扫描相关功能是否正常部分重构WebGL组件,需关注WebGL组件渲染是否正常小游戏 (重要)灰度期间尝试支持etc2和astc压缩格式,需关注游戏渲染是否正常优化uniformMatrix效率,需关注游戏运行性能部分重构渲染组件,需关注Touch事件等是否正常请基于以下提供的资源体验。使用过程中若发现问题,欢迎点击进入微信开放社区 #微信客户端内测 主页发表标题包含「微信8.0.2」的问答帖子反馈交流。 [图片] (扫描二维码下载) 如有需要,可查看并转发原公告:《微信团队邀请开发者参与内部体验(安卓微信8.0.2)》 微信团队邀请开发者参与内部体验(iOS微信8.0.3) 本次更新概要如下小程序: 文件系统底层重构,请关注相关接口是否受影响;小游戏: ATSC压缩纹理的支持;* 体验需识别下方二维码报名,若报名成功,则一天内会收到内测推送,内测名额8000人 [图片] 请基于以上提供的资源体验。使用过程中若发现问题,欢迎点击进入微信开放社区 #微信客户端内测 主页发表标题包含「微信iOS 8.0.3」的问答帖子反馈交流,发帖时建议提供以下信息方便定位问题: 1.手机型号 2.手机操作系统版本 3.必要时可提供代码片段 如有需要,可查看并转发原公告:《微信团队邀请开发者参与(iOS微信8.0.3内部体验)》 上周问题反馈和处理进度(3.08-3.12) 已修复的问题云开发-内容管理-短信统计分析数据一直为空的问题 查看详情 关联小程序提示:系统繁忙,请稍后重试(200003)的问题 查看详情 开发工具后控制台报(define,require)2个错误的问题 查看详情 修复中的问题 textarea maxlength 未阻止在中间输入 查看详情 previewImage 在安卓机无法预览,一直 loading 查看详情 ios 直接调hideLoading 没有触发回调 查看详情 安卓机下input输入框收起键盘之类的操作会多触发一次input事件 查看详情 iOS video 小窗模式 收不到bindended和bindtimeupdate的事件 查看详情 安卓performance中的firstRenderrender耗时偶现负数 查看详情 ios wx.previewMedia本地视频点击无法播放 查看详情 微信团队 2021.3.19
06-13