- 为什么小程序在备案时,提示负责人与小程序管理员不一致?
负责人这一栏填的不是管理员的信息吗? [图片]
2023-09-04 - 史上最强:一行代码解决隐私授权弹窗
// 以下代码复制到app.js首行 wx.onNeedPrivacyAuthorization && wx.onNeedPrivacyAuthorization((r, e) => { err });
2023-09-05 - Skyline渲染框架的头像合成小程序实例-比比头像生成 附uniapp源码
[图片] 2023 年国庆节就要到了,有粉丝问到今年是否可以出一款国庆头像生成小程序。 于是想到用微信新渲染引擎 skyline的新 API:Snapshot截图能力来完成 文档:https://developers.weixin.qq.com/miniprogram/dev/api/skyline/Snapshot.html [图片] 完成后,发现真的非常丝滑,它的原理就是先用<snapshot id="target">...</snapshot>将需要截图的区域包括起来,然后定义一个 ID, 接下来在脚本里通过createSelectorQuery()获取。 this.createSelectorQuery().select("#target") .node().exec(res => { const node = res[0].node node.takeSnapshot({ // type: 'file' 且 format: 'png' 时,可直接导出成临时文件 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') 。。 }, fail(res) { console.log("takeSnapshot fail:", res) } }) }) 比比小程序对选择器进行了封装,可搜索核心代码进行学习(全部代码见源码): getSelectorNodeInfo('#target').then((res) => { console.log('res', res) const node = res[0].node node.takeSnapshot({ type: 'arraybuffer', format: 'png', success: (res:any) => { const savePath = `${wx.env.USER_DATA_PATH}/hello.png` const fs = wx.getFileSystemManager(); fs.writeFileSync(savePath, res.data, 'binary'); //图片保存至本地 wx.showShareImageMenu({ //唤起分享图片的界面 path: savePath }) }, fail(res) { } }) }) 在此项目中也可以借鉴一下微信隐私弹窗的交互 [图片] [图片] 因为此项目仅用了1个小时完成,实在是没有太多的难点,主要是让大家对新的渲染引擎有一个全新的认识。 项目对skyline和webView都做了布局兼容,对于新手学习skyline是个不错的demo。 也可以看看我用 skyline搭建的第一个小程序: 比比轻壁纸:https://developers.weixin.qq.com/community/minihome/article/doc/0004ce2acf8020ac32af1ed5f51813 ----- 附上源码(uniapp+vue3+ts)和 demo: https://github.com/shiheme/skyline-wx-avatar https://gitee.com/h5gallery/skyline-wx-avatar [图片] 喜欢的给个star、点赞、留个评论,谢谢。 喜欢小程序开发的也可以加我微信或者关注我的公众号(github/gitee里扫码)一起学习成长。
2023-09-09 - 小游戏注册-备案-发布指南
一、流程图 [图片] 涉及步骤: (1)不开通虚拟支付游戏:7个步骤,预计需13 - 37个工作日 (2)开通虚拟支付游戏:10个步骤(含开通内购),预计需9 - 22个工作日 为提高上线效率,其中多个环节允许并行,如: (1) 【名称、简称、头像设置】 、 【类目设置】及【微信认证】支持并行 (2) 版本审核与资质审核支持并行(棋牌 - 牌类、文化互动除外) 注意事项:小游戏发布前,必须先完成微信认证和备案流程 二、注册、备案&上线步骤 第一步:注册账号1. 注册流程 小程序注册流程 2. 注册上限和绑定上限 小程序注册上限和绑定上限 第二步:名称、简称 & 图标设置1. 小程序名称、简称设置规范 小程序名称、简称设置规范 2. 办结时限 a. 正常情况:设置后直接生效 b. 命中名称保护词:1-3个工作日 c. 名称占用投诉:7个工作日+7个自然日名称保护期 3. 操作流程(1)常规流程 step1:首页,点击小程序信息“前往设置“ [图片] step2: -填写小程序(小游戏)名称 -填写小程序(小游戏)简称,选填 -设置小程序(小游戏)头像 -填写小程序(小游戏)介绍 step3:提交 [图片] (2)名字命中保护词流程 step1:填写小程序名称,提示命中保护词或涉及特定领域 [图片][图片] step2:在当前页面补充相关材料 -营业执照 -版号及相关授权书(依据系统提示补充) -商标及相关授权 (依据系统提示补充) -其他(依据系统提示补充) [图片] (3)名字被占用流程 step1: -填写小程序名称,提示名称与已有小程序名称重复 -查看同名账号,并记录id [图片] [图片] step2:发起侵权投诉 [图片] step3:依据系统指引,填写相关信息,并提交相关材料 [图片] step4:耐心等待平台处理,一般需时7个工作日。 -如投诉成功,则名称会在7个自然日保护期后释放; -如投诉不成功,建议依据系统提示补充材料或使用新的名称。 第三步:类目设置1. 办结时限 设置后直接生效 2. 注意事项 二级游戏类目在游戏发布后,不可修改,请认真设置 [图片] 3. 操作流程 step1:首页,点击小程序类目“前往设置“ [图片] step2:点击“添加类目,并使用管理员微信扫码验证 [图片] step3:“服务类目”选择“游戏”,二级游戏类目(文化互动、休闲、动作……)依据自身情况选择。 (请注意,如二级游戏类目与实际游戏内容不符,将会在提审版本时驳回,请谨慎选择) [图片] step4:设置成功 [图片] [图片] 注意事项一 (1) 第二步与第三步无先后顺序要求 (2) 当你完成第二步 及第三步 后,可直接提交资质审核及版本审核 第四步:微信认证(个人主体无需认证)1.办结时限 1-3个工作日 2.认证流程 小程序微信认证申请流程指引 3.特权 小程序微信认证有哪些特权 4.认证Q&A 小程序微信认证认证审核问题 第五步:选择是否开通虚拟支付1. 办结时限 选择后,进入相应引导流程 2. 注意事项 请根据自身资质情况谨慎选择,否则将影响游戏发布 3. 操作流程 step1:首页,设置-小程序备案,点击去完善 [图片] step2:根据自身资质情况选择 [图片] 第六步:资质审核1. 资质材料要求 (1) 非开通虚拟支付 [图片] (2) 开通虚拟支付 [图片] (3)主体迁移 [图片] 小游戏资质提交审核指引Q&A | 微信开放社区 2. 办结时限 正常情况:1-3个自然日 3. 操作流程 step1: MP首页 - 小程序备案 - 小游戏备案&发布流程指引 - 资质提交 [图片] 或设置-游戏设置-资质管理,点击”前往管理“ [图片] step2: -选择与游戏内容一致的游戏三级类目 -依据引导页的情况,选择是否同时申请支付资质 [图片] step3:上传资质材料 注意事项: (1) 请将材料上传至对应的模块,切勿错位上传(如著作权授权书上传至其他授权书);错位上传的材料,均会被驳回审核。 (2) 如同时申请支付,请注意版号、软著及相关授权书的格式、大小、数量要求。 a. 图片格式: 版号及版号授权书格式为 JPEG、JPG 软著文件为 JPEG、JPG、PNG、BMP、GIF、PDF 软著授权书为 JPEG、JPG、PNG、BMP b. 版号、版号授权书单个文件大小:≤ 200KB c. 软著、软著授权书单个文件大小:≤ 2M d. 版号文件限制最多1张(多于1张请按顺序自行合并) e. 版号授权书限制最多2张(多于2张请按顺序自行合并) f. 软著限制最多1张(多于1张请按顺序自行合并) g. 软著授权书限制最多2张(多于2张请按顺序自行合并) [图片] [图片] (3) 如同时申请支付,请谨慎选择“游戏运营权”关系,若选择错误,资质审核也将会被驳回。如版号刊载运营主体与本小程序账号主体不存在关联(控股/同一法人)关系,则需版号运营主体完成小额打款。 小额打款验证指引:小游戏小额打款验证 | 微信开放社区 [图片] step4:提交审核 [图片] 如提交审核后,发现材料需要改动,可操作撤回。 4. 撤回流程 路径:设置-游戏设置-资质管理,点击”撤回审核“ 注意事项: 提交的资质已进入审核队列,撤回审核后再次提交将重新排队审核。 [图片] 第七步:小程序备案1. 操作流程 step1:首页,设置-小程序备案,点击去完善 [图片] step2:展示相应的流程引导页面 (1)情况一: [图片] (2)情况二: [图片] 游戏内容介绍详细要求可查看: 各种类型游戏的内容介绍模版 内容介绍填写示例 2.办结时限 选择情况一,约5~12个工作日 选择情况二,约10~30个工作日 3. 操作指引 请见文档 小程序备案操作指引 | 微信开放文档 第八步:版本审核1. 提醒 版本审核通过,需在第七步“小程序备案”完成后,方可发布。 具体表现为:管局审核通过后,将下发的小程序备案号,代表你的小程序已完成备案,可以进入版本发布等流程。 2. 办结时限 正常情况:1个自然日 3. 操作流程 step1:版本管理-开发版本,点击”提交审核“ [图片] step2: -选择游戏开发对应的引擎 -完善用户隐私保护指引 小游戏落实《个人信息保护法》常见问题汇总 | 微信开放社区 -完成适龄提示设置 -填写版本更新说明 [图片] step3:上传宣传图(非必填) [图片] step4:提交版本审核 [图片] step5:版本审核通过后,即可发布上线 [图片] 加急流程 如有紧急需求(BUG修复/重大活动),可申请加急审核,加急审核需满足以下条件: (1)该小游戏版本属于更新版本,即:历史已有已通过的小游戏版本,首版本不可使用 (2) 剩余可用加急次数大于0。所有帐号每季度有2次加急次数,每年的1月、4月、7月、10月的1日刷新。过期次数不叠加。请谨慎选择申请加急 (3) 累计注册用户 > 5000 小游戏加急审核申请条件及相关说明 | 微信开放社区 [图片] 注意事项二 (1) 除特殊类目(牌类、文化互动)外,第六步资质审核提交后,无需等待审核结果,可直接进入第八步版本审核 (2) 特殊类目(牌类、文化互动),需第六步资质审核通过后,方可提交版本审核 (3) 无论什么类目,第六步资质审核通过后,方可进行第九步中宣部实名认证系统接入 第九步:中宣部实名认证系统接入1. 办结时长 1个工作日 2. 操作流程 微信小游戏接入中宣部实名认证系统流程指引 | 微信开放社区 第十步:开通虚拟支付1. 开通条件 (1) 主体类型为个体工商户或企业已认证小游戏 (2) 已接入中宣部实名认证系统 (3) 版号,软著自审自查报告及相关授权等资质审核通过 2. 办理指南 小游戏虚拟支付2.0开发指南(对外) 注意事项三 (1) 必须完成第四步、第六步、第九步,方可开通虚拟支付 (2) 第八步版本审核 与 第四步、第九步、第十步无串联关系,可先提审版本,再做微信认证、中宣实名及开通虚拟支付;或先做微信认证、中宣实名及开通虚拟支付,再提审版本 附录: 小游戏备案前置审批指引 各种类型游戏的内容介绍模版 游戏内容介绍填写示例
10-25 - 微信小程序隐私协议弹窗Uniapp组件
本插件参考文章,如需原生小程序的可以看这个:https://cloud.tencent.com/developer/article/23179601. 下载插件下载插件后将 /components/privacy-popup 文件夹复制到你项目的/components 目录下 2. 引入插件如果只在某些页面引入,在对应页面引入插件,例如:登录页或者注册页如果需要全局引入, 在 app.vue 引入js,在需要使用的页面引入template复制代码 复制代码 import PrivacyPopup from '@/components/privacy-popup/privacy-popup.vue'; export default { components: { PrivacyPopup }, data() { return { showPrivacyPopup: false, }; }, onLaunch: function() { }, onShow() { // #ifdef MP-WEIXIN // 在设置 showPrivacyPopup = true 后使用 $nextTick, if (wx.getPrivacySetting) { wx.getPrivacySetting({ success: (res) => { if (res.needAuthorization) { this.showPrivacyPopup = true; this.$nextTick(() => { if (this.$refs.privacyComponent) { this.$refs.privacyComponent.showPrivacy = true; } else { } }); } }, }); } // #endif }, () { }, onHide: function() { console.log('App Hide') } } 3. manifest.json切换为源码视图中添加usePrivacyCheck 复制代码 "mp-weixin" : { "__usePrivacyCheck__": true }, 组件地址:https://ext.dcloud.net.cn/plugin?id=14288
2023-08-28 - 最近新增的隐私弹窗相关api调用经验分享
我司的小程序是用uni-app开发的,在声明同意隐私协议的按钮时,参考官方文章 [代码]<button id="agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="handleAgreePrivacyAuthorization" > 同意 </button> [代码] [代码]methods: { handleAgreePrivacyAuthorization() { } } [代码] 在uni-app中,[代码]bindagreeprivacyauthorization[代码]要写成[代码]@agreeprivacyauthorization[代码],否则会报 [代码]Component "xxx" does not have a method "handleAgree" to handle event "agreeprivacyauthorization". [代码]
2023-08-28 - 适配隐私保护协议接口
1、相关api说明 适配过程中主要是用到了以下几个接口 1. wx.onNeedPrivacyAuthorization:用于监听隐私接口需要用户授权事件,只有当隐私协议需要用户授权时才会由平台触发此事件,然后开发者需要弹窗显示隐私协议说明。如果用户拒绝授权,则隐私接口调用失败,在下次调用到隐私接口时还会继续弹。 2. wx.requirePrivacyAuthorize:用于模拟隐私接口调用,并触发隐私弹窗逻辑,也就是会触发wx.onNeedPrivacyAuthorization,但如果用户之前已经同意过隐私授权,会立即返回success回调,不会触发 wx.onNeedPrivacyAuthorization 。这个api的使用场景目前我是用在获取用户昵称时,在下一篇文章会进行说明。 3. wx.openPrivacyContract:用于打开隐私协议页面。 其他api大家可以根据具体情况选择使用。 2、弹窗思路 其实就是写一个自定义组件,然后在有调用到隐私接口的页面引入,利用自定义组件的attached方法,把各个页面的隐私弹窗组件的显示、隐藏方法保存到自定义组件的全局变量中,当用户点击隐私协议弹窗的同意、拒绝按钮时调用resolve方法,将对应的参数通知给平台。 3、注意点 隐私接口在隐私保护指引中有声明才能调用基础库版本2.32.3及以上开始支持2023.9.15号之前,在 app.json 中配置 __usePrivacyCheck__: true 后,会启用隐私相关功能,如果不配置或者配置为 false 则不会启用。2023.9.15号之后,不论 app.json 中是否有配置 __usePrivacyCheck__,隐私相关功能都会启用wx.onNeedPrivacyAuthorization 是覆盖式注册监听,若重复注册监听,则只有最后一次注册会生效同意授权后如果想取消授权,在开发工具上 清缓存->清除模拟器缓存->清除授权数据,在手机上删除小程序即可隐私弹窗的z-index要设置成最大,避免被其他遮罩挡住导致无法点击,另外如果有调到官方的api例如wx.showLoading,也要注意是否设置了mask,避免在loading的时候弹出隐私弹窗,导致弹窗无法点击,而loading又要等弹窗关闭才会消失的尴尬情况4、代码如下 4.1、app.json "usingComponents": { //全局自定义组件 "privacyPopup": "/components/privacy/privacyPopup" }, //开启隐私相关功能 "__usePrivacyCheck__": true 4.2、自定义组件privacyPopup 4.2.1、privacyPopup.wxml <view class="container" wx:if="{{show}}"> <view class="cover {{showCoverAnimation?'cover-fade-in':''}}" catch:touchmove="return"></view> <view class="privacy-box {{showBoxAnimation?'slade-in':''}} {{device.isPhoneX? 'phx_68':''}}" catch:touchmove="return"> <view class="title flex-start-horizontal"> <view class="logo" wx:if="{{privacyConfig.icon}}"> <image class="icon" src="{{privacyConfig.icon}}"></image> </view> <view class="mini-name">{{privacyConfig.name || '小程序'}}</view> </view> <view class="tips"> <view class="privacy-content"> <view class="start">{{privacyConfig.content.start}}</view> <view class="link" bindtap="openPrivacyContract"> {{privacyConfig.content.mid}} </view> <view class="end">{{privacyConfig.content.end}}</view> </view> </view> <view class="buttons flex-center"> <button class="cancel reset-btn" bindtap="disagree">拒绝</button> <button class="save reset-btn" id="agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="agree">同意</button> </view> </view> </view> 4.2.2、privacyPopup.wxss @import "/app.wxss"; .cover{ background-color: #111; opacity: 0; position: fixed; left: 0; top: 0; right: 0; bottom: 0; z-index: 50000; transition: opacity .3s; } .privacy-box{ position: fixed; left: 0rpx; right: 0rpx; bottom: 0rpx; z-index: 51000; background-color: #fff; box-sizing: border-box; padding-top: 60rpx; padding-left: 50rpx; padding-right: 50rpx; border-radius: 30rpx 30rpx 0 0; transform: translateY(100%); transition: transform .3s, bottom .3s; } .cover-fade-in{ opacity: 0.7; } .slade-in{ transform: translateY(0); bottom: 0rpx; } .privacy-box .title{ font-size: 32rpx; font-weight: 500; text-align: center; margin-bottom: 40rpx; color: #161616; } .privacy-box .title .icon{ width: 46rpx; height: 46rpx; margin-right: 8rpx; vertical-align: bottom; border-radius: 50%; } .privacy-box .title .mini-name{ /*margin-bottom: 2rpx;*/ } .privacy-box .tips{ margin-bottom: 20rpx; } .privacy-box .tips .privacy-content{ color: #606266; font-size: 30rpx; margin-bottom: 20rpx; line-height: 1.6; } .privacy-box .tips .privacy-content .start, .privacy-box .tips .privacy-content .link, .privacy-box .tips .privacy-content .end { display: inline; } .privacy-box .tips .privacy-content .link{ color: #1890FF; } .privacy-box .buttons{ margin-bottom: 40rpx; margin-top: 50rpx; text-align: center; font-size: 34rpx; font-weight: 550; } .privacy-box .buttons .save{ width: 220rpx !important; height: 90rpx; line-height: 90rpx; border-radius: 14rpx; color: #fff; /*background:#fff linear-gradient(90deg,rgba(246, 120, 121,.9) 10%, rgb(246, 120, 121));*/ background-color: #07c160; margin-left: -50rpx; } .privacy-box .buttons .cancel{ width: 220rpx !important; height: 90rpx; line-height: 90rpx; border-radius: 14rpx; color: #07c160; background-color: #F2F2F2; } 4.2.3、privacyPopup.js //获取应用实例 const tabbar = require("../../utils/tabbar.js"); const app = getApp(); //用来保存各个页面注册的隐私协议回调事件 let privacyHooks = {}; if (wx.onNeedPrivacyAuthorization) { console.warn("当前基础库支持api wx.onNeedPrivacyAuthorization"); wx.onNeedPrivacyAuthorization(resolve => { console.warn("需要隐私协议弹窗:", resolve); const pages = getCurrentPages(); const route = pages[pages.length - 1].route; const hook = privacyHooks[route]; if (hook) { hook.resolve = resolve; hook.show(resolve); } else { console.error("当前页面没有注册隐藏协议弹窗回调:", route); } }) } else { console.warn("当前基础库不支持api wx.onNeedPrivacyAuthorization"); } Component({ data: { show: false, showCoverAnimation: false,//显示类别选择窗口动画 showBoxAnimation: false,//显示类别选择窗口动画 }, lifetimes: { //在组件实例进入页面节点树时执行 attached: function () { console.warn("privacyPopup attached"); const pages = getCurrentPages(); privacyHooks[pages[pages.length - 1].route] = { show: resolve => { this.show(resolve); }, close: () => { this.hide(); } } }, //在组件实例被从页面节点树移除时执行 detached: function () { console.warn("privacyPopup detached"); } }, methods: { /** * 同意隐私协议 * @param e */ agree(e) { Object.values(privacyHooks).forEach(hook => { hook.close(); hook.resolve && hook.resolve({ event: "agree", buttonId: "agree-btn" }); }); }, /** * 不同意隐私协议 * @param e */ disagree(e) { Object.values(privacyHooks).forEach(hook => { hook.close(); hook.resolve && hook.resolve({ event: "disagree" }); }); }, /** * 显示隐私协议授权弹窗 */ show(resolve) { app.fillConfig(this, ["privacyConfig"], data => { console.log("显示隐私协议弹窗"); const device = app.getSystemInfo(); this.setData({ show: true, device, }, () => { this.setData({ showCoverAnimation: true, showBoxAnimation: true }); //自定义隐私弹窗曝光告知平台 resolve({event: "exposureAuthorization"}); }); tabbar.hideTabByPrivacy(this); }); }, /** * 关闭隐私协议授权弹窗 */ hide() { console.log("隐藏隐私协议弹窗"); this.setData({ showCoverAnimation: false, showBoxAnimation: false }, () => { const that = this; setTimeout(function () { that.setData({ show: false }) }, 300) }) tabbar.showTabByPrivacy(this); }, /** * 打开隐私协议 */ openPrivacyContract() { wx.openPrivacyContract({ success: res => { console.log("openPrivacyContract success") }, fail: res => { console.error("openPrivacyContract fail", res) } }) } } }) 5、弹窗效果 [图片]
2023-09-13 - 小程序代码一键上传,告别慢吞吞的开发者工具
[图片] 如上,除了在开发者工具里上传代码, 我们现在还能借助微信开发者工具提供的 miniprogram-ci 库,实现一键上传。 这对需要批量上传多个工程代码,提供了极大的便捷。 我们来尝试下。 新建一个[代码]upload.js[代码]文件,存放我们的上传脚本 touch upload.js 引入[代码]miniprogram-ci[代码]库 npm i miniprogram-ci --save 在代码里引入 const ci = require('miniprogram-ci'); 借助[代码]miniprogram-ci[代码]库提供的[代码]upload[代码]API,我们来写下: ; (async () => { const project = new ci.Project({ appid: 'xxx', type: 'miniProgram', projectPath: 'the/path/to/project', privateKeyPath: 'the/path/to/privatekey', ignores: ['node_modules/**/*'], }) const uploadResult = await ci.upload({ project, version: '版本号', desc: '项目备注', setting: { es6: true, }, onProgressUpdate: console.log, }) console.log('uploadResult:', uploadResult); })() 这里有几个参数需要说明下: appid是需要上传的小程序的appidprojectPath填写工程所在的目录privateKeyPath填写秘钥所在目录version和desc对应图一截图里的版本号和项目备注 到这一步,我们上传代码的脚本,已经万事俱备了,还差一阵东风。 我们需要搞到,上传的秘钥,也就是上文提到的[代码]privateKeyPath[代码]。 使用小程序管理员身份访问"微信公众平台-开发-开发设置"后下载代码上传密钥,并配置 IP 白名单。 [图片] 这里我不开启ip白名单,方便测试,但您务必明白风险。 OK,我们来执行下[代码]uplaod.js[代码]脚本。 node upload.js 当看到控制台输出如下信息后,即表示已成功上传。 [图片] 登录小程序后台,我们也能看到本次的提交记录了。 [图片] 至此,我们已初步跑通小程序代码上传的脚本。 执行上传脚本的过程,实际是会对工程代码做 预编译检查。 比如我们在工程代码里,故意定义两个同名的变量。 [图片] 会在执行脚本的时候报错如下: [图片] 回看之前的上传脚本,有一个细节还是可以值得优化下。 我们注意到,[代码]upload[代码]的[代码]API[代码]有提供一个上传进度更新监听函数[代码]onProgressUpdate[代码]。 上述的代码,只是简单接入[代码]console.log[代码],把进度输出到控制台。 我们可以优化下: 定义一个回调函数[代码]cb[代码],实现两个功能: 对过回调里的字符串做过滤,记录上传的“文件名”。如有报错,标识出来 来看代码(其中借助kuler库做字符串着色): const uploadSucFiles = []; let haveError = false; const cb = output => { if (haveError) return; if (!!output.code) { haveError = true; console.log(output); console.log(kuler('something wrong is happened.pleace check.', '#ff4d4f')); return; } const allowSuffixs = ['js', 'json', 'wxml', 'wxss', 'ts', 'less', 'sass']; const curSuffix = output._msg.slice(output._msg.lastIndexOf('.') + 1); // 按后缀筛选 _msg if ( allowSuffixs.indexOf(curSuffix) >= 0 && output._status === 'done' ) { uploadSucFiles.push(`${output._msg} ${kuler('is uploaded.', '#2da44e')}`); // clear terminal output console.clear(); console.log(uploadSucFiles.join('\n')); } }; // 调用 const uploadResult = await ci.upload({ project, version: '版本号', desc: '项目备注', setting: { es6: true, }, onProgressUpdate: cb, }) 修饰后的控制台输出,如下截图,有点打包上传的那味了😛。 [图片] 出错时,直接打印调用栈,红色提示 [图片] 最后 我们来看下完整的[代码]upload.js[代码]文件。 const ci = require('miniprogram-ci'); const kuler = require('kuler'); const uploadSucFiles = []; let haveError = false; const cb = output => { if (haveError) return; if (!!output.code) { haveError = true; console.log(output); console.log(kuler('something wrong is happened.pleace check.', '#ff4d4f')); return; } const allowSuffixs = ['js', 'json', 'wxml', 'wxss', 'ts', 'less', 'sass']; const curSuffix = output._msg.slice(output._msg.lastIndexOf('.') + 1); // 按后缀筛选 _msg if ( allowSuffixs.indexOf(curSuffix) >= 0 && output._status === 'done' ) { uploadSucFiles.push(`${output._msg} ${kuler('is uploaded.', '#2da44e')}`); // clear terminal output console.clear(); console.log(uploadSucFiles.join('\n')); } }; ; (async () => { try { const project = new ci.Project({ appid: 'wx202120212021', type: 'miniProgram', projectPath: './wx202120212021', privateKeyPath: './private.wx202120212021.key', ignores: ['node_modules/**/*'], }) const uploadResult = await ci.upload({ project, version: '版本号', desc: '项目备注', setting: { es6: true, }, onProgressUpdate: cb, }) // console.log('uploadResult:', uploadResult); console.log('\n'); console.log(`${kuler('upload success~', '#ff5722')} 🎉🥳`); } catch (error) { cb(error); } })() 整个目录结构 [图片] 工程也已上传到github了,看这里miniprogram-ci-onestep。 clone下来后,需要自行替换对应的文件名和上传秘钥。 另外 miniprogram-ci库除了支持 node 脚本调用方式,还支持命令行调用。 安装 npm install -g miniprogram-ci 示例 miniprogram-ci \ upload \ --pp ./demo-proj/ \ --pkp ./private.YOUR_APPID.key \ --appid YOUR_APPID \ --uv PACKAGE_VERSION \ -r 1 \ --enable-es6 true \
2021-12-27