- 如何自己解绑小程序项目成员(体验者、运营者、开发者)
打开手机搜索公众号“公众平台安全助手”; [图片][图片] 关注公众号“公众平台安全助手”选择左下角菜单“绑定查询”; [图片] 选择子菜单“微信号绑定账号”; [图片] 选择“小程序”tab,下滑找到作为项目成员的小程序; [图片] 点击希望解绑的小程序,点击解绑。这样操作完你就可以再去绑定你需要的小程序啦! [图片] 补充:小程序相关数量限制: 成员管理人数限制 每个小程序帐号可添加一定数量的项目成员、体验成员,具体限制如下: [图片] 管理员及其他项目成员绑定帐号数不占用公众号绑定数量限制。 每个微信号可以成为50个小程序的项目成员。 每个微信号可以成为50个小程序的体验成员。 1.小程序成员管理官方教程 2.如何查询身份证个人微信号手机号绑定的帐号?
2020-11-05 - 你想在小程序里使用less嘛? (VScode版)
老规矩,直奔主题,三步走: Step 1: Ctrl+Shift+X 打开扩展 - 搜索 easy Less 并安装 Step 2: Ctrl+ 逗号 打开设置 - 搜索 easy Less config 并选择 点在setings.json中编辑 把下面配置粘贴进去(注意配置项间隔的逗号不要漏了) [代码]"less.compile": { // "compress": true, // 是否删除多余空白字符 // "sourceMap": true, // 是否创建文件目录树,true的话会自动生成一个 .css.map 文件 "outExt": ".wxss" // 输出文件的后缀,默认为.css } [代码] Step 3: 在你的wxml同级目录下新建一个 文件名.less 书写less语法的css并保存,同级目录下就会自动生成一个 文件名.wxss的文件 好了,这次分享到这里就结束了。如果你觉得对你有帮助,请给我点个赞并留言告诉我,让我为你开心下😊。
2019-04-30 - 动手打造更强更好用的微信开发者工具-编辑器扩展篇
1. 写在前面 1.1 微信开发者工具现状 具备一些基本的通用IDE功能,但是第三方的支持扩展需要加强。 1.2 开发者工具自带的编辑器扩展功能 可能很多老铁没用过官方的微信开发者工具的编辑器扩展(我一般称为编辑器插件)。官方把这块功能也隐藏得很深,也没有相关文档介绍,但是预留了相关的入口。合理利用第三方编辑器插件,可以极大的提升开发效率。下面先来看看官方预留的编辑器插件入口: [图片] (图一) 2. 几个不错插件安装效果 2.1 标签高亮插件-vincaslt.highlight-matching-tag [图片] 功能:可以把当前行对应的标签开头和结尾高亮起来,让开发者一目了然 2.2 小程序开发助手插件-overtrue.miniapp-helper [图片] 功能:必须要说的这个是纯国产的插件,里面的代码片段功能很全,具体介绍:小程序开发助手 - Visual Studio Marketplace https://marketplace.visualstudio.com/items?itemName=overtrue.miniapp-helper 2.3 minapp插件-qiu8310.minapp-vscode [图片] 功能:这个是今天的明星插件,里面的跳转功能很强,可以在wxml里CMD+点击对应变量/方法和CSS样式名称直接跳转到对应的js/wxss文件对应的地方。具体的下面是官方介绍: 标签名与属性自动补全 根据组件已有的属性,自动筛选出对应支持的属性集合 属性值自动补全 点击模板文件中的函数或属性跳转到 js/ts 定义的地方(纯 wxml 或 pug 文件才支持,vue 文件不完全支持) 样式名自动补全(纯 wxml 或 pug 文件才支持,vue 文件不完全支持) 在 vue 模板文件中也能自动补全,同时支持 pug 语言 支持 link(纯 wxml 或 pug 文件才支持,vue 文件不支持) 自定义组件自动补全(纯 wxml 文件才支持,vue 或 pug 文件不支持) 模板文件中 js 变量高亮(纯 wxml 或 pug 文件才支持,vue 文件不支持) 内置 snippets 支持 emmet 写法 wxml 格式化 3. DIY添加适合自己的插件 3.1 添加插件功能简介 仔细研究过微信开发者工具的人可能知道或者了解,其实微信开发者工具编辑器跟微软的开源编辑器vsCode「颇有渊源」。再深入研究发现,vsCode的插件完全可以无缝移植到微信开发者工具编辑器里来,所以今天的内容就是移植vsCode的插件到微信开发者工具。咱们先看看微信开发者工具自带的「管理编辑器扩展」功能(图1标注为2的地方) [图片](图二) 3.2 插件添加具体步骤 3.2.1 安装插件,获取插件文件 安装vsCode并安装你需要移植的插件,必须要说的是vsCode的插件非常多,好的插件也很多。相关安装,搜索插件教程建议大家百度相关教程。或者直接下载vsCode亲自体验,插件安装过程还是非常简单的。 3.2.2 复制插件文件夹 找到vsCode相关插件的安装文件夹: 操作系统 安装路径 windows %USERPROFILE%.vscode\extensions macOS ~/.vscode/extensions Linux ~/.vscode/extensions 复制对应插件文件夹到微信开发者工具的「打开编辑器扩展目录」(图一标注为1的地方) 3.2.3 添加插件配置文件 新版开发者工具直接进入图形设置,扩展设置里勾选对应插件即可。如下图: [图片] 旧版操作方法:进入微信开发者工具的「管理编辑器扩展」功能页面,在尾端加入对应添加的插件名称。以以上3个介绍的插件为例,在原来的尾端加入: “vincaslt.highlight-matching-tag”, “overtrue.miniapp-helper”, “qiu8310.minapp-vscode” 3.2.4 见证奇迹 重启微信开发者工具,见证插件带来的编码便利吧! 4 需要注意的 vsCode的插件很多,小程序相关的也越来越多了,但是插件质量参差不齐,所以安装时建议选择「标星」star比较多的插件。
2020-05-02 - 微信开发者工具下载的 sourcemaps 怎么用。
什么是 Sourcemaps uglifyjs、bable 等工具会对 源代码 进行编译处理生成编译后的代码(下称目标代码),而 sourcemaps 就是保留了目标代码在源代码中的 位置信息 --------- 大神分割线 --------- 如何解读 Sourcemaps Sourcemaps 是一个 json [代码]{ "version": 3, "sources": ["a.js", "b.js"], // 源文件列表,这个表示是由 a.js 和 b.js 合并生成 "names": ["myFn", "test"], // 如果开启了变量名混淆,这里会保留变量名在源文件中名字信息 "sourcesContent: [], // 可选项,保存源码信息,顺序与 sources 字段对应,chrome 的 sources 面板中源码使用了这个字段的内容进行展示 "sourceRoot": "", // 源文件所在的目录信息 "file": "dist.js", // 可选,编译后的文件名 "mappings": "" // 这个是重点,是目标代码和源文件的位置的映射关系 } [代码] mappings 目标文件"行"的信息 mappings 是使用 ; 分隔的,每个部分对应目标代码的行 如: “;AAAA;AAAA,BBBB;;” 本例子目标文件有 4 行 第 0 行和第 3 行没有源文件对应信息,所以这两行是编译过程中加入的代码 目标文件的"列"信息 如: “AAAA,CAEA,CAEA;” ‘,’ 表示行内的位置信息分隔符 本例表示目标文件的这一行有三个有效的位置信息。 位置信息的第一位表示目标文件的列的 偏移 信息 本例中,表示列的信息是 ‘A’、‘C’、‘C’,对应的数字为 0、+1、+1,(vlq 编码,在线编解码工具) 注意,这个是偏移信息; 列数从 0 开始,依次累加偏移值可以算出当前的位置信息对应的真正的列 所以本例中表示的是目标文件的第 n 行中的第 0 列,第 1 列,第 2 列(没错是第 2 列) 源文件的信息 如:‘AAAA;ACAA;ADAA;’ 位置信息的第二位表示源文件的信息,本例子中是 ‘A’、‘C’、‘D’,对应数字是 0、+1、-1 如果 sourcemaps 中的 sources 字段只有一个文件的话,那么位置信息中第二位一直是 A(不需要偏移) 假设 sourcemaps 中 sources: [‘a.js’, ‘b.js’] 本例的意思是 AAAA: 目标文件第 0 行第 0 列 对应 第 0 个文件 a.js ACAA; 目标文件第 1 行第 0 列 对应 第 1 个文件 b.js ADAA; 目标文件第 2 行第 0 列 对了 第 0 个文件 a.js (偏移是 -1 又回到了 a.js) 源文件的行信息 位置信息的第三位表示源文件中的行的信息, 理解了位置偏移的概念,我们很容易理解 如:‘AACA,CACA;AACA;‘ 那么 AACA: 目标文件的第 0 行第 0 列 对应 第 0 个文件的第 1 行 CACA: 目标文件的第 0 行第 0+1 列 对应 第 0 个文件的第 1+1 行 AACA:目标文件的第 1 行第 0 列 对应 第 0 个文件的第 1 行 (注意:’;’ 后的行列偏移信息归 0) 源文件中的列信息 位置信息的第四位表示源文件中的列的信息 如:'AAAA,CAAC;' 那么 AAAA: 目标文件的第 0 行第 0 列 对应 第 0 个文件的第 0 行第 0 列 CAAC: 目标文件的第 0 行第 0+1 列 对应 第 0 个文件的第 0 行第 0+1 列 位置信息的第五位 第五位表示变量的偏移,对应 sourcemaps 中的 names 字段,表示目标文件中的变量名对应域源文件中的变量 如:’AAAA,CAACC;AAAAD;' sourcemaps 中 names 字段是 [‘a’, ‘b’] 那么 AAAA: 目标文件的第 0 行第 0 列 对应 第 0 个文件的第 0 行第 0 列,没有变量的信息 CAACC: 目标文件的第 0 行第 0+1 列 对应 第 0 个文件的第 0 行第 0+1 列,有变量信息,变量在源文件中是 ‘b’ (0+1=1) AAAAD: 目标文件的第 1 行第 0 列 对应 第 0 个文件的第 0 行第 0 列,有变量信息,变量在源文件中是 ‘a’ (1-1=0) --------- 大神分割线 --------- 怎么使用 Sourcemaps Q: 线上小程序报错,我怎么通过 sourcemaps 还原到源代码中? A: 如报错 appservice.js 1:15000, 表示目标文件第一行 第 15000 列位置报错。根据上文介绍的,通过 mappings 字段算。 Q: 不会。 A: 如果你会写代码的话,参考下边 [代码]import fs = require('fs') import {SourceMapConsumer} from 'source-map' async function originalPositionFor(line, column) { const sourceMapFilePath = '如果你不真的替换的成 sourcemaps 在硬盘中的位置,那你还是放弃自己写代码吧。 ' const sourceMapConsumer = await new SourceMapConsumer(JSON.parse(fs.readFileSync(sourceMapFilePath, 'utf8'))) return sourceMapConsumer.originalPositionFor({ line, column, }) } originalPositionFor(出错的行,出错的列) [代码] Q: 不会写代码 A: 下载最新版的开发者工具,菜单-设置-拓展设置-调试器插件 [图片] [图片] Q: 为啥都是 null? A: 每个小程序版本都应该对应一个sourcemap文件。 运营中心那里下载的 sourcemap 是对应线上最新的小程序版本。但运营中心的报错集合了多个小程序版本。拿旧小程序版本的报错信息,和最新版本的 sourcemap,是匹配不出的。开发者工具和ci 上传的时候,会提示下载对应版本的 sourcemap 信息,可以自助保存。 [图片] Q: 怎么确定有没有版本对应上 A: 下载的 sourcemap 中有个 wx 字段,标明了该 sourcemap 文件对应小程序版本号。 [图片] [图片] 前提 1.确保发生错误的小程序版本和下载回来的 sourcemap 版本是一致的。 a. 下载 sourceMap 文件,可在 mp 后台或开发者工具上传成功弹窗下载 2.确保 map 文件和发生错误的 js 文件是对应的。sourcemap 的目录和文件说明 a. APP 是主包,FULL 是整包(仅在不支持分包的低版本微信中使用),其他目录是分包 b. 每个分包下都有对应的 app-service.js.map 文件。 c. 如果是使用了按需注入特性(app.json中配置了lazyCodeLoading),那么每个分包下还会有 appservice.app.js.map(对应分包下非页面的js),和所有页面的 xxx.js.map 以上事情都确保正确之后,还是出现行列号匹配不出来的情况。那就需要进一步排查。 线上运行的小程序 sourcemap 文件是怎么生成的? 处理流程:源码 [ a.js a.js.map b.js b.js.map ] -> 开发者工具(JS转 ES5,压缩)-> 微信后台(合并 js 文件)[ appservice.app.js appservice.app.js.map]。 注意:如果源码在交给工具之前是经过了 webpack 等打包工具的处理,那源码这里需要有 map 文件。否则不需要存在 map 文件。 可以看出,map 文件经过三个步骤的处理,每个步骤都有可能导致出错,因此开发者需要先排查,是否是前两个步骤出错导致的 map 文件失效的。 如何排查前两个步骤产生的 map 文件是否有问题。 1.排查 a.js.map 文件是否有问题。 a. 可以在 a.js 的代码中写一下 throw new Error(‘test sourcemap’)。 b. 使用了 webpack 的情况下,要构建为生产环境的版本。 c. 在开发者工具模拟器中运行对应的页面,看看控制台中的报错,错误行列号是否能正常映射到源文件。 2.排查 开发者工具(JS转 ES5,压缩)步骤是否有问题。 在排查完第一步的基础上,点击预览,用微信上扫码预览,并打开调试 vConsole 功能,检查 vConsole 中是否有报错信息,检查报错信息中的行列号是否能正常映射到源文件。 如何排查 微信后台(合并 js 文件)是否有问题。 a. 一定要先排查完前两个步骤再来排查这一步,一般情况下,这一步是不会出错的。 b. 如果有问题,也只会导致 map 文件中的行号信息出现偏移。比如 Error 信息中显示报错地址是 100: 200,行号是 100。那么你可能直接用 100: 200 在 map 文件中搜索不出信息,但是如果 用 150: 200 就可以搜索出来,说明行号偏移了 50。那其他报错也可以偏移 50 后再进行搜索就找到结果。 c. 怎么排查偏移了多少?可以结合 error.message 的内容,初步判断大概错误的内容是什么。把对应的 map 文件放到这个网站上 source-map-visualization 进行搜索,找出哪些相同列号的地方。再结合 error.message 的内容进行判断。 d. 如果排查到是这一步导致的问题,请在社区上联系我们,我们会在后续版本进行修复。 依旧排查不出原因? 先整理一下按照上述步骤排查的结论,再在社区上联系我们协助
2023-02-10 - 升级开发者工具到最新,种种原因需要恢复旧版,旧版安装包找不到应急处理方法
刚需 新的开发者工具出来发现跟现有项目有兼容性问题。 而项目一天不能停,要急着修改上架,所以要恢复最新的开发者工具到旧版本 旧版本安装包没备份找不到了怎么办,2个方案: 解决方案 1、使用自带的回退功能 开发者工具菜单,回退功能,如果这里回退的版本不行或者不能正常回退,那么使用方案2 2、稳定版更新日志页面选择回退 如果是稳定版,可以在稳定版的更新日志页面找到对应旧版本的历史下载链接: 稳定版 Stable Build 更新日志 | 微信开放文档 https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html 3、根据规律找出历史版本下载链接 分析规律 找出指定旧版本的下载链接,直接打开链接下载旧版本。 应急处理的下载链接格式: [代码]https://servicewechat.com/wxa-dev-logic/download_redirect?type=x64&from=mpwiki&download_version=1021910120&version_type=1 [代码] 这个链接:后面版本号(1910120)改成你想要的版本就为所欲为的下载旧版本了。 版本号1910120的分拆:前6位代表发布的年月日(YYMMDD)格式后面的一位代表当天的第几个版本,从0开始 另外说说url里面的type是代表平台(x64/ia32/darwin) version_type代表版本类型:正式版/预览版/开发版(推测) 下载链接demo 经过上面分析后,可以得出1910120的X64版本下载链接为: https://servicewechat.com/wxa-dev-logic/download_redirect?type=x64&from=mpwiki&download_version=1021910120&version_type=1 MacOs版本下载链接为: https://servicewechat.com/wxa-dev-logic/download_redirect?type=darwin&from=mpwiki&download_version=1021910120&version_type=1
2020-09-24 - 哪里可以下载微信开发者工具旧版本?
自从下载了新的微信开发者工具,各种难用,加载半天就加载不出来,老是卡死,而且一切在旧版本就都不会发生,我另一台电脑还没有更新到最新版本,很好用,但是最新版本时不时就卡死,加载慢,点击预览半天才出来。这些都是我升级工具版本之前没有发生过的。本来我觉得各小程序开发者工具之间跟微信有壁,微信开发者工具各种好用,QQ支付宝之类的开发者工具各种难用,但是自从更新,我要收回这个话了。
2020-04-22 - (12)微信同声传译插件
我 微信界的同传扛把子! 识别你的语音? Of course! 我就是你的知己! 翻译你的中文? No problem! 我的英语好着呢! 听懂她的英文? So easy! 你想听我就敢译! What’s more! 我还能读给你听! 如何快速实现语音转文字、文本翻译、语音合成等等能力? 不用着急,让微信同声传译插件来帮你! 今天我们的小故事想和大家分享微信同声传译插件的故事。 1 应用场景 大家好,我叫“微信同声传译”插件,是由微信智聆语音团队、微信翻译团队与公众平台联合推出的同传开放接口,可通过语音转文字、文本翻译、语音合成接口,为开发者赋能。下面介绍我的应用场景: 场景1: 英语口语、听力双管齐下,没有外教也能学好英语! 把我放在小程序里,我既可以将口语转为文字,也可以帮助用户判断发音是否标准纯正,是最佳听众和英语学习道路上的良师益友; 场景2: 出国旅游,英语蹩脚怎么办? 这时我可以应用到翻译小程序里,说中文,译英文,再也不怕出国交流难。 场景3: 看剧时想要吐槽!可是手里有零食,打字不方便怎么办? 只要在小程序里有我,用户就可以按住按钮说话,语音转文字,帮你发送弹幕! [图片] 微信同声传译插件目前开放了以下三个接口——语音识别接口、语音合成接口、文本翻译接口。 通过这个插件,插件使用者可以轻松实现语音读取识别、文本转语音和中英文文本转换,避免这类需求的重复开发工作。 [图片] 2 如何使用插件? 插件接入流程 >>> 开发者在小程序插件中搜索“同声传译”、“语音识别”可以搜索到微信同声传译,添加使用后按使用文档接入使用,同时小程序开发者还可通过 https://github.com/Tencent/Face2FaceTranslator 查看我们开源的插件使用案例。 [图片] 1 登录小程序后台管理,进入“设置”; [图片] 2 点击第三方服务; [图片] 3 点击添加插件; [图片] 4 输入“同声传译”或者“语音识别”、“翻译”等搜索关键字搜索插件并添加,同时可以点击“查看详情”,获取插件的详细介绍、接入说明和开发文档。 [图片] 3 插件简介 1 插件名称 微信同声传译 2 插件AppID wx069ba97219f66d99 3 插件使用指南 微信同声传译插件设计之初,采用和小程序官方流式录音API、网络请求API类似的javascript调用接口,小程序开发者可以快速接入使用此插件。小程序“面对面翻译”使用了这些接口,并且已经开源 [开源地址],便于开发者快速开发。 [图片] (面对面翻译小程序) 具体使用接口可以查看微信同声传译插件使用文档。
2018-08-17 - 如何用小程序开发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