微信开发者工具官网下载(深入了解-微信开发者工具)
主要介绍微信开发者工具如何编译小程序代码 ,如何实现小程序模拟器以及如何调试小程序 。
1 简介
虽然在开发语言层面小程序与传统的网页差别不大:是使用JavaScript 脚本语言编写逻辑代码 、使用类似于HTML的WXML来描述页面的结构 、使用类似于CSS的WXSS来描述节点的样式 ,但是由于小程序渲染和逻辑分离的运行机制与传统的网页存在差异 ,所以无法使用传统的网页的开发调试工具 ,因此我们使用小程序开发生态一站式IDE——微信开发者工具 。开发者可以借助微信开发者工具完成小程序的代码开发 、编译运行 、界面和逻辑调试 、真机预览和提交发布版本等功能 。
图1 微信开发者工具
微信开发者工具是一个基于nw.js ,使用node.js 、chromium以及系统API来实现底层模块 ,使用React 、Redux等前端技术框架来搭建用户交互层 ,实现同一套代码跨Mac和Windows 平台使用 。
图2 微信开发者工具底层框架
2 代码编译
微信开发者工具和微信客户端都无法直接运行小程序的源码 ,因此我们需要对小程序的源码进行编译 。代码编译过程包括本地预处理 、本地编译和服务器编译 。为了快速预览 ,微信开发者工具模拟器运行的代码只经过本地预处理 、本地编译 ,没有服务器编译过程 ,而微信客户端运行的代码是额外经过服务器编译的 。
1 编译WXML
WXML(WeiXin Markup Language)是小程序框架设计的一套标签语言 ,用于构建出页面的结构 。小程序的渲染层的运行环境是一个WebView,而WebView无法直接理解WXML标签 ,所以需要经过编译 。 微信开发者工具内置了一个二进制的WXML编译器 ,这个编译器接受WXML代码文件列表,处理完成之后输出JavaScript代码 ,这段代码是各个页面的结构生成函数 。
图3 WXML的编译过程
编译过程将所有的WXML代码最终变成一个JavaScript 函数 ,预先注入在WebView中 。在运行时确定了页面路径之后 ,将路径作为参数传递给这个函数得到该页面的结构生成函数 ,页面结构生成函数接受页面数据 ,输出一段描述页面结构的JSON ,最终通过小程序组件系统生成对应的HTML 。
代码清单1 如何使用页面结构生成函数
//$gwx 是WXML编译后得到的函数 //根据页面路径获取页面结构生成函数 var generateFun = $gwx(name.wxml) //页面结构生成函数接受页面数据 ,得到描述页面结构的JSON var virtualTree = generateFun({ name: miniprogram }) /** virtualTree == { tag: view , children: [{ tag: view, children: [miniprogram] }] }**/ //小程序组件系统在虚拟树对比后将结果渲染到页面上 virtualDom.render(virtualTree)上传代码时 ,微信开发者工具直接将本地的WXML代码文件提交到后台 ,由后台进行WXML编译 ,后台的WXML编译器和开发者工具本地内置的WXML编译器是同一套代码生成的。
2 编译WXSS
WXSS (WeiXin Style Sheets) 是一套样式语言 ,用来决定 WXML 的组件应该怎么显示 。为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性 。同时为了更适合开发微信小程序 ,WXSS 对 CSS 进行了扩充以及修改。与 CSS 相比 ,WXSS 扩展的一些特性,包括rpx尺寸单位和样式导入语法 ,这些特性都是WebView无法直接理解的 。
微信开发者工具内置了一个二进制的WXSS编译器 ,这个编译器接受WXSS文件列表 ,分析文件之间的引用关系 ,同时预处理rpx ,输出一个样式信息数组 ,如图4 ,每个WXSS文件对应于这个数组中的一项 。图4 WXSS的编译过程
在运行时 ,根据当前的屏幕宽度 ,计算出1rpx对应多少像素单位 ,然后将样式信息数组转换成最终的样式添加到页面中 。
由于样式在微信客户端存在兼容性问题 ,为了方便开发者 ,微信开发者工具提供了上传代码时样式自动补全的功能,利用PostCSS 对WXSS文件进行预处理 ,自动添加样式前缀 。3 编译JavaScript
微信客户端在运行小程序的逻辑层的时候只需要加载一个JS文件(我们称为app-service.js) ,而小程序框架允许开发者将 JavaScript 代码写在不同的文件中,所以在代码上传之前 ,微信开发者工具会对开发者的JS 文件做一些预处理 ,包括ES6转ES5和代码压缩(开发者可以选择关闭预处理操作) ,在服务器编译过程将每个JS文件的内容分别包裹在define域中 ,再按一定的顺序合并成 app-service.js 。其中对于页面JS和app.js需要主动require 。
图5 JavaScript的编译过程
3.模拟器
小程序模拟器模拟小程序在微信客户端的逻辑和界面表现 ,方便开发者实时查看代码效果 。由于系统差异以及微信客户端特有的一些交互流程 ,少部分的API无法在模拟器上进行模拟 ,但对于绝大部分的 API 均能够在模拟器上呈现出正确的状态 。同时微信开发者工具提供多种机型尺寸以及自定义机型尺寸功能 ,方便开发者进行界面样式的机型适配 。
图6 小程序模拟器
2 逻辑层模拟
在iOS微信客户端上 ,小程序的JavaScript代码是运行在JavaScriptCore中 ,在Android微信客户端上 ,小程序的JavaScript代码是通过 X5 JSCore来解析的 。而在微信开发者工具上我们采用了一个隐藏着的Webivew来模拟小程序的逻辑运行环境 。
图7 微信客户端小程序运行环境模型简图
图8 微信开发者工具小程序运行环境模型简图
在微信开发者工具上WebView是一个chrome的
我们在开发者工具底层搭建了一个本地HTTP服务器来处理小程序模拟器的网络请求 。其中:
./__asdebug/asdebug.js: 是开发者工具注入的脚本 。
./__dev__/WAService.js:是小程序逻辑层基础库。
./util.js 、./app.js 、./index.js:开发者JS代码 。
WebView在请求开发者JS代码时,开发者工具读取JS代码进行必要的预处理后 ,将处理结果返回 ,然后由WebView解析执行 。虽然开发者工具上是没有对JS代码进行合并的,但是还是按照相同的加载顺序进行解析执行 。
图9 appservice内容
WebView是一个浏览器环境 ,而JsCore是一个单纯的脚本解析器 ,浏览器中的BOM对象无法在JSCore中使用 ,开发者工具做了一个很巧妙的工作 ,将开发者的代码包裹在define域的时候 ,将浏览器的BOM对象局部变量化 ,从而使得在开发阶段就能发现问题 。
图10 BOM对象局部变量化
3 渲染层模拟
微信开发者工具使用chrome的 <webview />标签来加载渲染层页面 ,每个渲染层WebView加载
http://127.0.0.1:9973/pageframe/pageframe.html开发者工具底层搭建的HTTP本地服务器在收到这个请求的时候 ,就会编译WXML文件和WXSS文件 ,然后将编译结果作为HTTP请求的返回包 。当确定加载页面的路径之后 ,如index页面 ,开发工具会动态注入如下一段脚本:
// 改变当前webview 的路径 ,确保之后的图片网络请求能得到正确的相对路径 history.pushState(, , pageframe/index) // 创建自定义事件,将页面结构生成函数派发出去 ,由小程序渲染层基础库处理 document.dispatchEvent(new CustomEvent("generateFuncReady", { detail: { generateFunc: $gwx(./index.wxml) } })) // 注入对应页面的样式 ,这段函数由WXSS编译器生成 setCssToHead()4 客户端模拟
微信客户端为丰富小程序的功能提供了大量的API 。在微信开发者工具上,通过借助BOM(浏览器对象模型)以及node.js访问系统资源的能力
,同时模拟客户端的UI和交互流程 ,使得大部分的API能够正常执行 。
借助BOM ,如wx.request使用XMLHttpRequest 模拟 、wx.connectSocket 使用 WebSocket、wx.startRecord 使用MediaRecorder 、wx.playBackgroundAudio 使用
借助node.js ,如使用fs实现wx.saveFile 、wx.setStorage、wx.chooseImage等API功能 。
借助模拟UI和交互流程 ,实现wx.navigateTo 、wx.showToast 、wx.openSetting 、wx.addCard等 。5 通讯模拟
上文已经叙述了小程序的逻辑层 、渲染层以及客户端在微信开发者工具上的模拟实现 ,除此之外 ,我们需要一个有效的通讯方案使得小程序的逻辑层 、渲染层和客户端之间进行数据交流 ,才能将这三个部分串联成为一个有机的整体 。
微信开发者工具的有一个消息中心底层模块维持着一个WebSocket服务器 ,小程序的逻辑层的WebView和渲染层页面的WebView通过WebSocket与开发者工具底层建立长连 ,使用WebSocket的protocol字段来区分Socket的来源 。
代码清单2 逻辑层中的消息模块 // <webview/>的userAgent是可定制的 // 通过userAgent中获取开发者工具WebSocket服务器监听的端口 var port = window.navigator.userAgent.match(/port\/(\d*)/)[1] // 通过指定 protocol == APPSERVICE 告知开发者工具这个链接是来自逻辑层 var ws = new WebSocket(`ws://127.0.0.1:${port}`, APPSERVICE) ws.onmessage = (evt) => { let msg = JSON.parse(evt.data) // …处理来自开发者工具的信息 } // 调用API接口 wx.navigateBack ws.send(JSON.stringify({ command: APPSERVICE_INVOKE , data: { api: navigateBack, args: {} } }))创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!