【转自第九小程序的博客】相信很多试用过微信小程序开发者工具的开发者,都会对它的实现有一些疑惑。本文试图分析其架构模型。解析。如有错误,请留言指出。本文分为以下几个部分:小程序调试技巧小程序主模块构成小程序模块模块间通信设计概念分析小程序调试技巧微信开发者工具默认禁用右键打开调试面板功能,并且我们可以修改部分开发者工具代码去掉那个限制。找到app.nw项目根目录,Mac下是/Applications/wechatwebdevtools.app/Contents/Resources/app.nw使用js-beautify批量格式化代码:cd/Applications/wechatwebdevtools.app/Contents/Resources/app.nwfind.-typef-name'*.js'-not-path"./node_modules/*"-not-path"./modified_modules/*"-execjs-beautify-r-s2-p-f'{}'\;注释掉app/dist/app.js文件第44行和app/dist/components/simulator/webviewbody.js文件第149行的preventDefault调用。101100版本还需要修改package.json文件去掉--disable-devtools。执行完以上操作后,可以右键打开页面的调试面板。需要注意的是,在视图页面使用面板会导致wxml面板不可用、触摸事件无响应等各种问题。请谨慎使用。通过代码可以发现,在配置目录下添加config.json文件,然后添加{isDev:true}可以开启开发者工具所谓的调试模式,但是配置后程序无法正常启动,所以只好暂时放弃这种方法了。构成小程序的主要模块小程序本身分为独立运行的两个主要部分:视图模块和服务模块。在开发者工具中,它们在不同的webivew标签中独立运行。视图模块负责UI展示,由开发者编写的wxml、wxss转换代码和微信提供的相关辅助模块组成。一个视图模块对应一个webview组件(也就是我们常规理解中的一个页面),小程序支持多个视图同时存在。视图模块通过WeixinJSBridge对象与后台通信。服务模块负责应用的后台逻辑,由小程序的js代码和微信提供的相关辅助模块组成。一个应用只有一个服务进程,也是一个页面(至少在开发者工具里,上线后可能跑在WeixinJSCore里)。与视图模块不同的是,它在程序生命周期中是在后台运行的。服务模块通过与视图模块不同但接口格式相同的WeixinJSBridge对象与后台进行通信。小程序模块之间的通信(开发者工具中各模块通信图)做过微信开发的开发者都会知道WeixinJSBridge对象,它是一个负责UI和后台交互的中间层。与之前的微信webview相比,app账号的WeixinJSBridge多了两个公共方法publish和subscribe,用于发布和订阅事件,实现双向通信。服务模块的WeixinJSBridge对象定义在文件app/dist/weapp/appservice/asdebug.js中,视图层的WeixinJSBridge对象定义在文件app/dist/inject/jweixindebug.js中。虽然两者使用相同的接口,都使用postMessage方法与后台进行通信,但是它们的内部工作是完全不同的。比如服务模块可以通过提示方式直接调用底层组件,而视图层的WeixinJSBridge只能发送消息(H5与Native交互参考JSBridge技术)。我们来看一个典型的交互流程:1.用户点击界面触发事件2.对应的视图模块收到事件后,将事件封装成需要的格式,然后调用publish方法发送:WeixinJSBridge.publish('PAGE_EVENT',data)数据参数示例:{"data":{"eventName":"onhidetap","data":{"target":{...},"currentTarget":{...},"type":"tap","timeStamp":11457,"touches":[...],"detail":{...}}},"options":{"timestamp":1475445858336}}3.后台(开发者工具中的nwjs运行环境)将数据处理后发送给service模块,数据形式为:{"to":"appservice","msg":{"eventName":"PAGE_EVENT","data":{"data":{"eventName":"onhidetap","data":{"target":{...},"currentTarget":{...},"type":"tap",“timeStamp”:75329,“touches”:[...],“detail”:{...}}},“options”:{“timestamp”:1475445858336}},“webviewID”:0},“command”“:”MSG_FROM_WEBVIEW"}4.service模块的WeixinJSBridge内部回调函数根据传入的数据找到view对应的页面模块并执行eventName指向的对应函数5.回调函数调用this.setData({hidden:true})更改数据,serivce层计算页面数据,向后台发送send_app_data和appdataChange事件,具体数据格式如下:{"appData":{"page/index":{...}}"sdkName":"send_app_data","to":"backgroundjs","comemfrom":"webframe","command":"COMMAND_FROM_ASJS","appid":"touristappid","appname":"chat","apphash":70475629,"webviewID":100000}{"eventName":"appDataChange","data":{"data":{"data":{"hidden":true}},"options":{"timestamp":1475528706311}},"sdkName":"publish","webviewIds":[0],"to":"backgroundjs","comemfrom":"webframe","command":"COMMAND_FROM_ASJS","appid":"touristappid","appname":"chat","apphash":70475629,"webviewID":100000}6.后台(文件dist/components/simulator/webviewbody.js)接收appDataChangeevent数据后,对数据进行简单封装,最后转发给视图层具体数据格式为:{"to":"webframe","msg":{"eventName":"appDataChange","data":{"data":{"data":{"hidden":true}},"options":{"timestamp":1475528706311}},"sdkName":"publish","webviewIds":[0],"to":"backgroundjs","comefrom":"webframe","command":"COMMAND_FROM_ASJS","appid":"touristappid","appname":"chat","apphash":70475629,"webviewID":100000,"act":"sendMsgFromAppService"},"command":"MSG_FROM_APPSERVICE","webviewID":0,"id":0.10577065353216675}7.视图层的WeixinJSBridge接收后台数据。如果webviewID匹配,则将数据与现有页面数据合并,然后虚拟dom模块执行diff和apply操作以更改dom。除了接口事件和应用程序数据,小程序模块之间的消息传递还包括触发本地方法、握手和生命周期。虽然加工对象和加工方法不同,但大体流程同上。view模块和service模块的WeixinJSBridge均使用postMessage接口(参考MDN文档)与后台通信,但由于该接口无法直接与nwjs后台进程通信,开发者工具会将app/dist/contentscript/contentScript.js文件为了contentScript被注入到view模块和service模块所在的页面,contentScript.js的代码提供了message消息到chrome.runtime通信接口的转换。微信开发者工具扩展了devtools,提供了AppData面板,开发者可以修改里面的数据,直接看到视图界面的变化效果。这里修改完数据后,nwjs会把消息发给service层,后面的事情和上面的4、5、6步一样:service发消息给nwjs,最后到达view层。设计理念分析小程序的分层设计显然是有意为之。它的中间层完全控制程序在界面上的运行,同时监控传输的数据和响应时间。一方面,程序的行为受到极大的限制,另一方面,微信可以保证他们对小程序的内容和体验有绝对的控制权。我们不能在小程序的js代码中直接使用浏览器提供的DOM和BOM接口。这是因为js代码外层使用局部变量进行屏蔽。另一方面,即使我们可以操作DOM和BOM接口,它们也对应服务模块页面,不会对页面产生影响。这个结构也说明小程序的动画和绘图API是为了生成一个最终的对象而不是一步步执行的。原因是json格式的数据传输和分析与原生API相比成本高昂。如果频繁调用,很可能会消耗过多的性能,从而影响用户体验。了解了上面的机制之后,再修改view模块和service模块的WeixinJSBridge,我们就不难让小程序运行在自己的环境中,这样我们就可以进行一些手机调试、单机等操作了。页面测试。
