- 关于虚拟支付的汇总整理
本文场景 在iso端做支付,虚拟支付问题是绕不过去,没有处理好,轻则封禁搜索,重则永久封号,所以对待这个问题不可谓不慎重 本文内容本文主要汇总社区相关的几个经典帖子,特别是带有官方回复的帖子,进行截图,最后做一个总结 截图一 [图片] 截图二 [图片] 截图三 [图片] 截图四 [图片] 参考文章 为什么“小鹅通”的小程序可以做虚拟支付?? - 微信开放社区 https://developers.weixin.qq.com/community/develop/doc/84ef0895eb9e4261b114a88d73dc7621 所谓的小程序IOS不允许虚拟支付到底限制的是谁?? - 微信开放社区 https://developers.weixin.qq.com/community/develop/article/doc/000246265d01201064ea17bc65b813 实名举报手机充值小程序虚拟支付可以正常使用?? - 微信开放社区 https://developers.weixin.qq.com/community/develop/doc/00066aedd70a907b38ea5043856400 跑腿小程序,支付跑腿费,属于虚拟支付吗?可以在ios里进行支付吗?? - 微信开放社区 https://developers.weixin.qq.com/community/develop/doc/0002e8ec24cbd0f29cba2e28156400 虚拟业务指南请收好。? - 微信开放社区 https://developers.weixin.qq.com/community/develop/doc/000cc6c0b383a047c7798e0045b409 本文总结关于虚拟支付的整理 关于一个支付业务到底是不是虚拟支付,在有参考的情况,可以根据官方的 上面社区的锅巴同学整理的非常详细,给出了官方明确定义为非虚拟支付的6种情况 以下内容摘录自锅巴同学的社区回帖内容 小程序在线直播课程,充值加油卡,手机流量等这6种,不算小程序虚拟支付,请参照以下6种情况即可,因为你不符合这6种情况,所以被判定为违规 ① 小程序在线课程直播。用户先买课程,后续在线上安排老师在小程序直播。补充选择教育-在线视频课程类目 ② 线上报名活动,线下培训的类型 ③ 充值加油卡加油,涉及预付卡销售服务,补充商家自营-预付卡销售类目 ④ 充值手机流量,补充IT科技-电信运营商类目 ⑤ 悬赏问答功能,需选择社交红包-社交红包类目,并完成新商户号申请后,再提交代码审核。 ⑥ 微信支付充值积分,签到积分等,积分兑换实物商品,兑换成功后,会直接给用户寄过去。有实际服务存在 最后总结下 你所认为的虚拟支付可能并不是虚拟支付,你所强调的非虚拟支付也有可能被定义为虚拟支付,所以一切以官方口径为依据。
2020-09-07 - Android 13 从微信内可能无法回跳到第三方App
由于,从 Android 13 开始Intent过滤器会屏蔽不匹配的intent。详见Android官网关于Andorid13变更说明。因此,当满足以下两个条件时,微信内可能将无法回跳到第三方App。 1、开发者在Manifest内声明 WXEntryActivity 时,添加了 intent-filter 2、开发者的 APP 运行在 Android 13 的手机上 解决办法 在 manifest 中,尝试去除 WXEntryActivity 的 intent-filter。具体写法应该遵照上面接入方案中提到的示例,参考如下: [图片] 更多关于 OpenSDK 接入说明可前往 Android接入指南 查看
2023-11-29 - 多端框架用户成功案例
Donut 多端框架是小程序团队推出的移动应用开发框架。开发者可以使用小程序技术与工具,高效率开发移动应用,实现一次开发多端运行。现在已有不同领域的开发者选择多端框架,实现更高的开发经营效率。
07-10 - 小程序多端框架全面测评:chameleon、Taro、uni-app、mpvue、WePY
作者:coldsnap 原文:小程序多端框架全面测评 Fundebug经授权转载,版权归原作者所有。 最近前端届多端框架频出,相信很多有代码多端运行需求的开发者都会产生一些疑惑:这些框架都有什么优缺点?到底应该用哪个? 作为 Taro 开发团队一员,笔者想在本文尽量站在一个客观公正的角度去评价各个框架的选型和优劣。但宥于利益相关,本文的观点很可能是带有偏向性的,大家可以带着批判的眼光去看待,权当抛砖引玉。 那么,当我们在讨论多端框架时,我们在谈论什么: 多端 笔者以为,现在流行的多端框架可以大致分为三类: 1. 全包型 这类框架最大的特点就是从底层的渲染引擎、布局引擎,到中层的 DSL,再到上层的框架全部由自己开发,代表框架是 Qt 和 Flutter。这类框架优点非常明显:性能(的上限)高;各平台渲染结果一致。缺点也非常明显:需要完全重新学习 DSL(QML/Dart),以及难以适配中国特色的端:小程序。 这类框架是最原始也是最纯正的的多端开发框架,由于底层到上层每个环节都掌握在自己手里,也能最大可能地去保证开发和跨端体验一致。但它们的框架研发成本巨大,渲染引擎、布局引擎、DSL、上层框架每个部分都需要大量人力开发维护。 2. Web 技术型 这类框架把 Web 技术(JavaScript,CSS)带到移动开发中,自研布局引擎处理 CSS,使用 JavaScript 写业务逻辑,使用流行的前端框架作为 DSL,各端分别使用各自的原生组件渲染。代表框架是 React Native 和 Weex,这样做的优点有: 开发迅速 复用前端生态 易于学习上手,不管前端后端移动端,多多少少都会一点 JS、CSS 缺点有: 交互复杂时难以写出高性能的代码,这类框架的设计就必然导致 [代码]JS[代码] 和 [代码]Native[代码] 之间需要通信,类似于手势操作这样频繁地触发通信就很可能使得 UI 无法在 16ms 内及时绘制。React Native 有一些声明式的组件可以避免这个问题,但声明式的写法很难满足复杂交互的需求。 由于没有渲染引擎,使用各端的原生组件渲染,相同代码渲染的一致性没有第一种高。 3. JavaScript 编译型 这类框架就是我们这篇文章的主角们:[代码]Taro[代码]、[代码]WePY[代码] 、[代码]uni-app[代码] 、 [代码]mpvue[代码] 、 [代码]chameleon[代码],它们的原理也都大同小异:先以 JavaScript 作为基础选定一个 DSL 框架,以这个 DSL 框架为标准在各端分别编译为不同的代码,各端分别有一个运行时框架或兼容组件库保证代码正确运行。 这类框架最大优点和创造的最大原因就是小程序,因为第一第二种框架其实除了可以跨系统平台之外,也都能编译运行在浏览器中。(Qt 有 Qt for WebAssembly, Flutter 有 Hummingbird,React Native 有 [代码]react-native-web[代码], Weex 原生支持) 另外一个优点是在移动端一般会编译到 React Native/Weex,所以它们也都拥有 Web 技术型框架的优点。这看起来很美好,但实际上 React Native/Weex 的缺点编译型框架也无法避免。除此之外,编译型框架的抽象也不是免费的:当 bug 出现时,问题的根源可能出在运行时、编译时、组件库以及三者依赖的库等等各个方面。在 Taro 开源的过程中,我们就遇到过 Babel 的 bug,React Native 的 bug,JavaScript 引擎的 bug,当然也少不了 Taro 本身的 bug。相信其它原理相同的框架也无法避免这一问题。 但这并不意味着这类为了小程序而设计的多端框架就都不堪大用。首先现在各巨头超级 App 的小程序百花齐放,框架会为了抹平小程序做了许多工作,这些工作在大部分情况下是不需要开发者关心的。其次是许多业务类型并不需要复杂的逻辑和交互,没那么容易触发到框架底层依赖的 bug。 那么当你的业务适合选择编译型框架时,在笔者看来首先要考虑的就是选择 DSL 的起点。因为有多端需求业务通常都希望能快速开发,一个能够快速适应团队开发节奏的 DSL 就至关重要。不管是 React 还是 Vue(或者类 Vue)都有它们的优缺点,大家可以根据团队技术栈和偏好自行选择。 如果不管什么 DSL 都能接受,那就可以进入下一个环节: 生态 以下内容均以各框架现在(2019 年 3 月 11 日)已发布稳定版为标准进行讨论。 1. 开发工具 就开发工具而言 [代码]uni-app[代码] 应该是一骑绝尘,它的文档内容最为翔实丰富,还自带了 IDE 图形化开发工具,鼠标点点点就能编译测试发布。 其它的框架都是使用 CLI 命令行工具,但值得注意的是 [代码]chameleon[代码] 有独立的语法检查工具,[代码]Taro[代码] 则单独写了 ESLint 规则和规则集。 在语法支持方面,[代码]mpvue[代码]、[代码]uni-app[代码]、[代码]Taro[代码] 、[代码]WePY[代码] 均支持 TypeScript,四者也都能通过 [代码]typing[代码] 实现编辑器自动补全。除了 API 补全之外,得益于 TypeScript 对于 JSX 的良好支持,Taro 也能对组件进行自动补全。 CSS 方面,所有框架均支持 [代码]SASS[代码]、[代码]LESS[代码]、[代码]Stylus[代码],Taro 则多一个 [代码]CSS Modules[代码] 的支持。 所以这一轮比拼的结果应该是: uni-app > Taro > chameleon > WePY、mpvue [图片] 2. 多端支持度 只从支持端的数量来看,[代码]Taro[代码] 和 [代码]uni-app[代码] 以六端略微领先(移动端、H5、微信小程序、百度小程序、支付宝小程序、头条小程序),[代码]chameleon[代码] 少了头条小程序紧随其后。 但值得一提的是 [代码]chameleon[代码] 有一套自研多态协议,编写多端代码的体验会好许多,可以说是一个能戳到多端开发痛点的功能。[代码]uni-app[代码] 则有一套独立的条件编译语法,这套语法能同时作用于 [代码]js[代码]、样式和模板文件。[代码]Taro[代码] 可以在业务逻辑中根据环境变量使用条件编译,也可以直接使用条件编译文件(类似 React Native 的方式)。 在移动端方面,[代码]uni-app[代码] 基于 [代码]weex[代码] 定制了一套 [代码]nvue[代码] 方案 弥补 [代码]weex[代码] API 的不足;[代码]Taro[代码]则是暂时基于 [代码]expo[代码] 达到同样的效果;[代码]chameleon[代码] 在移动端则有一套 SDK 配合多端协议与原生语言通信。 H5 方面,[代码]chameleon[代码] 同样是由多态协议实现支持,[代码]uni-app[代码] 和 [代码]Taro[代码] 则是都在 H5 实现了一套兼容的组件库和 API。 [代码]mpvue[代码] 和 [代码]WePY[代码] 都提供了转换各端小程序的功能,但都没有 h5 和移动端的支持。 所以最后一轮对比的结果是: chameleon > Taro、uni-app > mpvue > WePY [图片] 3. 组件库/工具库/demo 作为开源时间最长的框架,[代码]WePY[代码] 不管从 Demo,组件库数量 ,工具库来看都占有一定优势。 [代码]uni-app[代码] 则有自己的插件市场和 UI 库,如果算上收费的框架和插件比起 [代码]WePy[代码] 也是完全不遑多让的。 [代码]Taro[代码] 也有官方维护的跨端 UI 库 [代码]taro-ui[代码] ,另外在状态管理工具上也有非常丰富的选择(Redux、MobX、dva),但 demo 的数量不如前两个。但 [代码]Taro[代码] 有一个转换微信小程序代码为 Taro 代码的工具,可以弥补这一问题。 而 [代码]mpvue[代码] 没有官方维护的 UI 库,[代码]chameleon[代码] 第三方的 demo 和工具库也还基本没有。 所以这轮的排序是: WePY > uni-app 、taro > mpvue > chameleon [图片] 4. 接入成本 接入成本有两个方面: 第一是框架接入原有微信小程序生态。由于目前微信小程序已呈一家独大之势,开源的组件和库(例如 [代码]wxparse[代码]、[代码]echart[代码]、[代码]zan-ui[代码] 等)多是基于原生微信小程序框架语法写成的。目前看来 [代码]uni-app[代码] 、[代码]Taro[代码]、[代码]mpvue[代码] 均有文档或 demo 在框架中直接使用原生小程序组件/库,[代码]WePY[代码] 由于运行机制的问题,很多情况需要小改一下目标库的源码,[代码]chameleon[代码] 则是提供了一个按步骤大改目标库源码的迁移方式。 第二是原有微信小程序项目部分接入框架重构。在这个方面 Taro 在京东购物小程序上进行了大胆的实践,具体可以查看文章《Taro 在京东购物小程序上的实践》。其它框架则没有提到相关内容。 而对于两种接入方式 Taro 都提供了 [代码]taro convert[代码] 功能,既可以将原有微信小程序项目转换为 Taro 多端代码,也可以将微信小程序生态的组件转换为 Taro 组件。 所以这轮的排序是: Taro > mpvue 、 uni-app > WePY > chameleon 流行度 从 GitHub 的 star 来看,[代码]mpvue[代码] 、[代码]Taro[代码]、[代码]WePY[代码] 的差距非常小。从 NPM 和 CNPM 的 CLI 工具下载量来看,是 Taro(3k/week)> mpvue (2k/w) > WePY (1k/w)。但发布时间也刚好反过来。笔者估计三家的流行程度和案例都差不太多。 [代码]uni-app[代码] 则号称有上万案例,但不像其它框架一样有一些大厂应用案例。另外从开发者的数量来看也是 [代码]uni-app[代码] 领先,它拥有 20+ 个 QQ 交流群(最大人数 2000)。 所以从流行程度来看应该是: uni-app > Taro、WePY、mpvue > chameleon [图片] 5. 开源建设 一个开源作品能走多远是由框架维护团队和第三方开发者共同决定的。虽然开源建设不能具体地量化,但依然是衡量一个框架/库生命力的非常重要的标准。 从第三方贡献者数量来看,[代码]Taro[代码] 在这一方面领先,并且 [代码]Taro[代码] 的一些核心包/功能(MobX、CSS Modules、alias)也是由第三方开发者贡献的。除此之外,腾讯开源的 [代码]omi[代码] 框架小程序部分也是基于 Taro 完成的。 [代码]WePY[代码] 在腾讯开源计划的加持下在这一方面也有不错的表现;[代码]mpvue[代码] 由于停滞开发了很久就比较落后了;可能是产品策略的原因,[代码]uni-app[代码] 在开源建设上并不热心,甚至有些部分代码都没有开源;[代码]chameleon[代码] 刚刚开源不久,但它的代码和测试用例都非常规范,以后或许会有不错的表现。 那么这一轮的对比结果是: Taro > WePY > mpvue > chameleon > uni-app 最后补一个总的生态对比图表: [图片] 未来 从各框架已经公布的规划来看: [代码]WePY[代码] 已经发布了 [代码]v2.0.alpha[代码] 版本,虽然没有公开的文档可以查阅到 [代码]2.0[代码] 版本有什么新功能/特性,但据其作者介绍,[代码]WePY 2.0[代码] 会放大招,是一个「对得起开发者」的版本。笔者也非常期待 2.0 正式发布后 [代码]WePY[代码] 的表现。 [代码]mpvue[代码] 已经发布了 [代码]2.0[代码] 的版本,主要是更新了其它端小程序的支持。但从代码提交, issue 的回复/解决率来看,[代码]mpvue[代码] 要想在未来有作为首先要打消社区对于 [代码]mpvue[代码]不管不顾不更新的质疑。 [代码]uni-app[代码] 已经在生态上建设得很好了,应该会在此基础之上继续稳步发展。如果 [代码]uni-app[代码] 能加强开源开放,再加强与大厂的合作,相信未来还能更上一层楼。 [代码]chameleon[代码] 的规划比较宏大,虽然是最后发的框架,但已经在规划或正在实现的功能有: 快应用和端拓展协议 通用组件库和垂直类组件库 面向研发的图形化开发工具 面向非研发的图形化页面搭建工具 如果 [代码]chameleon[代码] 把这些功能都做出来的话,再继续完善生态,争取更多第三方开发者,那么在未来 [代码]chameleon[代码] 将大有可为。 [代码]Taro[代码] 的未来也一样值得憧憬。Taro 即将要发布的 [代码]1.3[代码] 版本就会支持以下功能: 快应用支持 Taro Doctor,自动化检查项目配置和代码合法性 更多的 JSX 语法支持,1.3 之后限制生产力的语法只有 [代码]只能用 map 创造循环组件[代码] 一条 H5 打包体积大幅精简 同时 [代码]Taro[代码] 也正在对移动端进行大规模重构;开发图形化开发工具;开发组件/物料平台以及图形化页面搭建工具。 结语 那说了那么多,到底用哪个呢? 如果不介意尝鲜和学习 DSL 的话,完全可以尝试 [代码]WePY[代码] 2.0 和 [代码]chameleon[代码] ,一个是酝酿了很久的 2.0 全新升级,一个有专门针对多端开发的多态协议。 [代码]uni-app[代码] 和 [代码]Taro[代码] 相比起来就更像是「水桶型」框架,从工具、UI 库,开发体验、多端支持等各方面来看都没有明显的短板。而 [代码]mpvue[代码] 由于开发一度停滞,现在看来各个方面都不如在小程序端基于它的 [代码]uni-app[代码] 。 当然,Talk is cheap。如果对这个话题有更多兴趣的同学可以去 GitHub 另行研究,有空看代码,没空看提交: chameleon: https://github.com/didi/chameleon mpvue: https://github.com/Meituan-Dianping/mpvue Taro: https://github.com/NervJS/taro uni-app: https://github.com/dcloudio/uni-app WePY: https://github.com/Tencent/wepy (按字母顺序排序)
2019-06-18 - 【干货分享】如何玩转微信视频号直播接口?
一、背景 在7月份,微信小程序上线了跳转视频号直播的功能,我们也在第一时间发布了直播悬浮窗组件,使商家能够更便捷的将用户导流至视频号直播,促进成交。在近期,微信又上线了小程序预约直播功能,更加丰富了小程序与视频号之间的互动,我们也在微页面中新增了相关组件,帮助商家接入该功能。 二、实际效果 1、视频号直播悬浮窗 点击可跳转视频号直播间。该组件无需配置,商家直播时便会在页面上展示。 [图片] 2、视频号直播组件 需要商家在后台微页面配置,只要商家在视频号直播中创建预告,即可出现预约状态,支持用户点击预约 [图片] 点击预约后 [图片] 预约之后,在直播开始时,将会有消息推送提醒用户进直播间: [图片] 若直播已开始,则会展示直播中的状态,点击跳转直播间 [图片][图片] 三、对接微信接口 1、小程序跳转视频号直播间 开发者首先通过wx.getChannelsLiveInfo传入视频号id用于获取视频号直播信息,包括直播id(feedId与nonceId两个参数)与直播状态。其中直播状态含义如下: status=2:直播中,此时返回的feedId与nonceId为当前直播idstatus=3:直播已结束,此时返回的feedId与nonceId为最近一次直播id获取直播信息后,开发者可以通过wx.openChannelsLive打开视频号直播。若当前未在直播,则会跳转到最近一场直播的结束页。该接口使用限制如下: 需要用户触发跳转,若用户未点击小程序页面任意位置,则开发者将无法调用此接口。需要用户确认跳转,在跳转至视频号直播前,将统一增加弹窗,询问是否跳转,用户确认后才可以跳转视频号直播。在调试wx.getChannelsLiveInfo接口时比较麻烦的是需要在真机上测试,在开发者工具上,接口无法正常获取信息,会报告如下错误: {"errMsg":"getChannelsLiveInfo:fail","err_code":"-14"} 当然在真机上也得注意获取的是同一主体的视频号直播信息,否则会报告如下错误: {"errMsg":"getChannelsLiveInfo:fail data unknow error code","err_code":"100008"} 成功获取到视频号直播信息后,就可以调用wx.openChannelsLive进行直播间跳转,可能是为了防止开发者滥用此功能,微信要求必须用户点击小程序页面任意位置才能触发此接口,这句话说的有点模糊,到底是说用户点击后,就可以在任意时间调用此接口,还是每次调用都需要用户点击。在实际测试了之后发现,每次调用都需要用户点击,也就是需要在点击回调事件中调用,并且这里还有一点要注意,不能将调用写在promise或者setTimeout中,如: setTimeout(() => { wx.openChannelsLive() }, 0); Promise.resolve().then(() => { wx.openChannelsLive(); }); 这样也会导致接口调用失败。 四、小程序内发起预约视频号直播 预约也是分两步走 开发者首先通过wx.getChannelsLiveNoticeInfo传入视频号id用于获取视频号直播预告id(noticeId),若当前没有可预约的直播预告,将返回失败。获取直播预告信息后,开发者可以通过wx.reserveChannelsLive唤起预约弹窗,用户可以进行预约操作。成功唤起弹窗即为接口调用成功,通过state可以获取用户具体操作行为。获取预告信息会给到如下信息: [图片] 其中noticeId是用于后续预约预告用的,没什么可说的,比较让人疑惑的是status和reservable字段,你可能会将status理解成目前的预告状态,reservable理解成用户是否已预约,没毛病,笔者刚开始也是那么理解的,但真实调用后发现status只会存在0这种状态,如果预告被取消了或者已用,那直接就走到fail回调里面了。而reservable也不是是否已预约的意思,不管用户是否预约,该字段都是返回true。 所以,status和reservable字段目前给不到更多有价值的信息(后期可能会调整),若你想得知用户是否已预约,只能自己写接口去记录了。 获取直播预告信息后,开发者可以通过wx.reserveChannelsLive唤起预约弹窗,不同于跳转直播间,预约弹窗可随时唤起,不需要用户有点击操作,且支持在异步回调中调用。 [图片] 预约弹窗唤起后,根据用户的行为,会在success回调中返回相应的state值: [图片] 这里特别要说明的是,如果是正在直播中的状态,wx.reserveChannelsLive不再会唤起预约弹窗,而是直接唤起跳转直播弹窗,与wx.openChannelsLive的效果类似: [图片] 关于视频号预告,还有一点冷知识,当实际时间到达预告时间时,预告不会立即消失,而是会再保持一个小时,若一个小时后还未开始直播,预告才会被移除,并且在移除之前,预约相关的接口都可以正常调用。 五、总结 本文主要介绍了小程序对于视频号直播预约、跳转的支持,以及实际对接过程中遇到的一些问题,若想了解如何在视频号直播卖货可移步至https://help.youzan.com/displaylist/detail_4_4-2-54639 六、一些期待 目前视频号直播的功能都必须在同一主体下才能使用,希望微信能够早日放开这一限制。给到用户与开发者的直播数据过少,希望微信能够开放更多的直播数据,帮助用户分析直播效果,提升直播质量。
2021-11-25 - 【干货分享】小程序自定义交易组件开通及打通视频号场景
想要在视频号中拥有交易购物能力,必须接入交易组件,目前包含标准版交易组件和自定义版交易组件两种接入方案,以下是微信给出的对比及适用场景。 [图片] 因为有赞已经为商家小程序提供了完善的电商能力,所以自定义交易组件的方案更适合有赞商家小程序来对接微信视频号。 本文主要分享自定义交易组件开通的流程以及基于有赞场景去接入的时候遇到的一些坑,希望能帮助到大家!~ 一、总流程[图片] 二 、开通微信小程序 这个不必多说,但需要注意的是 1、必须是一个非个人主体的小程序 2、小程序类目需要符合下图要求 [图片] 三、开通微信支付后续的订单创建、同步会拉起微信的收银台完成支付,所以需要小程序开通微信支付的能力 四、检查是否已经开通标准版交易组件标准版和自定义版交易组件是二选一的,所以需要先检查是否开通了标准版交易组件 如果已经开通标准版但没有完成开店任务的话还是可以在微信后台取消使用的; 但如果连开店任务也完成的话,需要先注销(目前微信还没有开放注销功能),如果是有赞的商家的话可以联系有赞客服协助处理 五、授权自定义交易组件权限因为有赞是微信小程序的三方开发服务商,所以需要商家授权自定义交易组件权限,当然如果非服务商开发的话不用关心。 六、申请接入微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/register/apply?access_token=xxxxxxxxx 只需要获取到access_token后请求这个接口即可,接口是同步返回的(历史上是有异步的版本的,这块如果很早接触但没有在维护过的同学要注意了),这个接口请求失败的话可能是以下原因: access_token过期小程序类目不符合已经开通了标准版交易组件七、完成商品接口调试7.1 同步商品类目至微信审核你同步商品的三级类目id以及该类目在微信这边是否要求上传相应的类目资质,需要通过获取微信全量三级类目接口来查询 微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/cat/get?access_token=xxxxxxxxx 根据回参中的 qualification_type 类目资质类型 product_qualification_type 商品资质类型 来判断资质是否需要上传 根据回参中的 qualification 类目资质 product_qualification 商品资质 来查询需要上传资质 将回参中的third_cat_id记录,后续同步商品时会用 需要同步的话,就要调用上传类目资质接口,这是个异步接口,审核结果通过需要通过事件回调获取 微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/audit/audit_category?access_token=xxxxxxxxx 这块资质图片的字段建议先通过上传图片接口换取media_id来传入 7.2 同步品牌至微信审核如果你的同步的商品是一个品牌商品,那么在同步商品之前需要先同步品牌信息至微信审核,在审核通过的回调信息中获取到brand_id,之后同步商品时传入 微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/audit/audit_brand?access_token=xxxxxxxxx 同样的,这块品牌的一些证照图片的字段建议先通过上传图片接口换取media_id来传入 这里导致审核失败的几个原因: 上传证照的图片有问题,譬如有水印、大小超过2M、图片不能正常显示等证照过期 7.3 同步商品至微信审核现在就可以将调用同步商品接口完成商品同步了,也是一个异步接口,需要等审核回调 微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/spu/add?access_token=xxxxxxxxx 这里的tips引用下微信文档上的 注意:[代码]third_cat_id[代码]请根据获取类目接口拿到,并确定其[代码]qualification_type[代码]类目资质是否为必填,若为必填,那么要先调类目资质审核接口进行该[代码]third_cat_id[代码]的资质审核;[代码]qualification_pics[代码]请根据获取类目接口中对应[代码]third_cat_id[代码]的[代码]product_qualification_type[代码]为依据,若为必填,那么该字段需要加上该商品的资质图片;若需要上传某品牌商品,需要按照微信小商店开通规则开通对应品牌使用权限。微信小商店品牌开通规则:点击跳转,若无品牌可指定无品牌(无品牌[代码]brand_id: 2100000000[代码])。库存字段[代码]stock_num[代码]注意如果是0则无法在视频号直播上架该商品。部分特殊品类商品标题需要按照规范上传,请仔细阅读,避免审核不通过。商品标题规则:点击跳转。商品详情字段[代码]desc_info.desc[代码] [代码]desc_info.imgs[代码] 虽然非必填,但一些特殊品类仍然需要上传商品详情,请仔细阅读,避免审核不通过。商品详情规则:点击跳转。 这里应该是有赞场景下去开通自定义交易组件卡点比较严重的一环了,因为有赞的商家基数较大,商品种类较多,所以让商家自己同步一个商品至微信的话很容易被微信审核拒掉。有赞这边给到的一个方案是商家在开通自定义交易组件时,系统会帮商家创建一个简单的测试商品,因为这个商品无类目、无品牌且经验证100%通过商品审核,所以这一环的卡点也就能够被顺利疏通。 八、完成订单接口调试商品同步好后,需要对这个商品用微信支付完成一次交易,并将订单同步至微信 8.1 创建、同步订单因为自定义交易组件历史版本的原因,目前存在两套创建订单并同步至微信的方案 需要后端调用创建订单的微信api获取到ticket,然后小程序获取并通过ticket调用wx.requestPayment来拉起微信收银台(可能会废弃)小程序直接将订单信息通过wx.requestOrderPayment同步给微信,并拉起微信收银台微信这边推荐使用第二套方案 8.2 支付校验1、订单全量同步 如果选择订单全量同步到微信的话,那就不需要支付校验。 2、场景校验后同步 使用scene/check方法先去判断是否为视频号场景(这块后续可能会拓展,交易组件应该还会支持视频号以外的场景),是的话再去同步订单至微信。 这里建议在自定义交易组件接口调试过程中可以全量同步,但后续正常业务下单流程还是通过scene/check方式。因为如果你的小程序商城还支持其他支付方式的话,全量同步订单的话就会有坑,原因是无论你选择哪种创建、同步订单的方式都需要唤起微信支付,这样在原本能支持多种支付方式的场景下只能使用微信支付。 8.3 发布小程序因为创建、同步订单和支付校验有一些小程序的改动,所以小程序还是需要发布版本的。仅是开通流程的话走微信开发者工具也ok。 8.4 支付同步微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/order/pay?access_token=xxxxxxxxx 创建订单并支付成功后调用支付同步接口,就会将订单状态流转待发货 九、完成物流接口调试9.1 订单发货微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/delivery/send?access_token=xxxxxxxxx 9.2 订单收货微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/delivery/recieve?access_token=xxxxxxxxx 十、完成售后接口调试10.1 创建售后微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/aftersale/add?access_token=xxxxxxxxx 10.2 更新售后微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/aftersale/update?access_token=xxxxxxxxx 物流、售后接口的调试,如果只是开通流程的话,建议直接后端自动调用完成,可以减少卡点,帮助快速开通。 十一、完成接入任务11.1 获取接入状态微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/register/finish_access_info?access_token=xxxxxxxxx 回参中的access_info内 spu_audit_success 在商品接口调试成功后会被置为1 pay_order_success 在订单接口调试成功后会被置为1 send_delivery_success 在物流接口调试成功后会被置为1 add_aftersale_success 在售后接口调试成功后会被置为1 11.2 完成所有接入任务微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/register/finish_access_info?access_token=xxxxxxxxx 这个接口可以在上面获取接入状态接口返回的spu_audit_success、pay_order_success、send_delivery_success、add_aftersale_success的字段都为1时一次性调用完成所有。 当下面的任务都被完成后,自定义交易组件就已经完成接入了 6:完成spu接口,7:完成订单接口,8:完成物流接口,9:完成售后接口,10:测试完成,11:发版完成 十二、自定义交易组件接入视频号场景微信接口地址:点击跳转 http请求方式:POST https://api.weixin.qq.com/shop/register/finish_access_info?access_token=xxxxxxxxx 只需要调用场景申请接口来申请视频号场景,然后等待微信申请成功就可以完成自定义交易组件接入视频号了 十三、微信后台添加视频号推广员需要去微信后台添加一个视频号为推广员,然后就可以在这个视频号关联到已经开通自定义交易组件的小程序,关联后就可以上架已经商品同步接口调用通过的商品了。 [图片] [图片]
2021-10-27 - 关于小程序码生成后如何测试?
小程序码目前来说有生成跳测试或者体验环境的小程序码么? 根据开放文档,因为场景关系,我用的简单点的A接口方式生成的码,但是在小程序通过审核并且发布前无法进行测试,每次发布后测试完发现了bug,修改后又得提交审核发布后才能测试,而且普通审核好像说要好几天?加急的话次数有限,这样测试很不方便,是因为我没找到正确的方法吗(这两天第一次才因公司要求接触到小程序码) 此外,接口A和接口B方式文档中都提到只能生成已发布的小程序二维码,但是经过实际开发,似乎是有限制的那个其实还是能生成成功的,只是扫码后会提示小程序未发布,而无限制次数的那个生成方式却真的是生成不成功的(尝试了好几个小时,感觉应该不是代码问题) [图片] [图片]
2020-02-21 - 小程序服务商开发者,搭建一个mvp第三方平台必备的开发功能模块构成
我们在搭建小程序第三方平台过程发现官方提供的有很多接口,但不是每个接口都需要开发者用代码去实现。比如代码包管理的删除接口,就可以通过登录open.weixin.qq.com里,在列表看着更加详细的代码包版本介绍通过官方提供的界面就可以删除。即如果不是特殊需要,此接口可以不做开发。 那么我们搭建一个小程序服务商第三方平台需要哪些必要的功能模块呢? 必备功能模块概况 首先用一张图总概括下搭建一个mvp小程序服务商第三方平台必备的开发功能模块 [图片] 第三方平台权限集 先用一张图表明第三方平台账号在授权后可用的权限集的部分。 [图片] 只有平台先申请某一个权限,经过审核且全网发布后,旗下小程序才能在授权时选择某权限。有以下等 A>=B, B>=C;也就是第三方平台即使有每个微信提供的每个权限集,通过管理员授权后也不一定有全部权权限。原因: 1 单一授权被授权给其他第三方平台账号,或管理员授权时选择不把某一个权限授权给平台。比如开发和代码管理权限集 2 旗下小程序自身主体资质性质自带,不能拥有某个api权限。案例参考3 3 最终授权成功的权限集里,每个权限下都有多个api,所以在用某个api前需要看是由有权限。比如开发和代码管理权限集下,setwebviewdomain这个api不支持个人主体资质的appid调用 4 授权成功后,用token就可以用第三方平台提供的api代调用实现业务,或代调用小程序开发文档的api(标志参数需要access_token)里的接口,来实现产品开发。 授权及回调域名验证 ####### 说明 ####### 发起域名必须要在合法登记的域名名单内,且用户授权同意后的跳转url必须要在资料登记。体现在第三方平台创建时的以下两项配置中。 ① 授权发起页域名 ② 授权事件接收URL [图片] 授权回调URL源码 [代码] public void ProcessRequest(HttpContext context) { Request = context.Request; Response = context.Response; string signature = Request.QueryString["signature"]; string msg_signature = Request.QueryString["msg_signature"]; string timestamp = Request.QueryString["timestamp"]; string nonce = Request.QueryString["nonce"]; #region Response body // 微信并不会因为返回失败就再发送一次消息,相反如果不返回success, 微信会延迟推送 string ResMsg = "success"; if (Request.HttpMethod == "POST") { using (Stream stream = Request.InputStream) { Byte[] postBytes = new Byte[stream.Length]; stream.Read(postBytes, 0, (Int32)stream.Length); string postString = Encoding.UTF8.GetString(postBytes); if (postString.Contains("<AppId>")) { XElement xdoc = XElement.Parse(postString); CurAppID = xdoc.Element("AppId").Value.Trim(); LoadAppInfo(CurAppID); string postStringXmlSrc = string.Empty; Tencent.WXBizMsgCrypt wxcpt = new Tencent.WXBizMsgCrypt(CurAppToken, CurAppEncodingAESKey, CurAppID); int ret = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postString, ref postStringXmlSrc); if (ret == 0) { xdoc = XElement.Parse(postStringXmlSrc); if (xdoc != null) { string InfoType = xdoc.Element("InfoType").Value.Trim(); if (InfoType == "component_verify_ticket") { string componentVerifyTicket = xdoc.Element("ComponentVerifyTicket").Value.Trim(); WeixinDataHelper.UpdateComponentVerifyTicket(CurAppID, componentVerifyTicket); } else if (InfoType == "unauthorized") { string authorizedAppId = xdoc.Element("AuthorizerAppid").Value.Trim(); WeixinDataHelper.Unauthorized(CurAppID, authorizedAppId); } else { // 微信平台上填写的授权URL 目前就支持这两种 InfoType } } } } } } else if (Request.HttpMethod == "GET") { ResMsg = Request.QueryString["echostr"]; } ResponseEnd(ResMsg); #endregion } [代码] 各种票据有效性维护机制 1 授权后得到授权码(authorization_code ) [代码]需要用授权码去调用接口换取令牌,并保存。 [代码] 2 获取令牌和刷新令牌 [代码]用授权码获得令牌authorizer_access_token和刷新令牌authorizer_refresh_token。 需要保存令牌和刷新令牌。 [代码] 3 刷新令牌authorizer_access_token [代码]用刷新令牌定期去微信网关拉取令牌,维持令牌的有效性,保证后期代实现接口时令牌有效性。约1h左右的时间去刷新一次令牌。刷新令牌服务需要有重试机制,因为瞬时网络原因会返回失败,需要重试。 [代码] 消息与事件处理平台 1 第三方平台component_verify_ticke更新 [代码]平台审核通过后,每隔10分钟定时推送一次component_verify_ticket,开发者需要保存在数据库。再授权场景获取预授权码时需要用到这个有效的ticket。 [代码] 2 授权状态变更(成功,变更,取消) 3 代码审核通知消息 4 注意: [代码]① 这里的消息时加密的需要先解密。 ② 有开发者反馈说不知道返回信息时旗下哪个appid,这里补充下,appid是再请求头的request参数里直接返回的。 ③ 消息与通知解密部分代码 [代码] [代码] public void ProcessRequest(HttpContext context) { HttpRequest Request = context.Request; HttpResponse Response = context.Response; // 所属的已授权公众号的appid string AppID = Request.QueryString["AppID"]; string reqSignature = Request.QueryString["signature"]; string reqMsgSignature = Request.QueryString["msg_signature"]; string reqTimestamp = Request.QueryString["timestamp"]; string reqNonce = Request.QueryString["nonce"]; if (string.IsNullOrEmpty(AppID) || !WeixinHelper.ValidateWeixinInterface(reqSignature, WeixinResources.ComponentAppToken, reqTimestamp, reqNonce)) { ResponseEnd(Response, string.Empty,AppID); return; } if (AppID == WeixinResources.AutoTestAppID) { string _tmsg = new WeixinAutoTestHandler(Request, Response, WeixinResources.ComponentAppID).GetMsg(); ResponseEnd(Response, _tmsg,AppID); return; } #region Response body string ResMsg = string.Empty; if (Request.HttpMethod == "POST") { using (Stream stream = Request.InputStream) { Byte[] postBytes = new Byte[stream.Length]; stream.Read(postBytes, 0, (Int32)stream.Length); string postString = Encoding.UTF8.GetString(postBytes); string Msg = string.Empty; // 解密 Tencent.WXBizMsgCrypt wxcpt = new Tencent.WXBizMsgCrypt(WeixinResources.ComponentAppToken, WeixinResources.ComponentAppEncodingAESKey, WeixinResources.ComponentAppID); int ret = 0; ret = wxcpt.DecryptMsg(reqMsgSignature, reqTimestamp, reqNonce, postString, ref Msg); if (ret != 0) { ResponseEnd(Response, string.Empty,AppID); return; } // 生成响应消息 string resMsg = WeixinHelper.ReturnMessageAsThirdPlatform(AppID, Msg); // 加密消息 string EncryptMsg = string.Empty; ret = wxcpt.EncryptMsg(resMsg, reqTimestamp, reqNonce, ref EncryptMsg); if (ret != 0) { EncryptMsg = string.Empty; } ResMsg = EncryptMsg; } } else if (Request.HttpMethod == "GET") { ResMsg = Request.QueryString["echostr"]; } ResponseEnd(Response, ResMsg,AppID); #endregion } [代码] [代码]public static string ReturnMessageAsThirdPlatform(string AppID, string requestMsg) { string responseContent = string.Empty; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(requestMsg); XmlNode MsgType = xmlDoc.SelectSingleNode("/xml/MsgType"); if (MsgType != null) { switch (MsgType.InnerText) { case "event": responseContent = EventHandleAsThirdPlatform(AppID, xmlDoc); //事件处理 break; case "text": case "image": case "voice": case "video": case "shortvideo": case "location": responseContent = TextHandleAsThirdPlatform(AppID, xmlDoc); //消息处理 break; default: break; } } return responseContent; } [代码] 代小程序域名设置机制 1 小程序服务器域名 为授权小程序设置服务器域名 requestdomain request合法域名 wsrequestdomain socket合法域名 uploaddomain uploadFile合法域名 downloaddomain downloadFile合法域名 2 小程序业务域名 为授权小程序提供业务域名 web-view的合法域名 第三方平台先登记后,在给旗下小程序授权 旗下小程序可以使用配置域名的子域名作为业务域名 代小程序代码包管理机制 1 提交代码包 详细关于代码包管理参考https://developers.weixin.qq.com/community/develop/article/doc/000622ad764e48a45419e25b151813 ①ext.json的配置项更改体现在代码包配置json数据里。ext_json字段对应ext.json里的字段,这里template_id关联第三方平台》小程序模板管理里的模板ID。 ② 那么要提交小程序的appid呢?还是通过ext_json字段来配置。ext_jsonjson字符串里的extAppid就是第三方平台账号旗下授权,本次要提交代码的小程序appid,通过上传代码时候的来指定extAppid就可以给一个小程序代提交代码。 [图片] [图片] 2 提交审核 3 收到审核通知审核通过后提交上线 4 查询最近一次提交审核进度 5 回退到上一个版本 第三方代码模板管理 1 创建小程序账号,授权给平台账号,并绑定到第三方平台账号的开发小程序列表 2 用开发小程序appid创建项目的开发代码包模板 3 用开发小程序appid提交代码到草稿箱 4从草稿箱添加到模板库 附加总结稿 [图片]
2020-11-05 - 一个营业执照可以注册多少个开放平台账号?
50个。
2019-12-27 - 小程序压测工具使用疑问?
好像只能固定页面参数,压测同一个页面,能不能配置页面参数? 压测报告中的页面平均加载时间指的是指从访问到页面渲染完成的时间,还是指从访问到所有页面资源加载完成的时间? 另外,发现压测报告中的某些请求非本页面产生的请求是怎么回事?是每次都会先打开首页,再跳转到目标页面吗?
2021-06-22 - 同一企业主体下两个账号间的APP可以迁移吗?
如题,我们公司有A,B两个开放平台账号,现在想把A账号下的APP迁移到B账号下去。可以实现吗?流程一样的吗?
2020-09-21 - 微信小程序产品介绍
2020微信小程序应用开发大赛宣讲会, 我们邀请了小程序产品经理为大家介绍小程序的产品能力, 同时带来了案例分析和开发建议, 错过宣讲会直播的同学可以通过视频了解一下。 [视频]
2021-03-17 - 个人整理的小商店推广场景简要说明
看到有网友问怎么利用小商店的推广场景,结合官方客服提到的营销场所,做一下简单说明。 小商店实质上是一种特殊的小程序,所以推广方法可以参照小程序。 【小商店店铺】*任务栏展示微信首页,通过下拉页面方式,打开任务栏,可以看到用户最近使用的小商店(小程序); *发现入口微信-发现页,点击小程序,可以找到用户访问过的小商店; *客服消息微信首页,“小程序客服消息”聊天窗口,打开后选择里面的店铺客服,在对话框点击店铺名称,即可打开小商店小程序页面; *小程序码可以在小商店助手的店铺分享中,获得小商店二维码,发给别人扫码或识别即可进入小商店; *搜索微信首页,打开顶部搜索,可以搜索小商店名称,进入小商店; *对话分享可以将小商店用“发送给朋友”的方式,发给与朋友的对话框; *群分享可以将小商店用“发送给朋友”的方式,发给到聊天群; *APP分享【需开发】APP应用里面分享内容到微信聊天窗口,用户点击内容直接打开小商店; (参见:https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Share_and_Favorites/iOS.html) *模板消息【需开发】公众号模板消息可以设置跳转小商店,用户点击消息打开小商店; (参见:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#5) *公众号Profile页/文章插入将小商店加到公众号自定义菜单中,或者在公众号文章中加小商店的跳转链接; *LBS广告(个人理解)地图定位的周边小程序,小商店; *微信广告使用微信生态的广告主功能,通过官方向微信生态各个区域投放小商店广告; 【小商店商品页】*对话分享将商品详情页分享到朋友的聊天对话窗口; *群分享将商品详情页分享到群聊天窗口; *APP分享【需开发】APP应用里面分享内容到微信聊天窗口,用户点击内容直接打开小商店指定商品页; *小程序互跳【需开发】不同小程序之间互相跳转打开指定的小程序商品页; *公众号自定义菜单/文章插入将小商店指定商品页加到公众号自定义菜单中,或者在公众号文章中加小商店的指定商品页跳转链接; *二维码获取小商店指定商品的页面链接,然后生成商品二维码进行分享; (可参考网友“拾忆”的文章:https://developers.weixin.qq.com/community/develop/article/doc/0008066531c28043d2185a4d356813) *模板消息公众号模板消息可以设置跳转小商店指定商品页,用户点击消息打开小商店指定商品; 欢迎指摘与补充!
2020-09-17 - 有赞功夫:一个To B行业产品经理的自我修养
产品经理已经成为互联网行业最吃香的职业之一,不过大多数人提到这个职业最先想到的还是微信、今日头条、淘宝、支付宝等C端产品,它们有海量用户,也创造了海量的产品经理岗位。而一个不容忽视的趋势是:以腾讯为代表的诸多互联网公司正在加重To B业务,未来To B行业的产品经理将扮演更重要的角色。 ToB行业产品经理工作与To C 行业产品经理有哪些区别?要面对哪些挑战?需要怎样的职业素养?以下是有赞美业产品总监功夫关于SaaS产品的心得分享。 有赞作为一个商家服务公司,主要面向零售商家提供SaaS产品,成立7年来已积累了有赞微商城、有赞零售、有赞美业、有赞餐饮、有赞小程序等SaaS软件产品,帮商家网上开店、网上营销、管理客户、获取订单。 功夫曾在房天下(搜房网)担任产品副总监,参与房产家居的O2O业务,后在阿里巴巴负责个性化推荐业务,有近6年的产品经历,无论在To C还是To B的产品,都有着丰富的经验。这次分享中涉及到有赞产品经理的工作理念、判断逻辑以及一些很具体的产品需求场景,对SaaS行业或者To B行业的产品经理来说都是很好的参考。 以下是功夫分享内容的整理:(采访与整理 :三节课产品学院行业研究员张成翼) 一. 为什么需要SaaS? SaaS的产生,从一开始就是为了追求效率,能够让“专业人做专业事”,进而提升企业经营效率,它的产生,本质上是技术在商家经营过程应用程度不断提升的一种体现。现有的SaaS形式,是在不断演化之后产生的结果。 接下来,我们以有赞美业的SaaS为例,来看看商家经营的解决方案演化过程—— 1.记账 这是比较早期的阶段,商家是通过一个厚厚的本子来管理店里面的经营情况,甚至到现在还有很多商家是用这种解决方案。 2. IT化 然后,一部分追求效率的商家开始使用单机不联网的ERP去管理店里面的经营情况,相比原来数据不易丢失,也能省不少时间。与此同时,商家初步具备了事“后”分析的能力,比如美业商家经营里有个很重要的场景——预约。 通常的场景大概是这样的:顾客打电话给前台预约某个时间做服务,前台打开系统录入后,告知技师客户姓名以及具体的服务时间和项目。店长在晚上复盘能看到今天每个时间段的客户预约量,接下来她可能会和老板商量要不要在明天采取一系列动作。 3. 互联网化 这是当前处在的阶段,美团用了7年的时间让商家开始接受了互联网的工具,知道怎么在线上找流量进而引导进店。商家开始使用微信公众号和小程序客服功能和他的顾客进行互动,从顾客的角度上来讲体验变得更好了,因为不再是冷冰冰的买卖关系。 这个阶段解决方案创造的价值是,让商家具备了事“中”反应的能力,还是以刚才的预约为例:顾客打开公众号或小程序预约时,能看到商家门店里的动态流量,当她提交信息完成预约后,前台的预约看板里会以可视化的形式展示出来,与此同时,技师也会收到实时提醒。店长随时随地打开App能知道哪个房间、哪个技师处于空闲状态,进而决定是否开启一波限时促销的活动。 4. 智能化 这是不久的将来一定会发生的,当然前提条件是有了足够多数据和信息的积累,比如说颗粒度足够丰富的“活”数据、平台间的数据可以实时共享等等。不过,到那个时候商家一定能具备事“前”分析的能力,比如,一个新顾客进店后,装在店里面的人脸识别系统会调取出这个顾客在其他店的消费记录,以及别的商家给她打上的标签,营销顾问再基于这些信息做针对性的营销。 在不同的阶段,其实提供的也是不同的产品,在最早的阶段,你只要提供一个账本就可以,而到第二个阶段,用友、金蝶等产品是主流;第三个阶段,也是当前,商家开始逐步接受使用互联网产品,这也是为什么SaaS开始在这个阶段兴起。 所以,SaaS的产生,其实是技术在商家经营过程应用程度不断提升的一种体现。而从中长期来看,SaaS针对其所服务的行业,是有可能提供领先于行业的解决方案,为整个行业赋能。 虽然我们还无法得知它未来终极的产品形态究竟如何,不过,从目前阿里、有赞等公司开始尝试的实践当中来看,基于数据智能和网络智能提供的服务将是重要的趋势,这也是曾鸣教授在《智能商业》一书中,为我们描绘的图景。 二. 对于产品经理来说,To C与To B的工作有什么区别?或者说,提出了怎样的挑战? 首先,从事SaaS的产品经理本质上仍旧是产品经理。换言之,对于大多数产品经理都适用的工作方法和评判标准,对于SaaS产品经理来说,也是适用的。 比如说,对于SaaS产品经理,或者借用现在一个时髦的概念,从事产业互联网的产品经理与消费互联网的产品经理相比,其工作基本思路与流程并无二致,都是基于场景进行设计。其核心思考的思路都是“用户,场景,需求”,大家都需要写PRD,用AXURE画原型,这一点是通用的。 但是,具体到SaaS的场景当中去,有许多SaaS产品中遇到的典型问题,在To C场景中是前所未有的,比如说: To C的产品经理,天然是用户,天然就能更好地理解用户的需求,To B的产品经理,大多数情况下不是用户,毕竟,对于大多数产品经理来说,很少会有自己开设一家企业,并经营3-5年的经历。这就意味着,To B的产品经理大多数情况下,并不真正了解用户,就更难提理解了; To C的产品,决策链通常是『点』状的,产品可能某个单点功能足够优秀,就能够获得用户,而To B的产品,决策链更多情况下是『环』状的,员工,老板之间可能各有诉求,二者的诉求有时甚至可能是冲突的,这时候,产品需要切实的解决用户问题,创造价值,用户才有可能真正的buy in; To C的产品,试错成本很低,很多时候,如果一个功能效果不好很容易就可以回滚,但是在To B的场景下,这是不允许的,一个功能一旦上线,商家在上面形成业务数据,就几乎不可能回滚了。这就意味着,SaaS产品经理在做产品设计时,前期需要扎扎实实的产品功能想清楚。 这几点差异的背后,以及很多时候我们提到的关于To B与To C的不同,究其根本,很重要的原因是在To B的场景下,产品经理们对于他们所服务的用户的相关信息输入是不够的。 对于To B,或者说SaaS来说,很多行业中通用的解决方案和思考方式,都是隐性知识,是需要你在行业中长期实践才能了解到,否则,很多只是在逻辑上或者理念上合理的解决方案,实践中就会遇到很多挑战。 也因此,对于To B产品的产品经理来说,不仅需要互联网产品的基本设计方法,还需要对其所服务行业有足够深刻的认知。他们不仅仅要关注用户体验,更多的时候,是要关注用户价值,关注在这个行业中究竟应该如何高效解决问题。 如果做不到这一点,简单的将过去在To C领域使用的方法直接套用到在To B领域,将会面临着很大的挑战。这也是刚刚转行To B的产品经理,时常会遇到的挑战。 对于有赞而言也是如此,过去在C端产品非常优秀的产品经理,在进入有赞之后,可能两三个月都没法很好的进入状态。对于他们来说,很多过去的工作方法和理念都需要抛弃,从更多的角度理解产品设计这件事,掌握更多关于SaaS产品的设计方法和理念,才能够更好的适应这个环境和过程。 也是在这个过程中,有赞内部也实践出一套方法论,帮助产品经理在面对商家,这个有些特殊的用户群体时,能够更快的进入状态,产出更高效的解决方案。 接下来,我们就借助有赞在发展过程中的一些实际案例,聊一聊有赞的产品设计方法。 三. to B产品如何进行基于业务场景的设计? 正如我们之前所说,基于场景的产品设计这一基本思路,无论是在C端还是在B端,都是适用的。 不过,有赞在实践过程中发现,在面向企业用户进行产品设计时,需要注意和回答的很多问题,是与C端不同的。 简单来看,是要依次回答这样三个问题 —— 1.业务场景究竟是什么? 如何定义业务场景?这是进行产品设计时第一个回答问题。 在定义场景时,不仅仅是简单的说一句用户在什么情况下使用这个功能,这样的描述还是太简单,对于业务场景的描述需要更有颗粒度,“我要把这个产品给你描述完,立马你就有画面感的,才叫场景“。 怎样才是有画面感的场景描述呐呢?关键在于,能够包含七个要素,分别是—— 用户、环境、动机、目标、介质,交互,动作。 只有包含这七个要素,才能够叫做有“画面感”的场景描述。你对业务场景的理解,能否到达这个颗粒度,会对你的产品设计结果带来很大差异。 在有赞内部,发生过很多次类似的事情,产品经理们因为对于业务场景理解的不同,会提出完全不同的解决方案。 比如说,现在让你给有赞设计一个店铺装修功能,你会如何做? 通用的解决方案可能是: 给商家做好基础功能,商家在后台可以自由的搭配界面,拼装颜色,调整图片大小尺寸。他能够把有赞店铺像装修淘宝店铺,京东店铺一样特别好看,这样,无论什么时候来,不同的店铺都能够有不同的主题。 这个方案确实是有效,他也确实是”店铺装修“,但它真的是最适合用户的解决方案吗? 要回答这个问题,仍旧应该是回到原点——清晰描述客户的业务场景。 这个过程,其实就是思考什么样的用户需要这个功能?什么时候需要这个功能?他想要这个功能解决什么问题,实现怎样的效果?通过怎样的方式解决这个问题?为了解决这个问题他需要使用怎样的介质?这个过程中要执行怎样的动作? 回到店铺装修这个问题上,对于有赞的商家来说,他们使用店铺装修功能的场景可能是,头部的20个品牌商家,在春节期间,为了决定突出品牌调性,获得更多的用户认可,同时为了增强跟顾客之间的这种互动,提高大家对他的好感度,所以他决定在春节期间上线一些新的活动。同时把它整个的页面设计的更符合春节的这种气息一些。于是它在后台里面选择了一套模板,并安排美工,设计一些符合这种气息的这种图片上传到后台里面,来达到这样的效果。 在这个回答当中,大致将刚刚提到的七个要素体现出来。这时,我们会发现,其实特别自由的店铺装修功能可能并不最合适,节庆期间的活动,如果店铺装修太过复杂,只会让商家感到反感。他们需要把大量的时间花在店铺装修上,针对于时间就是金钱的大促来说并不值当。而且,这样繁复的装修,在日常使用当中却又使用不到。 最终,这个功能的方案是,只设置针对不同节庆的基础模板,商家可以自己上传图片,符合节庆的氛围。但是,店铺的具体样式并不能调整。 当然,具体的功能设计,当然还有很多考量,我们这里只是简单的讨论,业务场景理解对于产品设计的价值。 2.产品价值是什么? 对产品的业务场景有了基本的理解之后,第二步可能需要理解一下,你的产品或者功能,对于用户的价值究竟是什么? 一般而言,对于To B类的产品,用户价值这件事无非两点 : 商家的经营效率是否提高? 商家的经营效果是否提高? 用户使用你的产品,工作效率是不是提高了、是不是能够赚到更多的钱,这两条是评判SaaS产品的核心标准。 如果在这两条中,一条都不占,那么,你这个需求可能就没法上了。 有赞内部之前经常有类似的需求,对于他们自己来说是有价值的,但对于商家而言,可能并不能提供价值,这时,也是考验产品经理的产品设计水平的时刻。 还是以有赞为例。 有赞运营曾向产品提出过这样一个需求,希望在商家注册或者使用付费功能时,能够填写自己的经营类目。 比如说,你是一家水果店,那么就在注册时,填写自己的类目为零售。你是一家按摩店,就填写自己的类目为服务。 之所以需要增加这一步,是为了有赞能够对于自己服务的商家有更全面的了解,之后能够提供更为优质的服务。对于商家来说,凭空在注册流程中增加这一步,短期之内他们的经营效率没有太大的帮助,而且,反而会增加操作成本。 但是,另一方面,这个需求也确实对于有赞有价值,所以也不可能直接把运营的需求拒绝掉。 这个时候,就需要产品的同学能够提出更有效的解决方案。 最后采取的方案是,让内部的数据同学,把同一商家ID下面的商品名称数据进行分析,进而得出商家的类目。 商家在使用有赞SaaS时,一定会录入商品名称,比如说水果店就会有苹果,香蕉,哈密瓜等商品名,便利店可能就会有各种饮料,零食等商品。这些商品的名称基本都是独有的。 数据同学可以在后台抽样选择20个商品,看看商品名称都落在哪个类目,进而推断商家所处的类目,这样,不仅能够得出不同商家的经营类目,而且从结果上看,反而比商家自己选择自己的经营类目更加精准一些,对于运营的同学更有价值。 而这样的案例,其实对于有赞来说时常发生。对于SaaS产品,很多功能或许是需要做的,但是,究竟是否可以做,则需要反复思考,这个功能是不是真正能够为用户提升价值,如果不能,我们倾向于不要做,这也是在SaaS产品中第二个关键的问题。 3.如何判断功能的优先级? 最后,当你开始有大量的需求之后,应该如何判断产品功能优先级? 针对这个问题的解决方案,无论是在C端还是在SaaS,判断准则都差异不大。 大致的判断标准基本都是公司战略重心、行业发展趋势、资源限制以及收入等要素来考虑。 关于如何进行宏观的考量,此处就不再过多赘述了。 四. 一个优秀SaaS产品经理的判断标准 对于产品经理而言,其实无论是在C端还是B端,能力要求都是近似的,大约都是这样一个框架—— 1. 首先是需求分析产生的能力。 我们对于业务场景的理解,对于产品价值的判断,这些前置性的思考,其实都是基于产品的理解和思考。这是一个基础能力,通过这种方法,形成产品需求; 2. 第二个就是产品设计的能力。 很多C端的产品经理,会将产品设计能力定义为UI设计能力,交互逻辑的设计能力以及一些流程或者细节的优化。坦率来说,我认为这个能力在SaaS解决方案里面是最不重要的。对于SaaS而言,最重要的是能够提供可用的解决方案,产业互联网的第一优先级就是可用。没有做到可用,但是足够好看,是无法解决本质问题的。所以,这里的产品设计能力,特指的是能够针对所服务的行业提出可行的解决方案的能力; 3. 第三个是项目跟进的能力, 就是你是否有能力主导整个项目,它能够如期按时交付,能够组织大家所有的参与者按照设定的目标推进并最终实现它,甚至是提前上线等等; 4. 最后一个就是对行业的敏感能力, 这是一个很重要的能力点,为什么说它重要?因为对于前三个能力来说,其实都有清晰的方法论,是可以训练,可以交付的,包括三节课正在开设的课程都是在解决这个问题。 但是,行业敏感度很难进行批量的训练,它有一个前提是你对这个行业要有足够的热爱,如果做不到这一点,后续都很困难。在热爱的基础上,可能需要你学习和训练一些信息获取的能力、分析调研的能力、以及全局的思考能力等等,通过对行业的掌握,最终获得这项能力。
2019-08-29 - 第三方小程序涉直播代码上传经验总结
一直以来作为第三方服务商为商户运营小程序时,使用的是 复用公众号主体快速注册小程序 ,这种方式创建小程序很快速,商户也不需要去记录小程序帐号信息,我们维护小程序代码时也很容易,一套代码,有升级时自动去全网更新。 一切执行起来都挺和谐的,直到直播功能出现后,这份安宁被打破了 1、原来的商户无小程序帐号,变成一种羁绊了。好在还可以引导商户扫描《小程序助手》小程序码,设置登录邮箱;或在微信公众平台,通过找回帐号的方式获得; 2、小程序模板不能一蹴而就了,还得区分商户是否有开通小程序直播插件; 3、新的小程序要开通直播功能,必须经历①设置登录邮箱(或找回帐号)→②上传不带直播的代码→③发起小程序支付→④开通小程序插件→⑤上传带直播的代码 这样一串长流程。 能一次就解决的问题都不算问题,最大的问题是代码管理,如果非得分成2套代码来管理,对于程序员来讲确实有点痛苦,如果再来一个类似直播的插件,那不得分4套代码,接着8套代码,16套代码,那不得逼疯程序员。 好在小程序有为第三方提供ext_json,用来区分不同商户,有了它,我们就可以1套代码搞定不同的商户了。具体操作如下: 1、app.json中去掉插件相关引入代码 2、上传小程序代码前获取商家已经开通的插件列表 https://api.weixin.qq.com/wxa/plugin?access_token= post参数{"action":"list"} 再判断是否已经开通相关插件,如直播插件的appid为wx2b03c6e691cd7370,那么可以判断返回的插件list字符串是否包含该appid。 如果有开通,则extJson中插入该插件的引用(plugins开始的这串) {\"ext\":{\"你自己定义的扩展参数\":\"扩展参数值\",\"haveLive\":1},\"plugins\": {\"live-player-plugin\": {\"version\": \"1.0.16\", \"provider\": \"wx2b03c6e691cd7370\"}},\"recompile\": true} 如果没有开通则extJosn为 {\"ext\":{\"你自己定义的扩展参数\":\"扩展参数值\",\"haveLive\":0}} 3、上传代码时传入ext_json https://api.weixin.qq.com/wxa/commit?access_token= post参数 {"template_id":模板ID,"ext_json":"2中返回的json字符串","user_version":"版本号","user_desc":"版本描述"} 4、在小程序中通过 wx.getExtConfig 获取参数 haveLive, 当为0时,表示没有开通直播插件,这时候需要隐藏所有可能出现直播相关的界面。不然小程序审核时会被驳回,要求类目要增加选择“社交 → 直播”类目(因为有直播相关功能,却没有开通小程序直播插件。在小程序中要使用直播功能,要么使用官方提供的小程序直播插件;要么设置类目为“社交 → 直播”后,使用其他途径进行直播)
2020-07-07 - 从源码看微信小程序启动过程(下)
4、加载 app.js 与注册程序在 app.js 加载完成后,小程序会使用 require('app.js') 注册程序,即对 App 方法进行调用,App 方法是对 __appServiceEngine__.App 方法的引用。 下图是框架对于 App 方法调用时的处理流程: [图片] App 方法根据传入的对象实例化一个 app 实例,其生命周期函数 onLaunch 和 onShow 因为使用不同的方式获取 options的参数。在有些需要根据场景值来实现需求的,或许使用 onShow 中的场景值更合适。 在实际开发过程中发现,在微信顶部唤起小程序和在小程序列表唤起的 options 也是不一样的。在该案例中通过点击分享的小程序进入后,关闭小程序,再通过不同方式进入小程序,通过顶部唤起的还是 options 的 path 属性还是分享出来的 path,但是通过列表中打开直接回到了首页,这里 App 中的 onShow 就会获取到不同的 options。 5、加载自定义组件代码以及注册自定义组件自定义组件在 app.js 之后被加载,小程序会在这个过程中加载完所有的自定义组件(分包中自定义组件没有有测试过),并且是加载完成后自动注册,只有注册完成后才会加载下一个自定义组件的代码。 下图是框架对于 Component 方法处理流程: [图片] 图中介绍了框架如何对传入 Component 方法的对象的处理,其后面还有很多深入的对于组件实例化的步骤没有在图中表示出来,具体可以在文章最后的附件中查看。 自定义组件在小程序中越来越完善,其拥有的能力也比 Page 更强大,而后面会提到在使用自定义组件的 Page 中,Page 实例也会使用和自定义组件一样的实例化方式,也就是说,他拥有和自定义组件一样的能力。 6、加载页面代码和注册页面加载页面代码的处理流程和加载自定义组件一样,都是加载完成后先注册页面,然后才会加载下一个页面。 下图是注册一个页面时框架对于 Page 方法的处理流程: [图片] Page 方法会根据是否使用自定义组件做不同的处理。使用自定义组件的 page 对象会被处理为和自定义组件的结构,并在页面实例化时使用不同的处理流程进行实例化。当然对于开发而言没任何不同。 从图中可以发现 Page 传入的(生命周期)代码并不会在这里被执行,可以通过下面小节了解 Page 实例化的详细过程。 7、等待页面 Ready 和 Page 实例化还记得上面介绍的启动流程中最后一步等待页面 Ready?严格来讲是等待浏览器 Ready,小程序虽然有部分原生的组件,不过本质上还是一个 web 程序。 在小程序中切换页面或打开页面时会触发 onAppRoute 事件,小程序框架通过 wx.onAppRoute 注册页面切换的处理程序,在所有程序就绪后,以 entryPagePath 作为入口使用 appLaunch 的方式进入页面。 下图是处理导航的程序流程: [图片] 从图中可以看出页面的实例化是在进入页面时进行,下图是具体的实例化过程: [图片] 下图是最终可得到 Page 实例: [图片] 可以发现其中多了 onRouteEnd API,实际该接口不会被调用。其中以 component 标记的表示只有在使用了自定义组件时才会有的方法和属性。在前面第 5 小节提到了对于使用自定义组件的页面会按照自定义组件方式解析,这些属性和方法与自定义组件表现一致。 8、关于 setData小程序框架是一个以数据驱动的框架,当然不能少了对他如何实现数据绑定的探索,下图是 Page 实例的 setData 执行流程: [图片] 其中 component:setData 表示使用自定义组件的 Page 实例的 setData 方法。 三、写在最后这是一次不完全的小程序框架探索,是在微信开发工具中 debug 的结果。虽然对于实际开发没有什么太大的帮助,但是对框架如何对开发的 js 代码进行处理有了一个很明确的认识,在使用一些 js 特性时可以有明确的感知。如果你还疑惑“小程序框架对传入的对象等到底做了什么”那一定是我表达能力太差,说声对不起。 通过这一次 debug ,也给我引入了新的问题,还希望能够有更多的讨论: 自定义组件太多启动时会耗时处理自定义组件 文件太多会耗时读文件 合理的设计分包很重要 一份在调试过程中的笔记 小程序框架不完全分析.xmind,如果看官有兴趣可以下载看看。当然最后对于框架中已有的能力,还是非常希望微信可以开放更多稳定的接口,并在文档中告知开发者,让开发变得简单一些。
2019-02-19 - 从源码看微信小程序启动过程
一、写作背景 接触小程序一年多,真实体验就是小程序开发门槛相对而言确实比较低。不过小程序的开发方式,一直是开发者吐槽的,如习惯了 Vue,React 开发的开发者经常会吐槽小程序一个 Page 必须由多个文件组成,组件化支持不完善或者说不能非常愉快的开发组件。在以前小项目中没太大感觉,从加入有赞,参与有赞微商城小程序的开发,是真切的体会到对于大型小程序项目开发的复杂性。 有赞从微信小程序内测就开始开发小程序,在不支持自定义组件的时代,只能通过 import 的形式拆分模块或实现组件。在业务复杂的页面,可能会 import 非常多的模块,而相应的 wxss 也需要 import 样式,除了操作繁琐,有时候也难免遗漏。 作为开发者,我们当然希望可以让工作更简单,更愉快,也希望改善我们的开发方式。所以希望能够更了解微信小程序框架,减少不必要的试错,于是有了一次对小程序框架的 debug 之旅。(基础库 1.9.93) 通过三周空余时间的 debug,也算对小程序框架有了一些浅显的认识,达到了最初的目的;对小程序启动,实例,运行等有了真切的体会。这篇文章记录了小程序框架的基本代码结构,启动流程,以及程序实例化过程。 本文的目的是希望把我看到的分享给对小程序感兴趣或者正在开发小程序的读者,主要解答“框架对传入的对象等到底做了什么”。 二、从启动流程一窥小程序框架细节 在开发者工具中使用 help() 方法,可以查看一些指令和方法。使用其中的 openVendor 方法可以打开微信开发者工具在小程序框架所在目录。其中以包括以基础库命名的目录和其他帮助文件,如其中有两个工具 wcc,wcsc。wcc 可把 wxml 转换为对应的 JS 函数 —— $gwx(path, global),wcsc 可将 wxss 转换为 css。而基础库目录包括 WAService.js 和 WAWebview.js 文件。小程序框架在开发者工具中以 WAService.js 命名(WAWebview.js 不知其作用,听说在真机环境使用该文件)。 在开发中工具命令行使用 document.head 可以查看到小程序的启动流程大致如下: [图片] 以小节的方式分别介绍这些流程,小程序是如何处理的(小节编号与图中编号相同)。 1、初始化全局变量 下图是小程序启动是初始化的一些全局的变量: [图片] 那些使用“__”开头,未在文档中提及可使用变量是不建议使用的,wxAppCode 在开发者工具中分为两类值,json 类型和 wxml 类型。以 .json 结尾的,其 key 值为开发者代码中对应的 json 文件的内容,.wxml 结尾的,其 key 值为通过调用 $gwx(’./pages/example/index.wxml’) 将得到一个可执行函数,通过调用这个函数可得到一个标识节点关系的 JSON 树。 [图片] 2、加载框架(WAService.js) 使用工具对 WAService.js 进行格式化后进行 debug。可以发现小程序框架大致由: WeixinJSBridge、 NativeBuffer、 wxConsole、 WeixinWorker、 JavaScript兼容(这部分为猜测)、 Reporter、 wx、 exparser、 virtualDOM、 appServiceEngine 几部分组成。 其中除了 wx 和 WeixinJSBridge 这两个基础 API 集合, exparser, virtualDOM, appServiceEngine 这三部分作为框架的核心, appServiceEngine 提供了框架最基本的接口如 App,Page,Component; exparser 提供了框架底层的能力,如实例化组件,数据变化监听,view 层与逻辑层的交互等;而 virtualDOM 则起着链接 appServiceEngine 和 exparser 的作用,如对开发者传入 Page 方法的对象进行格式化再传入 exparser 的对应方法处理。 框架对外暴露了以下API:Behavior,App,Page,Component,getApp,getCurrentPages,definePlugin,requirePlugin,wx。 3、业务代码的加载 在小程序中,开发者的 JavaScript 代码会被打包为 [代码]define('xxx.js', function(require, module, exports, window, document, frames, self, location, navigator, localStorage, history, Caches, screen, alert, confirm, prompt, fetch, XMLHttpRequest, WebSocket, webkit, WeixinJSCore, Reporter, print, WeixinJSBridge) { 'use strict'; // your code }) [代码] 这里的 define 是在框架中定义的方法,在框架中提供了两个方法:require 和 define 用来定义和使用业务代码。其方式有些像 AMD 规范接口,通过 define 定义一个模块,使用 require 来应用一个模块。但是也有很大区别,首先 define 限制了模块可使用的其他模块,如 window,document;其次 require 在使用模块时只会传入 require 和 module,也就是说参数中的其他模块在定义的模块中都是 undefined,这也是不能在开发者工具中获取一些浏览器环境对象的原因。 在小程序中,JavaScript 代码的加载方式和在浏览器中也有些不同,其加载顺序是首先加载项目中其他 js 文件(非注册程序和注册页面的 js 文件),其次是注册程序的 app.js,然后是自定义组件 js 文件,最后才是注册页面的 js 代码。而且小程序对于在 app.js 以及注册页面的 js 代码都会加载完成后立即使用 require 方法执行模块中的程序。其他的代码则需要在程序中使用 require 方法才会被执行。 下面详细介绍了 app.js,自定义组件,页面 js 代码的处理流程。 4、加载 app.js 与注册程序 在 app.js 加载完成后,小程序会使用 require(‘app.js’) 注册程序,即对 App 方法进行调用,App 方法是对 appServiceEngine.App 方法的引用。 下图是框架对于 App 方法调用时的处理流程: [图片] App 方法根据传入的对象实例化一个 app 实例,其生命周期函数 onLaunch 和 onShow 因为使用不同的方式获取 options的参数。在有些需要根据场景值来实现需求的,或许使用 onShow 中的场景值更合适。 在实际开发过程中发现,在微信顶部唤起小程序和在小程序列表唤起的 options 也是不一样的。在该案例中通过点击分享的小程序进入后,关闭小程序,再通过不同方式进入小程序,通过顶部唤起的还是 options 的 path 属性还是分享出来的 path,但是通过列表中打开直接回到了首页,这里 App 中的 onShow 就会获取到不同的 options。 5、加载自定义组件代码以及注册自定义组件 自定义组件在 app.js 之后被加载,小程序会在这个过程中加载完所有的自定义组件(分包中自定义组件没有有测试过),并且是加载完成后自动注册,只有注册完成后才会加载下一个自定义组件的代码。 下图是框架对于 Component 方法处理流程: [图片] 图中介绍了框架如何对传入 Component 方法的对象的处理,其后面还有很多深入的对于组件实例化的步骤没有在图中表示出来,具体可以在文章最后的附件中查看。 自定义组件在小程序中越来越完善,其拥有的能力也比 Page 更强大,而后面会提到在使用自定义组件的 Page 中,Page 实例也会使用和自定义组件一样的实例化方式,也就是说,他拥有和自定义组件一样的能力。 6、加载页面代码和注册页面 加载页面代码的处理流程和加载自定义组件一样,都是加载完成后先注册页面,然后才会加载下一个页面。 下图是注册一个页面时框架对于 Page 方法的处理流程: [图片] Page 方法会根据是否使用自定义组件做不同的处理。使用自定义组件的 page 对象会被处理为和自定义组件的结构,并在页面实例化时使用不同的处理流程进行实例化。当然对于开发而言没任何不同。 从图中可以发现 Page 传入的(生命周期)代码并不会在这里被执行,可以通过下面小节了解 Page 实例化的详细过程。 7、等待页面 Ready 和 Page 实例化 还记得上面介绍的启动流程中最后一步等待页面 Ready?严格来讲是等待浏览器 Ready,小程序虽然有部分原生的组件,不过本质上还是一个 web 程序。 在小程序中切换页面或打开页面时会触发 onAppRoute 事件,小程序框架通过 wx.onAppRoute 注册页面切换的处理程序,在所有程序就绪后,以 entryPagePath 作为入口使用 appLaunch 的方式进入页面。 下图是处理导航的程序流程: [图片] 从图中可以看出页面的实例化是在进入页面时进行,下图是具体的实例化过程: [图片] 下图是最终可得到 Page 实例: [图片] 可以发现其中多了 onRouteEnd API,实际该接口不会被调用。其中以 component 标记的表示只有在使用了自定义组件时才会有的方法和属性。在前面第 5 小节提到了对于使用自定义组件的页面会按照自定义组件方式解析,这些属性和方法与自定义组件表现一致。 8、关于 setData 小程序框架是一个以数据驱动的框架,当然不能少了对他如何实现数据绑定的探索,下图是 Page 实例的 setData 执行流程: [图片] 其中 component:setData 表示使用自定义组件的 Page 实例的 setData 方法。 三、写在最后 这是一次不完全的小程序框架探索,是在微信开发工具中 debug 的结果。虽然对于实际开发没有什么太大的帮助,但是对框架如何对开发的 js 代码进行处理有了一个很明确的认识,在使用一些 js 特性时可以有明确的感知。如果你还疑惑“小程序框架对传入的对象等到底做了什么”那一定是我表达能力太差,说声对不起。 通过这一次 debug ,也给我引入了新的问题,还希望能够有更多的讨论: · 自定义组件太多启动时会耗时处理自定义组件 · 文件太多会耗时读文件 · 合理的设计分包很重要 当然最后对于框架中已有的能力,还是非常希望微信可以开放更多稳定的接口,并在文档中告知开发者,让开发变得简单一些。
2019-03-05 - 如何用小程序开发app
背景 都知道小程序的体验要比app里面直接嵌入h5的体验要好,都知道小程序其实也是运行在app上的。那么我们为什么不能用小程序来开发app呢?这样不仅可以小程序和app只要开发一次,小程序和app都有了。还可以实现app动态更新不需要提交应用市场审核,我们只要做个小程序载体的app壳(类微信端小程序 sdk),而且体验效果也接近原生。做一个类似小程序平台把我们现在的app项目框架从组件化改成为小程序平台构架。 [图片] 每个业务程序都是一个个小程序,原生提供原生能力。 什么是小程序 首先我们要知道小程序是啥?现在市场上的小程序有很多,微信小程序、百度小程序、支付宝小程序、字节跳动小程序等但都差不多。与传统app相比,小程序无需安装、卸载,运行在微信、百度、支付宝等这样大型app载体上。虽然每种小程序都差不太多,但都定义了自己的开发语言和规范,这对开发者来说也是不少的麻烦。 小程序是介于web网页应用和原生应用的一种产物; [图片] 小程序和Hybrid APP的关系 原以为Hybrid APP就是用app的webview去加载一个h5文件,然后webview通过js桥梁和原生通信,实现js调用h5方法,h5方法调原生方法。来弥补h5无法拍照、打电话等不足。但是做出来的效果h5都会有短暂白屏,体验也无法达到原生效果(提供一个简单的demo)。后来接触了小程序,觉得小程序的体验和原生差不了多少了,可以说不是专业人员基本是看不出区别的,原先以为小程序是类似RN、weex这样的原生渲染,后面才知道它也是webview渲染。竟然也是hybird app,那它的体验是什么上去的?都是webview渲染,为什么小程序的体验会比普通的h5好?这让我非常感兴趣,于是就开始了小程序的深入了解。 初步了解用h5做Hybrid APP和小程序的区别: 相同点: 1.都是webview渲染 2.都是js通过桥接和原生通信 3.都可以调用原生组件 4.都可以把资源文件下载本地加载渲染 不同点: 1.Hybrid是html 有dom操作,小程序是虚拟dom 屏蔽了直接对dom操作 2.小程序有服务层,负责处理业务逻辑和数据处理 3.小程序页面有原生页面的生命周期管理 4.小程序tab和bar是原生控件 5.小程序类web不是h5 6.小程序基于微信跨平台 小程序原理 下面以微信小程序为例,进一步展开小程序原理 都知道微信小程序有自己的开发语言,wx开头的方法也不少,那它是什么转化为微信app能识别的语言呢?微信开发工具开发完提交审核,审核通过下发到微信端的是什么样的文件呢?带着这些问题我查阅了很多资料,小程序在技术架构上非常清晰易懂。JS负责业务逻辑的实现,而表现层则WXML和WXSS来共同实现,前者其实就是一种微信定义的模板语言,而后者类似CSS。但是语法毕竟是自定义的,所以要么在下发的之前进行编译,要么就是在渲染的时候进行转化成webview能够识别的语法。我们发现这2个节点微信都做了处理,拿到下发到微信端的wxapkg格式的小程序包,解开后都是js和html已经不是我们开发的WXML和WXSS格式了。但是这一个个html直接用浏览器打开却是空白的。没错<body></body>里面是空的,渲染的时候动态加进入内容的。 1.小程序是如何编译的 我们先来看看打包编译这层,微信都做了些啥呢?微信的打包和编译都在服务端进行,我这边找了个类似的来描述下,不一定准确,只能参考下。 检测app.json文件是否存在 清空并创建指定的输出目录 根据service.html模板,带上版本信息输出到指定的目录中 读取配置文件app.json,将其注入到app-config.js中,输出到指定的目录中 读取所有小程序代码中所有的JS文件,同时判断其是否在app.json中定义,如果其没被定义也不是app.js,说明其为引入的module, 将这些JS路径名存入一个数组中,并确保app.js和页面文件放置在数组尾部 遍历JS文件数组并读取它们,根据用户设置项判断是否使用Babel将其转换为es5的代码 把js模块封装成CommonJS模块,并合并成app-service.js这个文件输出 根据app.json里的pages配置,遍历每个页面根据页面wxml,wxss生成相应的页面文件并合成page-frame.html 其他步骤应该都不难理解,我认为最难的应该是wxml,wxss生成相应的页面文件,这个页面不是普通的html文件,前面也说过它的body是空的。如果你安装了微信的开发工具的化你可以找下是否有wcc和wcsc这2个小工具。wxss 转换成了css,wxml转换成了inject_js,实际上就是virtual_dom。openVendor命令可以在小程序中获取到构建脚本wcc和wcsc,以及各个版本小程序的执行SDK***.wxvpkg,这个SDK也可以用Wechat-app-unpack解开,解开后里面就有WAService.js和WAWebview.js等代码。 根据 /Users/***/Library/Application Support/微信web开发者工具/WeappVendor 路径来找到微信开发者工具目录,以及查看工具集成的核心类。可以看到我们和熟悉的也很重要的WAService.js和WAWebview.js2个文件也在里面。不过代码都是加密混淆的,没有可读性。 [图片] 2.编译好的小程序包如何下发解析 再看下下面这张图,微信下发的wxapkg格式的文件(每个小程序都是这样的一个包),这个文件可以通过从越狱的iPhone或者root的安卓手机上拿到。有部分人用charles通过https抓包拿到了下载链接,也拿到了包。解压出来就是这样的目录格式。简单解释下这每个文件的作用以及是什么来的: [图片] app-config.json:小程序的整体配置文件,里面是一个json 主要包括page、entryPagePath、pages、global、tabBar、ext、extAppid等 { “page”: { “pages/shop/index.html”: { “window”: { “enablePullDownRefresh”: false } }, “pages/goods/detail.html”: { “window”: { “navigationBarTitleText”: “商品详情”, “enablePullDownRefresh”: false } }, “pages/order/address/list.html”: { “window”: { “navigationBarTitleText”: “地址列表”, “enablePullDownRefresh”: false, “backgroundTextStyle”: “light” } }, … }, “entryPagePath”: “pages/shop/index.html”, “pages”: [“pages/shop/index”, “pages/order/detail/logisticsmap”,…], “global”: { “window”: { “backgroundTextStyle”: “light”, “navigationBarBackgroundColor”: “#f1f1f1”, “navigationBarTitleText”: " ", “navigationBarTextStyle”: “black” } }, “ext”: { “api”: { }, “form”: { }, “name”: “小店” }, “extAppid”: “########” } page节点:管理每个页面的整体设置,比如原生navigationBar的标题样式、是否需要下拉刷新等可以说这些设置都是对原生的ViewController的一个设置。没错一个小程序页面都有一个对应的原生页面,所以它可以封装原生页面的生命周期暴漏给小程序页面使用,包括原生的navigationBar和tabBar、下拉刷新控件等。这也是为什么小程序如果屏蔽调自带的navigationBar,自己定义navigationBar 下拉刷新也要自己重新做的原因。自定义navigationBar就不再是原生的了,它默认下拉刷新效果是在原生navigationBar下的整个webview做动画效果,这显然满足不了我们的需求。 entryPagePath:这个节点就简单了,小程序的入口页面的配置 pages节点:页面路径数组 对应小程序源代码里面的app.json文件里面的pages节点 global节点:全局设置和全局变量等;window 整个小程序的私有页面都起作用,也就是说每个页面没有自己单独设置都直接用这个全局设置的效果。 ext、extAppid节点:对应的就是ext.json文件 第三方平台部署小程序才需要 tabBar节点:对原生tabBar的样式设置和页面路径和图标等配置 app-service.js文件:这个是小程序一个很重要的文件,小程序体验好一个很重要的环节。从下图截取的代码片段很容易看出这个文件就是小程序里面全部js文件内容的集合。通过__wxRoute来路由,wxRouteBegin=true来标记启始页面。 var wxAppData = wxAppData || {}; ** var wxRoute = wxRoute || “”; var wxRouteBegin = wxRouteBegin || “”; var wxAppCode = wxAppCode || {}; var global = global || {}; var WXML_GLOBAL=WXML_GLOBAL || {}; var wxAppCurrentFile=wxAppCurrentFile||""; ** var Component = Component || function(){}; var definePlugin = definePlugin || function(){}; var requirePlugin = requirePlugin || function(){}; var Behavior = Behavior || function(){}; [代码]define("app.js", function(require, module, exports, window,document,frames,self,location,navigator,localStorage,history,Caches,screen,alert,confirm,prompt,XMLHttpRequest,WebSocket,Reporter,webkit,WeixinJSCore){ [代码] “use strict”;App({onLaunch:function(){var e=this,o=wx.getStorageSync(“logs”)||[];o.unshift(Date.now()),wx.setStorageSync(“logs”,o),wx.login({success:function(e){}}),wx.getSetting({success:function(o){o.authSetting[“scope.userInfo”]&&wx.getUserInfo({success:function(o){e.globalData.userInfo=o.userInfo,e.userInfoReadyCallback&&e.userInfoReadyCallback(o)}})}})},globalData:{userInfo:“hello world”,text:“hello world”}}); ** }); require(“app.js”); wxRoute = ‘pages/page2/page2’;wxRouteBegin = true; define(“pages/page2/page2.js”, function(require, module, exports, window,document,frames,self,location,navigator,localStorage,history,Caches,screen,alert,confirm,prompt,XMLHttpRequest,WebSocket,Reporter,webkit,WeixinJSCore){ “use strict”;Page({data:{},onLoad:function(n){},onReady:function(){},onShow:function(){},onHide:function(){},onUnload:function(){},onPullDownRefresh:function(){},onReachBottom:function(){},onShareAppMessage:function(){}}); }); require(“pages/page2/page2.js”);**** 3.小程序如何渲染 除了小程序每个页面的js还包含了app.js 这个包含小程序的整个生命周期管理逻辑的js文件内容也都在这个文件里面。在微信端里面小程序的sdk会有一个单独的webview来加载app-service.js文件当作这个小程序的服务层,负责每个页面逻辑处理,而且这个服务在这个小程序的整个生命周期它是一直在的,每个页面的js文件都已经压缩在这个文件里面,并在小程序服务启动的时候已经加载到内存中,所以在点击按钮需要做逻辑交互的时候体验会那么快。 [图片] App Service(逻辑层)主要就是由app-service.js文件和集成在微信app里面的WAService.js组成,如一个页面加载需要网络请求就是由逻辑层处理请求参数并交给原生来进行请求,原生把请求到的数据返回给App Service(逻辑层)进行数据处理,最后把处理好的数据通过原生JSBridge传给view(试图层)进行渲染。对 逻辑层和视图层没有直接的交互,逻辑服务层和视图层也不在一个线程里面,2个webview 只能通过原生来进行通信。 几个文件夹没啥特别的 就是和你微信小程序开发的目录是一样,放的都是你的页面和组件的html文件。但是值得一提的是这里面的html文件内容很少,它不是一个完整的页面,可以说这个页面的样式,静态内容都不在这个html里面。里面放的是这个页面css、路由路径和加载入口方法的调用generateFunc: $gwx(’./pages/order/rights/index.wxml’)。可以看下我的hello world页面代码,就更加清晰了。 <!–pages/page2/page2.wxml–> <text class=“pageText”>hello world page2</text> /* pages/page2/page2.wxss */ .pageText { background-color: red; width: 100%; height: 100rpx; display: flex; align-items: center; justify-content: center; } 这是一个很简单的小程序页面代码,那它编译后的html页面代码是什么样的呢?下面我展示出来给大家看。 <style> </style> <page></page> <script> var setCssStartTime = Date.now(); setCssToHead([".",[1],“pageText { background-color: red; width: 100%; height: “,[0,100],”; display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; -webkit-justify-content: center; justify-content: center; }\n”,],undefined,{path:"./pages/page2/page2.wxss"})() var setCssEndTime = Date.now(); document.dispatchEvent(new CustomEvent( “generateFuncReady”, { detail: { generateFunc: $gwx( ‘./pages/page2/page2.wxml’ ) }})) </script> 发现了啥?“hello world page2“ 这样页面关键内容不见了,那它是如何渲染的?懂js的人估计很容易就可以看到这个页面的入口方法generateFunc: $gwx 是的 这个方法是一个很重要的方法。那么这个方法在哪里?“hello world page2“ 这样页面关键元素又在哪里?肯定是跟着这个资源包一起下发的。对的所以的页面标签、元素 内容都在page-frame.html文件里面。也就是wxml文件的代码都编译压缩到page-frame.html文件里面,而对应页面的html文件只放对应的wxss文件代码和入口js代码。而入口方法的触发是由原生app调用js"generateFuncReady"事件触发调用。原生sdk这块后面可以以OC为例贴出对应代码,再展开说明下。 page-frame.html文件:这个文件应该是一个小程序包里面最大一个文件,所以里面的代码也不好都贴出来,简单介绍下里面的组成和作用。第一大块:模版 View(视图)层如何绘制每个页面都是公共的,如何把vdom渲染到webview上。$gwx方法就在这个模版里面,一个页面的入口。 [图片] 再找找我们刚才html页面消失的关键元素“hello world page2“在哪里?把每个元素都转化为Z数组了,每个页面都是一个类似这样的代码块。由于混淆和压缩加大了我们阅读的难度,但是如果你以为看完这个文件就完了,那就错了。View(视图)层除了这几个html文件外 还需要一个很重要的文件,那就是放在微信app包里面的WAWebview.js文件。和服务层里面也有一个WAService.js文件配合使用达到和原生交互的效果。 [图片] 和原生交互这块是属于小程序框架,所以肯定不会在下发的小程序包里面,除了原生sdk代码之外,还有2个很重要的js文件就是上面提到的WAService.js文件和文件。接下来我们就开始简单了解下: 为了方便理解我整理了js和原生的一些API,有app(小程序)级别的、有页面级别的、有原生组件级别的。可见js和原生交互是非常频繁的,可以说每个操作都是需要提供View(视图)层的WAWebview.js调用原生的桥梁需要原生处理就原生处理后再调用app Service(逻辑)层的WAService.js 由WAService.js通知 逻辑层处理对应逻辑,再把处理结果返回到原生。 [图片] 小程序在App中执行时的时候分为三个不同的模块,View/Service/Native,各司其职。View和Service都在WKWebView中执行,互相无法调用,不直接操作DOM。他们之间通过Native层通信。Native和WebView之间通过webkit.messagehandler和evaluateJavascript互相调用。小程序借助的是JSBridge实现了对底层API接口的调用,所以在小程序里面开发,开发者不用太多去考虑IOS,安卓的实现差异的问题,安心在上层的视图层和逻辑层进行开发即可。 WeixinJSBridge.publish: view和service之间的透传,在WKWebView之间传递消息。 WeixinJSBridge.subscribe: 注册监听,监听view和service之间的消息调用。 WeixinJSBridge.invoke: View或者Service传递消息到Native,然后Native使用逻辑调用js callback。 WeixinJSBridge.on:监听Native的事件。 [图片] 启动小程序服务startAppWithAppInfo根据appid等基本信息判断小程序是否已经下载到本地,没有的话下载解压加载配置信息等。然后进入manager,manager其实也是分为几部分一个是小程序级别的管理,一个是单个小程序的管理。具体的可以通过下面的类图更加直观。 [图片] 下图显示了小程序启动时会从CDN和服务器校验和下载资源。也就是是小程序启动的时候会有点慢的主要原因,还有一些时间就是需要初值化小程序本地服务。 [图片] 4.小程序的生命周期 关于小程序的生命周期,可以两个部分来理解:应用生命周期(左侧蓝色部分)和页面生命周期(右侧绿色部分)。 其中应用的生命周期是这样一个流程:1、用户首次打开小程序,触发 onLaunch(全局只触发一次)。2、小程序初始化完成后,触发onShow方法,监听小程序显示。3、小程序从前台进入后台,触发 onHide方法。4、小程序从后台进入前台显示,触发 onShow方法。5、小程序后台运行一定时间,或系统资源占用过高,会被销毁。 页面生命周期是这样的一个流程:1、小程序注册完成后,加载页面,触发onLoad方法。2、页面载入后触发onShow方法,显示页面。3、首次显示页面,会触发onReady方法,渲染页面元素和样式,一个页面只会调用一次。4、当小程序后台运行或跳转到其他页面时,触发onHide方法。5、当小程序有后台进入到前台运行或重新进入页面时,触发onShow方法。6、当使用重定向方法wx.redirectTo(OBJECT)或关闭当前页返回上一页wx.navigateBack(),触发onUnload。同时,应用生命周期会影响到页面生命周期。 [图片] 用Page 实例说明的页面的生命周期 [图片] 由上图可知,小程序由两大线程组成:负责界面的视图线程(view thread)和负责数据、服务处理的服务线程(appservice thread),两者协同工作,完成小程序页面生命周期的调用。 视图线程有四大状态: 初始化状态:初始化视图线程所需要的工作,初始化完成后向 “服务线程”发送初始化完成信号,然后进入等待状态,等待服务线程提供初始化数据。 首次渲染状态:当收到服务线程提供的初始化数据后(json和js中的data数据),渲染小程序界面,渲染完毕后,发送“首次渲染完成信号”给服务线程,并将页面展示给用户。 持续渲染状态:此时界面线程继续一直等待“服务线程”通过this.setdata()函数发送来的界面数据,只要收到就重新局部渲染,也因此只要更新数据并发送信号,界面就自动更新。 结束状态:页面被回收或者销毁、应用被系统回收、销毁时触发。 服务线程五大状态: 初始化状态:此阶段仅启动服务线程所需的基本功能,比如信号发送模块。系统的初始化工作完毕,就调用自定义的onload和onshow,然后等待视图线程的“视图线程初始化完成”号。onload是只会首次渲染的时候执行一次,onshow是每次界面切换都会执行,简单理解,这就是唯一差别。 等待激活状态:接收到“视图线程初始化完成”信号后,将初始化数据发送给“视图线程”,等待视图线程完成初次渲染。 激活状态:收到视图线程发送来的“首次渲染完成”信号后,就进入激活状态既程序的正常运行状态,并调用自定义的onReady()函数。此状态下就可以通过 this.setData 函数发送界面数据给界面线程进行局部渲染,更新页面。 后台运行状态:如果界面进入后台,服务线程就进入后台运行状态,从目前的官方解读来说,这个状态挺奇怪的,和激活状态是相同的,也可以通过setdata函数更新界面的。毕竟小程序的框架刚推出,应该后续会有很大不同吧。 结束状态:页面被回收或者销毁、应用被系统回收、销毁时触发。 小程序在App中的应用场景 说了这么多技术理论,最后说下小程序在项目中如何应用。整个项目都是小程序不现实,毕竟小程序的定义是轻量级的,像IM、消息等用原生肯定比小程序更加适合,所以用小程序和原生混合开发是不可少的。还有一个让你不得不混合开发的一个重要原因,你的app不是一个新项目,是一个现有的原生app,一次性用小程序重新做一次不现实,所以混合会是最好的选择。我这边做的混合开发不是技术层面的,我们都知道小程序是很原生通信很频繁的,它需要原生提供各种能力才能到达接近原生的体验,所以本身就是一个混合。而我这里说的混合是指业务层面的混合开发,打破我们以往对小程序的认知。不管是百度小程序还是微信小程序都是运行在他们生态下的一个独立应用程序。比如一个商城小程序它不会有部分页面是原生部分页面是小程序,也只会有一个入口,一个出口。而我们要用小程序来开发app,我们app有自己的需求我们需要让小程序看起来像原生页面一样,对用户来说它还是一个app,不存在哪个页面是原生哪个页面是原生的。所以一切都是从技术层面来说,就是小程序和原生进行混合开发的业务app。你可以理解为你的app里面嵌入h5一样的开发模式,只是小程序页面比一般的h5页面交互体验要好一些而已。 [图片] 我可以从原生页面跳转到小程序的任何页面,如果必要的话也可以从小程序页面跳转到原生页面。所以小程序服务不能在进入小程序页面的时候才启动,也不能因为回到原生页面而销毁。必须根据你的业务场景来调用控制。 以上是个人对与小程序开发app的一些浅薄看法,期待和业界同仁共同探讨。你有什么想法呢?欢迎评论交流。 最后感谢业界各位大佬的贡献,在这里附上我的参考文献: https://blog.csdn.net/ListenToSennTyou/article/details/53258163 https://www.jianshu.com/p/92c6a75c2323 https://blog.csdn.net/xiangzhihong8/article/details/66521459 https://yq.aliyun.com/articles/72825?t=t1 https://github.com/weidian-inc/hera-cli https://www.cnblogs.com/viaiu/p/9935602.html https://www.jianshu.com/p/51ac882ea9f4 http://lrdcq.com/me/read.php/66.htm https://github.com/wdfe/weweb
2019-05-30 - 第三方平台代小程序开发,第三方小程序能基于小程序模板新增页面吗?
不支持。一旦托管给第三方平台,那么你的小程序将没有开发能力,代码亦从第三方来,不能自己编写代码更改页面等。
2019-12-26