个人案例
- 微客程序
从事互联网软件开发服务的外包企业,致力于向中小型企业提供软件开发服务。
专为懒人商户量身定制的一款微信小程序平台。扫码体验
- 小程序webview组件,小程序和webview交互,小程序内联h5页面,小程序webview内网页实现微信支付
小程序支持webview以后,我们开发的好多h5页面,就可以直接在小程序里使用了,比如我们开发的微信商城,文章详情页,商品详情页,就可以开发一套,多处使用了。我们今天来讲一讲。在小程序的webview里实现微信支付功能。因为微信不允许在小程序的webview里直接调起微信支付。所以我们这节课就要涉及到小程序和webview的交互了。 老规矩先看效果。 因为这里涉及的东西比较多,录gif太多,没法上传,我就录制了一段视频出来。 https://v.qq.com/x/page/t0913iprnay.html 原理 先说下实现原理吧,实现原理就是我们在webview的h5页面里实现下单功能,然后点击支付按钮,我们点击支付按钮的时候会跳转到小程序页面,把订单号,订单总金额,传递到小程序里,然后小程序里使用订单号和订单金额去调起微信支付,实现付款,付款成功或者失败时都会有回调。我们再把对应的回调传递给webview,刷新webview里的订单和支付状态。 一,定义webview显示h5页面 关于webview的使用,我就不做讲解了,官方文档里写的很清楚,用起来也很简单。https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html [图片] webview很简单,就是用一个webview组件,显示我们的网页。 二,定义h5页面 我这里启动一个本地服务器,用来展示一个简单的h5页面。 [图片] 上图是我在浏览器里显示的效果。 接下来我们在小程序的webview里显示这个页面,也很简单,只需要把我们的src定义为我们的本地网页链接就可以了。 [图片] 这里有一点需要注意 因为我们是本地链接,我们需要到开发者工具里把这一项给勾选。 [图片] 三,来看下h5页面代码 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>小程序内嵌webview</title> <style> .btn { font-size: 70px; color: red; } </style> </head> <body> <h1>我是webview里的h5页面</h1> <a id="desc" class="btn" onclick="jumpPay()">点击支付</a> <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script> <script> console.log(location.href); let payOk = getQueryVariable("payOk"); console.log("payOk", payOk) if(payOk){//支付成功 document.getElementById('desc').innerText="支持成功" document.getElementById('desc').style.color="green" }else{ document.getElementById('desc').innerText="点击支付" } //获取url里携带的参数 function getQueryVariable(variable) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i = 0; i < vars.length; i++) { var pair = vars[i].split("="); if (pair[0] == variable) { return pair[1]; } } return (false); } function jumpPay() { let orderId = Date.now();//这里用当前时间戳做订单号(后面使用你自己真实的订单号) let money = 1;//订单总金额(单位分) let payData = {orderId: orderId, money: money}; let payDataStr = JSON.stringify(payData);//因为要吧参数传递给小程序,所以这里需要转为字符串 const url = `../wePay/wePay?payDataStr=${payDataStr}`; wx.miniProgram.navigateTo({ url: url }); // console.log("点击了去支付", url) console.log("点击了去支付") } </script> </body> </html> [代码] h5代码这里不做具体讲解,只简单说下。我们就是在点击支付按钮时,用当前时间戳做为订单号(因为订单号要保证唯一),然后传一个订单金额(单位分),这里节约起见,就传1分钱吧,花的是自己的钱,心疼。。。。 关键点说一下 1, 必须引入jweixin,才可以实现h5跳转小程序。 <script type=“text/javascript” src=“https://res.wx.qq.com/open/js/jweixin-1.3.2.js”></script> 2,跳转到小程序页面的方法 [代码]const url = `../wePay/wePay?payDataStr=${payDataStr}`; wx.miniProgram.navigateTo({ url: url }); [代码] 这里要和你小程序的页面保持一致。payDataStr是我们携带的参数 [图片] 四,小程序支付页 来看下我们的小程序支付页 [图片] 小程序支付页功能很简单,就是来接收我们h5传过订单号和订单金额。然后去调起微信支付,实现支付。支付成功和支付失败都有对应的回调。 [图片] 支付我们这里实用的小程序云开发来实现的支付,核心代码只有10行。由于支付不是本节的重点,所以这里不做具体讲解。感兴趣的同学可以去看我写的文章和我录的视频 小程序支付文章:https://www.jianshu.com/p/2b391df055a9 小程序支付视频:https://edu.csdn.net/course/play/25701/310742 下面把小程序接收参数和支付的完整代码贴出来给大家 [代码]Page({ //h5传过来的参数 onLoad: function(options) { console.log("webview传过来的参数", options) //字符串转对象 let payData = JSON.parse(options.payDataStr) console.log("orderId", payData.orderId) let that = this; wx.cloud.callFunction({ name: "pay", data: { orderId: payData.orderId, money: payData.money }, success(res) { console.log("获取成功", res) that.goPay(res.result); }, fail(err) { console.log("获取失败", err) } }) }, //微信支付 goPay(payData) { wx.requestPayment({ timeStamp: payData.timeStamp, nonceStr: payData.nonceStr, package: payData.package, signType: 'MD5', paySign: payData.paySign, success(res) { console.log("支付成功", res) //你可以在这里支付成功以后,再跳会webview页,并把支付成功状态传回去 wx.navigateTo({ url: '../webview/webview?payOk=true', }) }, fail(res) { console.log("支付失败", res) } }) } }) [代码] 代码里注释很清楚,这里有一点,就是我们支付成功后,需要告诉h5我们支付成功了,通知h5去刷新订单或者支付状态。 到这里我们就完整的实现了小程序webview展示h5页面,并且做到了h5和小程序的交互,实现了小程序webview的支付功能。 是不是很简单呢。 源码地址 1,关注“编程小石头”公号,回复“webview”即可获取源码 2,也可以到我github下载源码 https://github.com/qiushi123/xiaochengxu_demos [图片]
2019-08-15 - 【微信支付新人必读】智慧的提问,快速的解答
写在开头 在技术社区里,你技术提问的解答情况,很大程度上取决于你提问的方式与解决此问题的难度。 智慧的提问就是好的提问习惯和好的提问规范的结合,它能让你事半功倍。至少在微信支付社区,它是真实成立的 如果您没有时间读完全文,请务必读完微信支付社区提问智慧 首先来看一下,微信支付社区的智慧提问法则: 微信支付社区提问智慧 好的提问习惯 如果你有以下几个提问习惯,能直接解决大部分你想问的问题~ [代码]1. 尝试在搜索框中搜索答案; 2. 尝试阅读相关官方文档以找到答案; 3. 尝试阅读FAQ以找到答案; 4. 尝试自己检查或试验以找到答案; [代码] 好的提问规范 好的提问规范,能在最快的解决让你得到最优效的解答~ [代码]请用陈述句准确描述问题 1. 标题定位到微信支付具体业务,比如:支付分、代金券、普通支付、合单支付等; 2. 50+字详细准确描述问题的症状: 3. 包含必要的错误信息、期待的结果; 4. 包含必要的截图或代码等细节; 5. 请描述已经尝试过的方法。 [代码] 如果期望得到微信支付技术支持,请参考以下模板:(有敏感信息可私信提供) [代码]1. 请求的具体API接口(提供文档地址和请求的URL): 2. 问题发生时间【必填】 3. 商户号【必填】: 4. 商户订单号【必填】: 5. 相关报错信息文案: 6. 完整的请求和返回参数以及单号: 7. 问题截图或视频: 8. 已经尝试过的方法: [代码] 如果你已做了上述事情,我们会非常乐意回答比较规范的优质提问,也会在最快的时间推送到支持组进行针对性的回答。 当然为了维持社区的内容质量,无效提问(空泛、偏离技术讨论、软文传播、推广引流等内容),我们也有有权进行删除处理。 下面跟着大家看一下通用的技术社区提问智慧,仅供参考~ 通用技术社区提问智慧 量不在多,精炼则灵 简单的将一大堆代码或数据罗列在求助信息中达不到目的。如果你有一个很大且复杂的测试样例让程序崩溃,尝试将其裁剪得越小越好。 描述问题而不是猜测 提问中描述是什么导致了问题是没用的(如果你的诊断理论是对的,或许你就不会来这儿咨询求助了?)。所以,确保只要描述问题的原始症状,而不是你的解释和理论,让社区名人或官方支持来解释和诊断。如果你认为陈述自己的猜测很重要,应清楚地说明这只是你的猜测并描述为什么它们不起作用。 错误的示范: 我在XX时遇到了YY错误,怀疑是ZZ原因,这个问题怎么解决? 智慧的提问: 我组装的电脑(电脑信息)最近在开机20分钟左右,做内核编译时频繁地报SLG11错,但在开头20分钟内从不出问题,重启动不会复位时钟,但整夜关机会。更换所有内存未解决问题,相关的典型编译会话日志附后。 按时间先后罗列问题症状 刚出问题之前发生的事情通常包含有解决问题最有效的线索。所以,问题描述中尽可能的描述在问题出现之前都做了什么。在命令行处理的情况下,有会话日志(如运行脚本工具生成的)并引用相关的若干(如 20)行记录会非常有帮助。 提问应明确 漫无边际的问题通常也被视为没有明确限制的时间无底洞。最有可能给你有用答案的人通常也是最忙的人(假如只是因为他们承担了太多工作的话),这些人对于没有止境的时间无底洞极其敏感,所以他们也倾向于不太喜欢那些漫无边际的问题。 如果你明确了想让回复者做的事(如指点方向、发送代码、检查补丁或其它),你更有可能得到有用的回复。(因为)这样可以让他们集中精力并间接地设定了他们为帮助你需要花费的时间和精力上限。 结语 提问的智慧就是一个敲门砖,它会让你了解到一个事实,为什么那些看起来很牛的人几乎从不提问,似乎他们一进入这个行业就是牛人了。不是的,他们也有问题,但是通常在提问之前就自己解决了;不是因为他们本来就懂得怎么解决,而是解决问题的经历让他们成为牛人;最终,你只会看到网络上多了一篇文章:关于解决 某某 问题的方案。 最后,祝你在微信支付开发的路上,早日晋升为大神~希望未来有一天,您也能将在社区得到的帮助回馈给更多需要帮助的“微信支付新人”。
2020-11-12 - 多商户商城系统如何对接电商收付通?
多商户商城系统分账问题,相信一直困扰着大家,微信电商收付通确实是不二选择, 那如何对接电商收付通, 把自己的一点小经验写出来,希望能帮大家少走弯路。 一、 什么是电商收付通? 电商收付通是微信支付专为电商行业场景打造的支付、结算解决方案。电商平台的平台商户入驻微信支付成为二级商户。电商 收付通支持将多个二级商户的订单进行合单支付(如电商购物车中的多笔订单合并支付),合单支付款项分别进入到二级商户各自的账户(资金为冻结状态,可用于实现二级商户账期);电商平台在满足业务流程条件下(如确认收货等),可将二级商户的冻结状态的资金解冻,并收取平台佣金。 注:电商平台开通电商收付通前,需确保在本平台没有已经入驻或处于入驻流程中的二级商户。 二、 通电商收付通前的准备 1.选择接入模式 商户/服务商在接入前首先要判断自己公司注册区域适用的接入模式,微信支付目前提供两种接入方式:直连模式和服务商模式。 ● 直连模式: 信息、资金流:微信支付—>直连商户 直连模式,商户自行申请入驻微信支付,无需服务商协助,(商户平台申请)成为直连商户。 [图片] ● 服务商模式: 服务商模式,商户申请成为微信支付服务商,服务商自身无法作为一个直连商户直接发起交易,其发起交易必须传入相关特约商户商户号的参数信息。(服务商平台申请)成为服务商 请结合自身实际情况来选择接入模式。 [图片] 2. 准备资质 需准备与电商平台主体一致的ICP许可证或EDI许可证。(该证在各省的通信管理局办理,时间根据准备资料和各地的流程1-3个月不等) 三、开通电商收付通 第一步:请在微信公众号后台开通电商收付通 在 产品中心>合作工具箱 中开通电商收付通 [图片] 开通电商收付通需要上传上文提及的资质证书。 [图片] 第二步:请在平台后台做相应参数配置 [图片] 此处电商系统后台以CRMEB多商户系统为例: 位置:平台后台>设置>支付配置>微信服务商支付配置 [图片] 第三步:开启分账 位置:平台后台>财务>转账设置 [图片] 第四步:子商户后台操作 位置:商户后台>财务>申请分账商户>提交资料>审核完成 子商户在该页面上传资料、查看审核状态、审核结果。 [图片] [图片] [图片] 第五步:设置自动分账时间 位置:平台后台>设置>商城设置 此处设置售后时长,比如10天,指用户确认收货后10天内可以退货;超过10天就自动分账了,不能退货;如果此处没有设置,默认用户在确认收货后15天自动分账,15天自动分账后,就不能退货了。 [图片] 备注: 1. 以上步骤全部完成后,用户通过微信所支付的金额,会根据设置时间自动分账到子商户号。 2. 自动分账、线下转账,每笔结算记录都在财务账单中可查看;自动分账的金额会直接到商户账户,不会显示在平台后台的商户余额。 3. 用户可根据自身业务及资质情况自由选择开启自动分账或不开启,如果不开启,则启用线下转账模式 四、查看分账状态 位置:平台后台>财务>分账管理 [图片] 位置:商户后台>财务>分账管理 [图片] 五、商户提现 自动分账的金额到分账商户的商户号中,需登录微信后台提现到银行 第一步:微信后台地址:https://pay.weixin.qq.com/ 第二步:商户申请分账时设置的超级管理员扫码登陆 [图片] 第三步:确认账户信息,输入转账金额,提交转出 [图片] 微信电商收付通 接口文档链接 :https://pay.weixin.qq.com/wiki/doc/apiv3_partner/open/pay/chapter3_3_0.shtml
2022-10-14 - 小程序广告变现新方式:免开发智能接入模式上线啦!
微信广告创新推出小程序广告免开发智能接入模式,同时下调小程序流量主开通门槛,助力更多中小开发者获取变现收益。 智能接入模式下,开发者全程 0 代码开发、3 步简单操作、仅需约 5 分钟,即可完成广告上线,大大提高变现效率。 [图片] 亮点一 系统智能推荐 系统将基于小程序页面结构,自动计算并为开发者推荐最合适的“展示位置 × 广告类型”组合,免去了前期广告方案设计环节,简化广告接入流程。 [图片] 亮点二 实时预览编辑 区别于常规自主接入模式,智能接入模式无需经历广告代码嵌入和版本发布测试等环节,开发者可直接在移动端实时预览广告,在线手动编辑调整广告位置和类型,大大降低调试成本。 [图片] 亮点三 免开发上线 开发者使用智能接入模式完成预览后,依据广告位体验效果和收入预估,简单选择合适的广告位,并一键确认开启即可上线广告,全程 0 代码、免开发,仅需约 5 分钟,便可快速踏上商业化收益之旅。 目前,小程序广告免开发智能接入模式已全面开放;同时,为助力更多开发者获取流量变现收益,小程序流量主的开通门槛已从“累计独立用户(UV)≥1000”下调至“累计独立用户(UV)≥500”。 符合条件的开发者可登录“微信公众平台”,进入“流量主 - 广告管理”页面,按提示进行 3 步操作,即可完成广告接入。 [图片] 点击查看 小程序广告免开发智能接入模式详细操作指引。 未来,微信广告也将持续降低流量变现门槛,并提供更简单、更高效的变现解决方案,期待与开发者伙伴们一起共创繁荣的流量生态,共享更丰富的商业收益。
01-25 - 搭建活动页面可以有多快?带你来看小程序云模板
抽奖活动需要紧急上线,时间紧任务重? 活动页面需要承载大规模的并发访问,一个人咋支持? 有羊毛党来搅局,怎么快速方便的防护? ....... 作为开发者,你是否会遇到上面这些局面? 微信小程序推出「云模版」,在降低开发门槛,提升开发效率的路上又走了一步。 云模版为开发者提供了众多常用的业务模块,只需选择所需模块并进行简单调整,即可直接将源码页面部署到小程序包中,实现活动的快速开发和上线。 [图片] 可以先观看以下实践视频来感受一下: [视频] 一、 什么场景需要云模板? 在小程序开发过程中,我们可以发现,有一些业务需求是类似的,可能最大的变化就是前端页面设计;比如签到打卡、积分中心、趣味抽奖等。 我们可以将这些相似的需求归类,每一类需求都可以用一个开发模板为底座,通过上层的参数或页面调整来实现。作为开发者,我们可以用这种方式来替代我们重复的开发工作,同时提升了我们搭建活动页面的效率。 微信小程序推出的「云模版」能力,正是利用了这种 “模板复用,二次修改” 的思路。另外也为开发者预置了常见的场景类别,并且这个类别会持续的扩展。 我在这里随便列举几个类别,大家可以带入一下: 1. 营销活动大类: ● 抽奖活动:吸引用户参与的抽奖页面;● 限时优惠:限时折扣页面;● 新品发布:为新品专设活动页面;2. 信息收集与报名: ● 线上课程报名:为用户报名体验使用;● 活动登记:活动登记表单,收集用户数据;● 意见反馈:创建收集用户意见和建议的反馈页面;3. 内容发布与展示: ● 新闻公告:在小程序中发布展示最新公告;● 教育培训:在线教育机构可以快速更新课程信息;● 产品展示:为产品创建专属展示页面;4. 服务预约与管理: ● 医疗健康预约:用户可以方便地预约医疗服务;● 餐饮预定:提供在线菜单,实现快速点餐与预定;● 汽车维修预约:车主在线预约维修服务;5. 用户互动与社区: ● 投票调查:发起在线投票,了解用户偏好;● 社区交流:构建社区交流平台,促进用户互动;● 知识问答:设置问答环节,提升内容的互动性;「云模版」最大的好处是,由它生成的页面,可以直接导出源码到自己开发的小程序包中,调整非常的灵活。 [图片] 二、 云模版有什么特点和能力?云模版最大的特点就是数据互通和组建丰富化两点。 1. 数据互通直接打通登录态,用户进入云模版生成的活动页面后,会自动获取登录信息。另外在活动页面操作过程中的所有数据,都会有自带的数据源支持,开发者可以直接跟后面的数据源做对接。 [图片] 这样直接对接数据源的好处有两点: (1) 不需要修改前端页面来冗杂的对接所有数据,节省开发时间,提升开发效率。 (2) 直接对接的数据源数据更加整齐,减少了很多控制层的后端开发逻辑,一切以数据驱动。 如果你不想与自己的后端对接,只是想快速上线并运营一个独立的活动页。2.0自带的数据源也配有完善的管理后台,可以支持多用户多角色精细化授权管理。 [图片] 2. 组件丰富化云模版除了预置很多类别的模板之外,还允许你在模板的基础上做很多精细化的页面修改,这就需要提供更多组件来适应众多开发者不同的需求。 所以我们可以在云模版管理器中,看到丰富的组件库,以及可以供自定义逻辑使用的表达式配置。 [图片][图片] 三、 如何使用云模版 ?接下来给大家展示一下云模版使用步骤 1. 下载最新版的微信开发者工具IDE(nightly版本) 请在官方IDE下载页面,下载最新nightly版本的开发者工具IDE,并安装。(stable版本需要等待下一发版,2401020(不含)之后) 2. 打开自己的小程序开发项目(无需新建一个小程序项目),在代码目录中右键菜单,在菜单中点击「配置云模版/单页模板」 [图片] 3. 跳转到云模版配置管理控制台,如果你没有任何使用任何模板,会出现以下界面,你可以选择心仪的模板,点击「安装模板」 [图片] [图片] 安装页面大概需要2分钟左右,请耐心等待。 5. 页面安装完成后,跳转到页面的控制页面 [图片] 在这里你可以点击右上角的「前往管理后台」,配置活动相关配置。以大转盘举例子,可以在管理后台中配置抽奖次数、奖品信息、中奖概率、中奖后地址的维护等。 如果你觉得页面的信息和自己的期望不符,你可以前往「自定义设计」做相应的修改,修改后发布即可。 [图片] 如果你有和自己后端对接的需求,可以前往「数据管理」页,配置外部数据源来对接,以及修改工作流改变页面的执行逻辑。 [图片] 6. 将页面安装到自己的小程序中 在初次安装云模版时,你需要填写必要的信息到控制台中,点击顶部的黄色警告栏,在弹出的对话框中输入小程序的关键信息。 [图片] 对应的信息可以前往小程序管理后台配置获取 [图片] 配置完毕后,可以在页面控制台中,直接点击「添加到小程序」,页面就会自动的插入到你打开的项目中了。 [图片] 你可以在后面二次修改这个页面的路径,和原生开发的体验无异。 [图片] 四、 写在后面初次体验下来,从开通到安装到小程序,全程不到10分钟。如果再需要自己修改一下页面和规则,1个小时的时间也是富裕的。 目前的云模板预置的页面还是有限的几个,如果有其他场景需求,倒也不妨碍我们直接自定义全新的页面(自定义页面能力),期待后面可以推出更多场景的模板。 另外还发现云模板有「高并发设置」和「安全设置」能力,但是还没有上线。考虑到抽奖等活动可能会引来羊毛党等灰产的攻击,这些设置不仅能保证活动页面的顺畅运行,还能提供额外的性能和安全加成,又为开发者省去了一大工作量,我这里蹲一波,后面推出后体验下这块能力。 如果你目前正在为快速上线活动页面而烦恼,或者有计划升级你的开发模式,不妨可以花点时间体验一下「云模板」。 如果你在使用过程中有疑问或者建议,可以加入交流群直接问。 关于本文中提出的观点和内容,如果你有其他补充和意见,欢迎在文章下留言一起探讨~ 最后给一些场景中一小部分模板,供大家参考 [图片] [图片] [图片] [图片]
04-25 - Skyline 转场动画轻松实现
在之前的 Skyline|小程序页面转场动画 文章中,Skyline 支持了自定义路由,开发者可以根据业务的需求来自行编写页面转场动画。 文章发布之后,我们收到不少开发者的反馈,对于“半屏”打开的转场动画是十分常见的,希望官方可以内置该能力。 为了降低开发成本,从基础库 v3.1.0 开始,Skyline 预设了一些常见的路由动画效果~ routeType 动画效果 wx://bottom-sheet 向上半屏弹窗,前一个页面不变 wx://upwards 向上进入页面,前一个页面不变 wx://zoom 放大进入页面,前一个页面不变 wx://cupertino-modal 向上打开页面至胶囊下面的位置,前一个页面收缩下沉 wx://cupertino-modal-inside 被 wx://cupertino-modal 打开的页面需要继续使用 wx://cupertino-modal 打开效果 wx://modal-navigation 被 wx://cupertino-modal 或 wx://modal 打开的页面向左进入页面的效果,前一个页面不变 wx://modal 向上打开页面至胶囊下面的位置,前一个页面不变 对于以上的 routeType,使用起来非常简单,因为动画效果已经由基础库内置了,所以开发者直接使用即可 [代码]// 演示使用 wx://modal 进入页面 wx.navigateTo({ url: 'xxx', routeType: 'wx://modal' }) [代码] 让我们来看看动画效果吧~ 1、向上半屏弹窗 & 向上进入页面 & 放大进入页面 除了默认的向左进入页面外,基础库内置了向上半屏弹窗 & 向上进入页面 & 放大进入页面 这几个动画效果,开发者可以根据业务自身情况来使用 [图片] 2、向上打开页面至胶囊下面的位置 这个动画效果在原生 APP 中的使用十分常见,对于前一个页面的处理和后面页面打开的动画效果略有不同 我们先来看 wx://cupertino-modal 的路由效果(图左)向上打开页面至胶囊下面的位置,前一个页面收缩下沉 在使用 wx://cupertino-modal 打开的页面之后,有两种页面打开形式 · wx://cupertino-modal-inside(图中):新页面打开方式同 wx://cupertino-modal 一致 · wx://modal-navigation(图右):新页面向左进入,前一个页面不变 [图片] 前一个页面的效果除了下沉收缩,也支持保持不变,使用起来就比较简单 使用 wx://modal 向上打开页面至胶囊下面的位置,前一个页面不变。新页面需要使用 wx://modal-navigation 向左进入,前一个页面不变 [图片] 预设路由使用简单,直接在 wx.navigateTo 配置参数即可,如果想要更丰富、更多的自定义的路由效果,大家可以使用 自定义路由 来自行定制~
2023-10-23 - Skyline | 快速搞定复杂的分享海报
在小程序中生成海报是一种非常有效的推广方式 用户可以使用小程序的过程中生成小程序海报并分享给他人 通过海报的形式,用户可以直观地了解产品或服务的特点和优势 [图片] 常见绘制海报方式 目前,小程序海报有两种常见的实现方式: · canvas 绘制海报 · 服务端绘制海报 这两种方式各有千秋 canvas 绘制海报使用 canvas 绘制海报主要有以下几个步骤 1、创建 [代码]canvasContext[代码] 2、获取网络图片的本地路径 3、绘制图片、文字等到 [代码]canvas[代码] 4、调用 [代码]wx.canvasToTempFilePath[代码] 导出图片 尽管 canvas 绘制功能强大,但实际使用中,这些操作看似简单,但调试起来却比较麻烦 而且面对一些复杂的排版时,使用 canvas 绘制相较于使用 CSS 绘制来说困难许多 除此之外,canvas 的宽高有最大限制,超出限制则会绘制空白 服务端绘制 小程序也可以通过调用服务端接口,将需要生成海报的数据传递给服务端, 由服务端使用 Canvas API 等第三方库来生成图片。 然而,这种绘制方式需要走网络请求,如果量大会给服务器带来一定的成本压力。 此外,对于复杂排版的实现,使用 Canvas 绘制也有一定的难度。 尽管小程序海报虽然好用,但是当遇到要求比较高的设计稿需要还原海报时,对小程序开发者来说是一个十分让人头疼的问题 考虑到海报在小程序中使用的广泛性,我们把开发者的烦恼交给官方来处理~ 小程序官方推出了 [代码]snapshot[代码] 组件,可以直接将小程序 wxml 导出图片。 snapshot 生成海报 当使用 canvas 或 服务端绘制海报遇到复杂排版时,如 圆角、百分比、自定义字体 等等,实现比较困难。 但是使用 wxml 实现却很简单 👇 下面的例子我们使用 wxml 实现海报 <view class="snapshot-box"> <view class="poster-container"> <view class="poster-header"> <image /> ... </view> <view class="description"> ... </view> <view class="footer"> ... </view> </view> </view> [图片] 接着,我们就可以导出海报啦,使用非常简单: 1、用 [代码]snapshot[代码] 组件包裹海报的 wxml 2、调用 [代码]takeSnapshot[代码] 获取图片数据 3、调用 [代码]fs.writeFileSync[代码] 将海报数据写入本地文件 4、调用 [代码]wx.saveImageToPhotosAlbum[代码] 将海报保存到本地 <snapshot id="view"> <!-- 这里是要海报的 wxml --> </snapshot> <button bindtap="tap">保存海报</button> tap() { this.createSelectorQuery().select("#view") .node().exec(res => { const node = res[0].node // 保存海报 node.takeSnapshot({ type: 'arraybuffer', format: 'png', success: (res) => { const f = `${wx.env.USER_DATA_PATH}/hello.png` const fs = wx.getFileSystemManager(); // 将海报数据写入本地文件 fs.writeFileSync(f, res.data, 'binary') this.setData({ img: f }) // 把海报图片保存到本地 wx.saveImageToPhotosAlbum({ filePath: f }) } }) }) } 最后我们来看看使用 [代码]snapshot[代码] 组件生成海报的效果吧~ [图片] 除了普通尺寸分享海报之外,对于 canvas 无法搞定的超长海报,[代码]snapshot[代码] 后续也会支持超长海报的导出~ [图片] 你的小程序也有海报生成需求吗? 赶紧 mark 下这个 代码片段 来接入使用吧~
2023-09-06 - 用uniapp开发打包多端应用完整指南
一、uni-app项目介绍用uni-app开发多端项目,一套代码可同时打包出各端小程序、h5和app,uni-app支持通过 HBuilderX可视化界面 和 vue-cli命令行 两种方式创建项目,下面示例项目采用 HBuilderX可视化界面 的方式创建,cli项目可参考uni文档,大部分流程都是通用的。 项目结构: ├── common api文件 ├── components 公用组件 ├── libs 公共方法 ├── pages 页面 ├── static 本地静态资源,注意:静态资源只能存放于此 ├── store 状态管理 ├── styles 公共样式 ├── config.js 配置文件 ├── manifest.json 配置应用名称、appid、logo、版本等打包信息,详见 ├── pages.json 配置页面路由、导航条、选项卡等页面类信息 └── unpackage ├── res 图标、启动页 ├── cert APP证书文件 └── dist 打包的文件 BashCopy 拿到源码先修改 config.js 里的 api 请求接口地址,改成你自己的请求域名,然后 manifest.json 里各平台的 appid 改成你自己小程序的 appid: [图片] 相关开发文档: vueuniappHBuilderXstylus[图片] 二、注册开发者账号和创建应用开始开发前需要先去uni的开发者后台注册一个账号,登录注册地址:https://dev.dcloud.net.cn/,然后在里面创建一个你自己的应用: [图片] 三、安装开发工具HBuilderXHBuilderX,简称HX,是轻如编辑器,强如IDE的合体版本,有点像vscode和小程序开发工具的结合体,顶部菜单栏有一个“运行”和“发行”的菜单,直接点击:运行 —— 运行到内置浏览器,可以直接像在浏览器里一样调试。 发布App时,需要使用HBuilderX,其他开发工具无法发布App,但可以发布H5、各种小程序。如需开发App,可以先在HBuilderX里运行起来,然后在其他编辑器里修改保存代码,代码修改后会自动同步到手机基座。HBuilderX下载地址:https://www.dcloud.io/hbuilderx.html。 四、新建和运行项目先安装一些常用的插件: 内置浏览器uni-app(Vue2)编译uni-app(Vue3)编译App真机运行App云打包scss/sass编译stylus编译[图片] 创建项目 创建新项目可以通过HBuilderX顶部菜单:文件 - 新建 - 项目,导入已有项目:文件 - 导入 - 从... 运行项目 运行项目通过HBuilderX顶部菜单:运行 - 运行到...,开发阶段可先选择:运行到内置浏览器,如果有报错缺少xx插件,直接根据提示去安装对应插件,再重新运行就可以了。 [图片] 五、小程序和H5打包各平台的配置可以直接在manifest.json里配置,或者在HBuilderX开发工具里选中manifest.json文件,右侧会出现图形化界面直接选择配置 [图片] 先运行起来,然后点击:发行 - 小程序/网站 - 设置小程序/网站名字/appid/域名,打包成功后可以在dist - build 文件夹下找到对应平台的打包文件(dist - dev 目录下对应的是各平台运行文件) [图片] 六、安卓应用打包1、点击:发行 - 原生App-云打包 2、按照unpackage/cert目录下的README.md说明填写: Android包名、证书别名、证书私钥密码、选择证书文件(直接点浏览按钮,选到 unpackage/cert 目录,Android开发证书生成参考文末的说明) 3、点击打包按钮 [图片] 七、IOS应用打包1、点击:发行 - 原生App-云打包 2、按照unpackage/cert目录下的 README.md 说明填写: Bundle ID(AppID)、证书私钥密码、证书profile文件和私钥证书(直接点浏览按钮,选到 unpackage/cert 目录) 3、点击打包按钮 [图片] 使用云打包点击了打包按钮后,需要等待一段时间,少则几分钟,多则大半天...最终打包成功后会在控制台打印出app安装文件的下载地址: [图片] Android:apk文件,直接点击“打开所在目录”,生成的apk文件在 unpackage/release/apk文件夹下 IOS: ipa文件,直接点击“下载地址”,远程下载到本地 打包证书相关资料: Android平台云端打包证书使用说明 Android平台云端打包 - DCloud公用证书(DCloud老版证书) Android平台签名证书(.keystore)生成指南 iOS证书(.p12)和描述文件(.mobileprovision)申请 八、发布上线1、小程序 直接用小程序开发者工具导入 dist - build 文件夹下对应的目录,如微信小程序:dist/build/mp-weixin 2、H5 和web网站一样,将最终打包出来的H5文件部署到线上:dist/build/h5 3、Android 最终生成的apk文件,可以直接用聊天工具发送到安卓手机上安装使用去注册各大安卓应用市场账号,上传到应用市场供用户下载也可以自己开发一个发布页,将安卓apk放到项目里,用户点击直接下载到手机里,如果设备是ios还可以直接判断让跳转到appstore下载地址4、IOS ① 正式版本 ios正式应用只能从app store里下载,需要先注册苹果开发者账号,填写各项应用资料,上传ipa文件审核通过后才能下载使用 [图片] ② 测试版本 ios-app测试时,将ipa文件上传到蒲公英上:https://www.pgyer.com/ 用有授权的苹果手机扫描二维码在Safari浏览器里打开即可直接下载安装,或者直接在safari浏览器中输入“下载地址” 附:windows下生成安卓开发证书Android平台打包发布apk应用,需要使用数字证书(.keystore文件)进行签名,用于表明开发者身份,Android证书的生成是自助和免费的,不需要审批或付费。 可以使用JRE环境中的keytool命令生成,以下是windows平台生成证书的方法: 1、安装JRE环境 可从Oracle官方下载jre安装包:https://www.oracle.com/technetwork/java/javase/downloads/index.html(记住安装的路径,后面生成证书的时候要用到) 2、打开命令行(cmd),可以先切换到要生成的目录下 我直接在D盘根目录下生成输入: d: BashCopy 3、将JRE安装路径添加到系统环境变量 我的JRE装在D盘下 "D:\Programs\jre\bin" set PATH=%PATH%;"D:\Programs\jre\bin" BashCopy 注意这里安装路径不要写错了,我这里刚开始路径里 Programs 就少了个s,后面就一直报错:keytool不是内部或外部命令,也不是可运行的程序 4、使用keytool -genkey命令生成证书 keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore android.keystore BashCopy testalias:是证书别名,可修改为自己想设置的字符,建议使用英文字母和数字android.keystore:是证书文件名称,可修改为自己想设置的文件名称,也可以指定完整文件路径36500:是证书的有效期,表示100年有效期,单位天,建议时间设置长一点,避免证书过期[图片] 按提示输入信息后就会在D盘根目录下生成 android.keystore 文件,这个文件就可以用来直接打包安卓app了
2022-11-30 - 小程序新渲染引擎 Skyline 发布正式版
为了进一步提升小程序的渲染性能和体验,我们推出了一套新渲染引擎 Skyline,现在,跟随着基础库 3.0.0 发布 Skyline 正式版。 我们知道,小程序一直用 WebView 来渲染界面,因其有不错的兼容性和丰富的特性,且各大厂商也在不断优化 Web 的渲染性能,但 Web 体系相比于原生开发,在性能上仍然有较大差距,并且特性上发展缓慢,使得小程序很难做出类原生的体验。因此,我们开发了一套新渲染引擎 Skyline,旨在替代 WebView 作为小程序的渲染层,以提供更优秀的渲染性能和诸多增强特性,让小程序能达到原生的体验。 以下为你全方位介绍 Skyline 的特点。 提供更好的性能 在渲染流程上,WebView 因其需要向后兼容,积累了较多历史包袱,加之整体设计目标不同,使其渲染流水线更加冗长复杂,而 Skyline 则更为精简,同时只保留更现代的 CSS 特性。在此基础上,我们还进一步实现了很多优化点: 单线程版本组件框架。Skyline 下默认启用了新版本的组件框架 glass-easel,该版本适应了 Skyline 的单线程模型,使得建树流程的耗时有效降低(优化 30%-40%),同时 setData 调用也不再有通信开销。 组件下沉。我们将部分内置组件(如 scroll-view、swiper、picker-view 等)直接在底层实现,以追求更流畅的交互体验。此外,我们也将常用的内置组件(view、text、image)从 JS 下沉到原生实现,相当于原生 DOM 节点,有效降低了创建组件的开销(优化 30%)。 长列表按需渲染。长列表是一个常用的但又经常遇到性能瓶颈的场景,Skyline 对其做了一些优化,使 scroll-view 组件只渲染在屏节点(用法上有一定的约束),并且增加 lazy mount 机制优化首次渲染长列表的性能,后续我们也计划在组件框架层面进一步支持 scroll-view 的可回收机制,以更大程度降低创建节点的开销。 WXSS 预编译。同 WebView 传输 WXSS 文本不同,Skyline 在后台构建小程序代码包时会将 WXSS 预编译为二进制文件,在运行时直接读取二进制文件获得样式表结构,避免了运行时解析的开销(预编译较运行时解析快 5 倍以上)。 样式计算更快。Skyline 通过精简 WXSS 特性大幅简化了样式计算的流程。同时 Skyline 与小程序框架结合也更为紧密,例如: Skyline 结合组件系统实现了 WXSS 样式隔离、基于 wx:for 实现了节点样式共享(相比于 WebView 推测式样式共享更为精确、高效)。 降低内存占用。在 WebView 渲染模式下,一个小程序页面对应一个 WebView 实例,并且每个页面会重复注入一些公共资源。而 Skyline 只有 AppService 线程,且多个 Skyline 页面会运行在同一个渲染引擎实例下,因此页面占用内存能够降低很多,还能做到更细粒度的页面间资源共享(如全局样式、公共代码、缓存资源等)。总体上,由于 Skyline 在渲染流程上更加可控,我们能让小程序的特性尽可能融合进渲染流程中完成,还有很多在细节上的优化(比如对 rpx 的处理、image mode=widthFix 的处理等,都是融入渲染流程中,而避免在 JS 做太多额外的计算)就不再一一介绍。另外,我们也在持续优化中,Skyline 会是之后小程序性能优化的重点。 至于目前整体的性能情况,我们从已上线的小程序数据观测到(基础库 3.0.0 glass-easel 带来的优化暂未体现),启动耗时方面,即点击到完全渲染(LCP)的耗时,WebView 对比 Skyline 为 2492ms vs 2052ms,减少 17.6%;渲染阶段耗时方面,即框架建树到完全渲染(LCP)的耗时,WebView 对比 Skyline 为 626ms vs 312ms,减少 50%。 根除旧有架构的问题 在基于 Web 体系的架构下,小程序的部分基础体验会受限于 WebView 提供的能力(特别是 iOS WKWebView 限制更大一些),使得一些技术方案无法做得很完美,留下一些潜在的问题。 原生组件同层渲染更稳定。iOS 下原生组件同层渲染的原理先前有介绍过,本质上是在 WKWebView 黑盒下一种取巧的实现方式,并不能完美融合到 WKWebView 的渲染流程,因此很容易在一些特殊的样式发生变化后,同层渲染会失效,而在 Skyline 下可以很好地融合到渲染流程中,因此会更稳定。 无需页面恢复机制。iOS 下 WKWebView 会受系统的管理,当内存紧张时,系统就会将不在屏的 WKWebView 回收,会使得小程序除前台以外的页面丢失,虽然在页面返回时,我们对页面做了恢复,但页面的状态并不能 100% 还原,而在 Skyline 下则不再有该问题。 无页面栈层数限制。由于 WebView 的内存占用较大,页面层级最多有 10 层,而 Skyline 在内存方面更有优势,因此在连续 Skyline 页面跳转(复用同一引擎实例)的情况下,不再有该限制。 全新的交互动画体系 我们发现,要达到类原生的体验,渲染性能与交互动画缺一不可,渲染性能能让页面更快渲染出来,而交互动画能让浏览页面的体验更佳。但在 Web 体系下,难以做到像素级可控,交互动画衔接不顺畅,究其原因,在于缺失了一些重要的能力,为此,我们提供一套全新的交互动画能力。 Worklet 动画机制。在原来双线程的架构下,若要对界面元素做逐帧动画是需要频繁在逻辑层和渲染层之间通信的,这会带来较大的延迟,动画也就不会流畅。而 Worklet 动画正是为了解决这类问题而诞生的,其运行机制与 WXS 类似,但比 WXS 更靠近渲染流程而性能更好,而且支持的特性更多,可扩展性更强,这个是 Skyline 交互动画体系的基础。 手势系统。在原生的交互动画里,手势识别与协商是一个很重要的特性,而这块在 Web 体系是缺失的,因此 Skyline 下补全手势系统相关特性,包括常用手势的识别,如缩放、拖动、双击等,还有很重要的手势协商机制,在遇到手势冲突(常见于滚动容器下)时决定让哪个手势生效,以实现更顺畅的动画衔接。 自定义路由与共享元素。页面间的自定义转场动画,在原生应用里也是一个很常见的交互动画。在原来的小程序架构下,每个页面都是独立的 WebView 渲染,互相隔离,其跨页能力是基本不具备的。因此,Skyline 提供了一套自定义路由机制,能实现市面上大多数页面转场动画,同时也提供了共享元素机制,能很方便地做到同一元素在页面间飞跃的效果。此外,对内置组件的扩展也是重要一环,特别是 scroll-view 组件,我们优化了下拉刷新的体验,并且实现“下拉二楼”的交互,也添加很多控制能力,这都是些在 Web 下很难做到又非常重要的特性。总之,这套全新的交互动画体系是 Skyline 能实现类原生交互体验的关键。 释放更多高级能力 除了上面提到的交互动画能力外,Skyline 所能释放的能力还远不止于此,借助 Skyline 的特点,我们还提供以下新的组件 grid-view 瀑布流组件。瀑布流是一种常用的列表布局方式,得益于 Skyline 在布局过程中的可控性,我们直接在底层实现并提供出来,渲染性能要比 WebView 更优。 snapshot 截图组件。大多数小程序都会基于 canvas 实现自定义分享图的功能,但分享图的布局较复杂时,canvas 的方案实现成本会更大,而 Skyline 是具备对 WXML 子树截图的能力的,因此我们直接封装后开放出来,这样能复用更完善的 WXSS 能力,极大降低开发成本。除了新增的组件,还有不少是原有内置组件扩展的小特性,这里就不一一介绍,可 查看文档 或 更新日志。未来,我们还会持续在 Skyline 上开放更多高级功能,如全局跨页面组件,scroll-view 列表节点 builder 模块支持节点可回收等,更多可查看 文档特性状态 一栏,同时,也欢迎开发者在社区给我们提议。 至此,Skyline 的主要特点已基本介绍完毕,更完整的介绍、用法、迁移指引、注意点等等请查阅 文档。建议开发者现在就使用起来,尽早享受到 Skyline 带来的优化和丰富的特性,如果开发中遇到问题,可在开发者社区发贴反馈,我们也会邀请加入沟通交流群。
2023-07-19 - Donut 上传应用商店遇到的问题及解决方案
分享我自己碰到的一些上架问题,大家也可以留言补充! 1.安卓端单独微信登入就可以 2.尽量所有《点击事件》都有反馈 3.要提供账号注销的功能 4.软件页面要提供展示入口《隐私协议》/《用户协议》 5.应用宝- icp备案域名 打开后需要有app宣传页面等,页面最好不要带登入入口 6.聊天、社区等需要提供安全报告下面有案例 7.ios端如果不使用苹果支付,ios登入等,在标识符里面不要勾选,描述文件里面也不要有。会被驳回! 8.有wx.openLocation功能的,这个功能暂时不能用,用wx.getLocation被华为驳回了 9.如果APP中未使用微信支付,可在开发者工具project.miniapp.json中勾选不代支付能力的opensdk。 [图片] 一、软件版权 软件版权 1.《计算机软件著作权登记证书》当前最快申请速度为20-30个工作日,不包含材料整理时间; 2.《电子版权认证证书》和《软件著作权认证证书》最快申请速度为3个工作日,最慢申请时间10-15个工作日,在时效方面具有非常大的优势。 [流泪/]花了6个月注册了软著,忘记写简称了,又花了15天办了软件著作权认证证书 其实来说《软件著作权认证证书》就可以上架绝大部分应用商店了,白交了一次学费,并浪费了时间! 软著找第三方申请tb pdd等,不要自己傻傻的申请,要不然很多地方改正驳回 二、ICP备案 备案查询后截图,打印盖公章!!! 感觉是随缘审核,有的时候需要盖公章,有的时候不需要。 三、UI问题 尽量做到UI自适应,UI设计尽量自己设计, 如果UI与其他软件页面一致会有驳回的风险。 四、安全评估报告 登录全国互联网安全服务管理平台(http://www.beian.gov.cn ),请选择主页评估报告登录 按照我这个填即可 服务名称 功能名称 ..... 评估情形:具有舆论属性或社会动员能力的信息服务上线,或者信息服务增设相关功能; 评估方法:自评估 1、安全管理负责人、信息审核人员及安全管理机构设立情况。 安全管理负责人:XXX 审核人员:XXX 2、用户真实身份核验及注册信息留存措施。 建立台账、专人记录留存。 3、对用户账号、操作时间、操作类型、网络源地址和目标地址、网络源端口、客户端硬件特征等日志信息,以及用户发布信息记录的留存措施。 建立台账,专人记录留存备案。 4、对用户账号和通讯群组名称、昵称、简介、备注、标识,信息发布、转发、评论和通讯群组等服务功能中违法有害信息的防范处置和有关记录保存措施。 设专人进行扫描、查找,及时处理,并进行纪律备案。 5、个人信息保护以及防范违法有害信息传播扩散、社会动员功能失控风险的技术措施。 定期组织人员培训,宣传个人信息保护知识,严防社会动员功能失控。 6、建立投诉、举报制度,公布投诉、举报方式等信息,及时受理并处理有关投诉和举报的情况。 在网络的显著位置设置投诉电话,并安排专人接听电话,受理并及时处理各类投诉和举报情况。 7、建立为监管部门和执法部门依法履职提供技术、数据支持和协助的工作机制的情况。 安排专人专责,为监管部门和执法部门依法履职提供技术、数据支持和协助 填完后,会让你打印一份PDF上传,然后等待wang警上门核查,等待通过即可! 上传后,没人审核怎么办?联系当地网络部门催审, 我催审后,第二天就上门解决了。 五、隐私协议 网上复制的只能找那些通用型模板, 软件权限说明,尽量在隐私协议上补充清楚。 开启了推送消息需要在《隐私协议说明》并在软件设置里面设置一个《个性化推荐》开关 有获取用户信息,并推荐给其他人 需要在《隐私协议说明》并在软件设置里面设置一个《把我推荐给可能认识的人》开关 三方SDK列表 为保障相关功能的实现与应用安全稳定的运行,我们可能会接入由第三方提供的软件开发包(SDK)实现相关目的。 我们会对合作方获取信息的软件工具开发包(SDK)进行严格的安全监测,以保护数据安全。 我们对接入的相关第三方SDK在目录中列明。 请注意,第三方SDK可能因为其版本升级、策略调整等原因导致数据处理类型存在一定变化,请以其公示的官方说明为准。 综合运行类 第三方SDK名称:微信 SDK 链接:https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/Android.html/ 收集信息类型:设备标识信息、软件安装列表 使用目的:接入微信开放平台,让你的移动应用支持微信分享、微信收藏和微信支付。 第三方SDK名称:wmpf_demo_external 链接:https://github.com/wmpf/wmpf_demo_external 收集信息类型:设备标识信息、软件安装列表 使用目的:该运行环境能让硬件在脱离微信客户端的情况下运行微信小程序 祝大家上架顺利!!! 先写这么多吧,想到了在补充。
2023-07-11 - 申请开通【商家转账到零钱】超时后如何反馈?
前言 在微信开放社区看到很人【商家转账到零钱】超过了7-15个工作日没有回复,还在审核中,遇到这个问题怎么解决呢?我最近正好在申请,这篇文章我就要讲讲我是如何找到客服,并且得到反馈的。 [图片] 步骤 关注【腾讯客服】公众号 [图片] 在公众号输入“人工客服”发送 [图片] 点击链接输入你的问题,就会进入排队等待,我第一天没有人回复了。 第二天同样的方式有人工客服回复了,等了差不多1个小时。 [图片] [图片] 发完之后,客服给我了一个链接填写商户号和联系方式 [图片] [图片] 收到了具体的回复 [图片] [图片] 过了24小时吼,我登陆微信支付后台【商家转账到零钱】的审核也得到了处理。 [图片] [图片] 总结 你的申请如果超过了 7-15 个工作日,建议在公众号上多联系几次人工客服,不要怕麻烦,申请的人很多,多点耐心,只要联系上了人工客服基本就可以得到处理了。
2023-02-14 - 小程序性能优化实践
小程序性能优化课程基于实际开发场景,由资深开发者分享小程序性能优化的各项能力及应用实践,提升小程序性能表现,满足用户体验。
10-09 - 还在为开发调试头疼?来来来,这里有一份微信支付APIv3脚本,真金白银开源了!
脚本名称: Name:微信支付 APIv3 脚本说明: 本脚本是基于 微信支付 APIv3 的 Postman请求前置脚本(Pre-Request Script)进行完善,补充了微信支付普通商户所有已知公开接口,每个接口请求预置了请求参数示例与请求成功返回的参数示例,帮助商户开发者、测试人员以及小白用户也可以快速上手。 仅修改原脚本变量为常用叫法,无其他修改部分: merchantId->mchid merchantSerialNo->merchant_serial_no merchantPrivateKey->apiclient_key.pem 使用前提条件 postman,建议注册一个账户,便于使用它各种功能,例如同步。 有一个微信支付商户号,支持微信支付直连普通商户、微信支付直连特约商户,不支持微信二级子商户。 商户 API 私钥与商户证书序列号:商户API私钥是在商家平台申请商户API证书时,会生成商户私钥,并保存在本地证书文件夹的文件 apiclient_key.pem 中,商户商户序列号可在商家平台->账户中心->API安全->管理API证书查询到。 快速开始 1、使用Fork 方式导入脚本 1.1、点击[图片]进入向导,如下图所示。 [图片] 1.2:点击 Fork Collection 进入下一步,填入标签 Fork Label 并选择目的工作台 Workspace。一般情况下,导入个人工作台 My Workspace 即可。 如未登录账户,会跳转到账户登录页面,如无账户建议先去注册一个 [图片] 1.3点击 Fork Collection 完成导入。在你指定的 workspace 中可以看到《微信支付 APIv3》了。 [图片] 2、配置Environment 环境(Environment) 是一组变量 (Varibles) 的集合。 脚本从环境中读取变量,用来计算请求的签名。 你可以从《微信支付 APIv3》提供的 商户参数模版 中 fork 一个空环境到自己的工作台。 [图片] 接下来,在你工作台的 Enviroments 中找到新建的环境,点击 Add a new varialbe 添加新的变量: 变量名 是否必填 描述 备注 server_url 必填 微信支付接口域名 固定值:https://api.mch.weixin.qq.com mchid 必填 微信支付商户号 纯数字 merchant_serial_no 必填 商户 API 证书序列号 apiclient_key.pem 必填 PEM 格式的商户 API 私钥 以 -----BEGIN PRIVATE KEY----- 开始的 PEM 格式的商户 API 私钥。 appid 必填 用于微信支付接口请求中的APPID APPID需要与填写的mchid有绑定关系 openid 选填 用于微信支付接口请求中的openid 如不配置全局变量,请求时需要将参数中的变量openid替换为实际openid值 一组常见配置如下图所示: [图片] 3、发送测试请求 此处建议,使用桌面版 Postman app 发送请求,速度更快,体验更好! 现在回到工作台的请求构造界面,填入请求方法、URL、请求参数、Body 等参数。 工作台预置了微信支付普通商户所有请求样例供开发者参考,开发者也可以参考请求样例,构造自己的请求。 最后,选择你之前配置的 Environment,再点击地址栏右侧的Send按钮,发送请求。 [图片] 常见问题 1、发送请求时遇到错误提示“Error: Too few bytes to parse DER.”或者“Too few bytes to read ASN.1 value.” A:通常是环境 Environments 里配置的变量 merchantPrivateKey 填写有误导致的。脚本接收的私钥,以 -----BEGIN PRIVATEKEY----- 开始,以 -----END PRIVATE KEY----- 结束的一串字符串。 2、为什么我发送请求很慢? A:如果你使用的网页版 Postman,请使用桌面版 Postman app。因为浏览器中跨域资源共享(CORS)的限制,网页版发送请求是由 Postman 后台中转的。 WeChatPay Developers QQ Group ID:684379275
2022-11-08 - 微信视频号·创作运营指南
微信创作者课堂,是由微信官方发起的视频号创作、运营及交流的免费教学平台,旨在帮助所有爱好短视频和直播的创作者,更好地玩转视频号。
2022-06-10 - 专为懒人商户量身定制的一款微信小程序平台。
[图片] [图片] [图片] [图片] [图片]
2021-09-12 - 前端开发,必备的学习网站!
入门阶段 MDN 地址:https://developer.mozilla.org/zh-CN/docs/Web [图片] w3school 地址:https://www.w3school.com.cn/index.html [图片] JavaScript教程 地址:https://www.liaoxuefeng.com/wiki/1022910821149312 [图片] 进阶阶段 ES6 入门教程 地址:https://es6.ruanyifeng.com/ [图片] Cnode 地址:https://cnodejs.org/ [图片] 通用 GitHub 找轮子,开源项目有它就够了 地址:https://github.com/ [图片] Stack Overflow 提问题有它就够了 地址:https://stackoverflow.com/ [图片]
2020-08-19 - 搞懂微信支付 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 - 微信小商店·商家成长学习资料
内含开店指引、店铺运营和平台规则,帮你快速掌握小商店经营秘诀。
09-05 - [笔记] 小程序先享卡开发指南
前言自从2020年1月9日微信公开课上讲解了关于先享卡的功能简介及营销模式外,就被这产品吸引了,能降低摇摆用户决策门槛,锁定用户是商家最关心的。于是也第一时间进行了对接及申请开发并上线。后期期待早日推出用户组队有效拉新功能。 本文主要是讲解从先享卡的申请开通到产品如何对接并上线的整个流程步骤说明及开发中遇到的踩坑。 文档地址 新版先享卡api: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/discount-card/chapter1_1.shtml 步骤一: 申请接入先享卡流程1.直接参考文档地址链接完成接入步骤,目前还是只能先发邮件,等待官方邮件回复,让你加微信业务对接人,需要对贵司产品以及流程评估。 2.评估后拉微信群,把先享卡相关对接人拉到群里,发你服务入驻信息/先享卡内容配置表,注意领卡通知URL 跟结算通知URL填写,URL不要有换行或空格出现。 3.微信支付负责人根据商户提供的资料进行配置,发你先享卡号后就可进入开发了。 步骤二: 开发对接流程 1.设计一个领卡页面,我这边的思路是单独做了一张先享卡领取页,通过小程序广告图片点击进入,或者直接分享领卡页,分享朋友圈,海报图片都行。 2.用户进入领卡页后,先判断当前用户有没有参与过此先享卡活动,如已参与给出提示,未参与的话点击领取按钮后会先去请求一个先享卡下单接口,返回先享卡需要的相关字段后调用打开另一个小程序进入微信先享卡小程序。 [图片] 3.顺利的话,就进入微信先享卡活动页了,也就是之前在表里配置的活动内容。点击参与约定立享奖励后会跳转到领取页。(这时微信会把用户领卡信息发送给表里配置的回调请求路径,可以在回调方法里获得先享卡领卡的相关数据。并会同时收到一条微信支付服务号推送的模板消息提醒,点击模板消息后又会进入活动详情页。) [图片][图片] 4.点击完成按钮会关闭当前微信先享卡小程序。回到之前领取页,这时要自己去请求一个接口去查看当前用户是否已领取卡了,如已领取自动跳转到其他业务页。 [图片][图片] [图片] 5.用户只需在约定的时间内在小程序进行了服务预约下单操作,只需支付优惠后的金额(下单时显示已领取先享卡,可抵扣金额/打折),系统同时会进行扣除一次先享卡使用次数,并告知(调用更新先享卡订单API接口)先享卡更新1次状态(用户会收到微信支付模板消息-微信先享卡进度更新提醒)。当用户全部完成本次活动次数后,调用结算通知API。(用户会收到微信支付模板消息提醒) [图片][图片] [图片][图片] 6.用户已完成此次先享卡约定,在指定的时间周期内已完成订单共2次,并享受到9折优惠。如到期用户未完成约定,则由平台代扣用户已享优惠给商家,(如没有享过的优惠就不扣),从用户微信钱包里自动扣除,如用户微信钱包没钱的话,会定期向用户请求多次扣款,多次扣款还失败的话,个人微信支付分会受到影响。 7.到这里开发工作基本结束了,然后需要在微信群里联系微信相关人员,提前把每一步关于先享卡的操作需要截图,并录完整的视频打包后发给微信相关人员做验收,验收通过后,会走内部帮你把微信支付商户号里的微信支付分开通,并走正式上线流程。 8.最后在微信群里等待正式上线通知。 使用心得最后谈谈对接整个业务还是花了些时间了,邮件回复比较慢,流程比较多,对接wechatpay-api-v3 也比较严,API文档写的比较简单,加密解密的蛮多,希望早日全面开放API文档升级版,另外期待先享卡能早日加入组队玩法,一起参与活动完成与商家的约定。 昨晚收到微信支付API改版消息体验版,目前首页仅开放了JSAPI支付的开发文档入口,可以提前抢先看看。https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml
2020-11-12 - 视频号如何关联微信小商店带货赚钱?
我的微信号goodnicest,关注我免费持续关注小商店动态,还提供主播,货源渠道对接。 想了解微信小商店最新动态,请关注我哦 视频号如火如荼,变现一直是大家头疼的问题,不过今天我就给大家带来了详细的变现教程:视频号挂载微信小商店链接,直接进店完成购买。 在教程之前,大家可以在视频号搜索我的视频号(子凌不语),体验完成的视频号-微信小商店下单体验,如下图所示 [图片] 微信小商店挂载教程 1.准备好你的微信小商店AppID、商品ID,参考下图 [图片] 个人/企业的商品ID如何查看? 个人店:在 小商店助手 商品管理查看(商品编号=商品ID) 企业店:在 PC管理后台 商品列表查看(SpuId=商品ID) 2.转换链接,搜索【扩展链接】小程序 [图片] [图片] 3.发布视频号动态 .需要注意,个人公众号如果没有认证,那么商品的公众号会自动分配到官方的公众号,需要自己完成认证比较合适。建议大家都找已经认证的公众号,比较合适。已认证和未认证的区别如下: [图片] 我的公众号【子凌不语】,能提供 1.「产品」产品方法论交流,帮你构建体系 2.「变现」有各种变现组建,帮你流量变现 3.「电商」经营微信电商群,货源团长主播 ------------------------------------------------------- 最后求个关注和点赞 我的微信号goodnicest,关注我免费持续关注小商店动态,还提供主播,货源渠道对接。
2021-09-20 - 微信外卖、到家小程序上手攻略
当面临流量下降、租金上涨等压力时,搭建外卖、到家线上服务,已日益成为餐饮、零售等线下行业的标配。 微信作为连接用户与服务的载体,又能如何快速帮助各行业落地,并做好线上服务呢?我们将从以下三个方面解读: 在微信里做外卖、配送到家小程序,为何值得做有哪些资源(流量、产品能力)能使用,辅助服务落地外卖、配送到家小程序怎么做 1. 三大优势助力 交易0佣金 微信小程序官方不收取商户,在外卖小程序里产生的交易佣金,并持续提供运营辅助。 入口多、流量大,交易转化率高 外卖、配送小程序搭建好,如何快速推广到目标用户,完成新增用户,促进交易十分关键。附近的小程序、我的小程序、微信搜一搜等多入口助你轻松上“量”。 如何做好用户关系维护,提供有效服务,持续拉动交易,是经营者的必修课。微信群、服务号导购助手、订阅消息等多能力让交易转化节节“高”。 开通门槛低,服务平台助力服务落地快 只要是已开放行业,提供有效资质通过审核即可开通小程序账号。不具备开发能力的伙伴可通过微信服务平台,寻找服务商完成小程序开发。 2. 多流量入口与能力辅助 多个免费、零开发的流量入口,门槛低收益高 附近的小程序:零成本,拉新强外卖、配送服务是强依赖于线下地理位置的服务。通过在微信公众号后台将小程序设置到附近的小程序,即可为门店5公里的用户提供服务。 能为足不出户的用户提供点餐外卖、零售配送到家的服务,同时还能投放“优惠券”吸引用户促成交易。 点击获得能力详解与设置指南 [图片] (附近的小程序,外卖服务示意图) 我的小程序:零成本,留存高引导用户将小程序添加到“我的小程序”,即可实现用户在微信首页下拉窗口中,直达“我的小程序”,实现快速访问。 对于餐饮行业小程序主来讲, “我的小程序”可以提高用户的访问效率,免去用户搜索、查找的步骤。 点击获得能力详解与引导指南 [图片] (我的小程序,添加示意图) 微信搜一搜:零成本,精准直达通过在后台设置你的外卖、到家小程序服务,即可通过功能直达被用户搜索,直接获得曝光与交易的机会,还能强化用户对品牌的认知。 点击获得能力详解与设置指南 [图片] (微信搜一搜,品牌服务搜索示意图) 能力辅助交易转化与服务落地 社群运营:低成本、高收益的经营通过团长与门店附近的小区住户快速建立微信群。进行定时在线点餐、发起团购食材、推送优惠信息、推出速食食品等方式,用户足不出户也能享美食购好物。 并且通过群交流互动,建立情感联系后,根据不同区域或用户属性推荐对应的优惠或商品等精准化运营,拉动交易。 [图片] (微信群运营,示意图) 服务号+导购:精细化运营最佳搭档线下的门店导购,线上也能有,服务号粉丝就是你的潜在顾客。伙伴们可以通过接入微信导购助手,主动向服务号粉丝发起一对一的沟通,不仅有温度、人性化,还可以盘活现有服务号粉丝,挖掘个体的深度价值。 点击获得能力详解与内测申请指引 [图片] (微信导购助手,服务示意图) 小程序订阅消息:及时、有效对于餐饮、零售行业来说,很重要的是做到服务即时通知。例如将点餐配餐进程信息、送餐及配送信息、优惠券过期提醒等重要信息,便捷有效的通知用户。 小程序订阅消息针对不同场景提供多种消息模版,根据实际服务需求,提供有效消息通知能力。 点击获得能力详解与开发运营指南 [图片] (小程序订阅消息,示意图) 即时配送能力:“线上开店”最后一环稳定可靠的配送服务,是提供外卖外送服务的关键一环。微信即时配送的能力,统一对接了顺丰同城急送、闪送、达达快送和美团配送四家主流的即时配送公司,节省了伙伴们逐一对接多家的工作量。 同时,用户可通过微信物流服务通知获知配餐情况、查看配送员实时的地址位置,也可通过服务通知回访商家小程序,让商家获得更多线上的“回头客”。 点击查看,即时配送接口文档(内测中) 点击申请,即时配送接口内测权限 [图片] (物流工具箱服务示意图) 3. 如何快速拥有小程序 搭建小程序流程: 申请账号 - 开发 - 上线运营 小程序开发:支持具备开发能力的伙伴,按照小程序开发指引进行开发; 不具备开发能力的伙伴,可通过服务平台寻找服务商,完成小程序开发。 (需在获得小程序账号后,才能进行小程序开发) 申请小程序账号在搭建服务前,需先拥有一个小程序“身份证”,只要是具有独立开发能力的企业及商家,可通过提交资料注册小程序便可获得。支持公众号快速注册小程序,无公众号可通过线上流程进行注册。 点击获得能力详解指南 小程序开发,服务平台快速实现通过微信服务平台,你可搜索外卖、餐饮、零售等关键词,查询可提供开发服务的第三方服务商及其小程序案例,并与服务商取得联系。 为加速餐饮、零售行业到家类小程序落地,在疫情期间(2月-3月),部分服务商为外卖、到家小程序提供了优惠的开发方案,前往服务平台,在“共抗疫情-小程序服务专区”中了解明细: [图片] (服务平台,搜索外卖示意图) 小程序运营提升工具小程序上线后持续的优化运营是至关重要的环节,想要获得你的小程序运营状态与同行业的对比情况,与各个行业最新运营玩法与垂直行业资讯。微信行业助手为你提供小程序与同行业运营对比状态、微信官方能力详解、行业头部玩家的运营经验及一手行业资讯的工具。 同时为更好服务好各行业伙伴,诚邀你加入微信行业“领跑计划”,和我们一起探索更多场景。
2022-11-04