本文包括的内容:css
介绍小程序原理的文章比较多,这篇讲的比较细:微信小程序架构分析。这篇文章的做者也成功的实现了wept,让小程序运行在本身的webapp里。html
参考最多的是微店的Hera,完成度很是高的小程序框架,可以将小程序的demo代码在web/iOS/android运行起来,并且实现了不少工具。Hera的问题是开发于比较早期的版本,不兼容最新的版本了。Hera还有一个问题是他修改了小程序构建以后的目录结构,采用了service.html做为service部分的入口,跟小程序自己的实现尚有有一些区别。因此Hera只可以构建执行本身编写的小程序,不能执行别人编写的小程序。vue
个人目标是可以运行其它人开发的app,意味着我只能经过逆向的方式拿到wxapkg。可是由于拿不到源码,因此要尽量在构建环节跟小程序保持一致。python
通过数周的挣扎,目前已经实现了运行官方demo。已经达到"可行"的阶段,可是还远远谈不上“可用”,由于须要实现小程序大量的API,这是个体力活,依赖我的的力量难以完成。android
官方demo小程序原先的目录分为几类文件:git
demo
├── app.js
├── app.json
├── app.wxss
├── config.js
├── image
│ ├── green_tri.png
│ ├── ...
├── page
│ ├── API
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ ├── pages
│ │ │ ├── action-sheet
│ │ │ │ ├── action-sheet.js
│ │ │ │ ├── action-sheet.json
│ │ │ │ ├── action-sheet.wxml
│ │ │ │ └── action-sheet.wxss
│ │ │ ├── ...
│ │ └── resources
│ │ └── ...
│ ├── ...
├── project.config.json
├── util
│ └── util.js
└── vendor
└── qcloud-weapp-client-sdk
├── ...
复制代码
通过小程序的开发环境构建后,生成了一个*.wxapkg文件。 这个文件能够经过从越狱的iPhone或者root的安卓手机上拿到。有部分人用charles经过https抓包拿到了下载连接,也拿到了包。 拿到后要进行解包。有大神已经经过反编译安卓apk的方式拿到了解包部分的代码,而后用python重写了一遍。源码见wechat-app-unpack。github
解包后获得的目录以下:web
1.wxapkg_dir
├── app-config.json
├── app-service.js
├── app-service.js.map
├── image
│ ├── green_tri.png
│ ├── ...
├── page
│ ├── API
│ │ ├── index.html
│ │ ├── pages
│ │ │ ├── action-sheet
│ │ │ │ └── action-sheet.html
│ │ │ ├── ...
│ │ └── resources
│ │ └── kind
│ │ ├── api.png
│ │ ├── ...
│ ├── ...
└── page-frame.html
复制代码
转换过程能够分为三部分:算法
openVendor
命令能够在小程序中获取到构建脚本wcc和wcsc, 以及各个版本小程序的执行SDK ****.wxvpkg,这个SDK也能够用wechat-app-unpack解开,解开后里面就是WAService.js和WAWebView.js等代码。json
wxss 转换成了css,wxml转换成了inject_js,实际上就是virtual_dom。 是用什么工具转换的?小程序里是叫wcc和wcsc。在开源工具hera本身实现了一套wxss-transpiler和wxml-transpiler。而hera的前身wept是直接使用wcc和wcsc。 咱们为了减小维护成本,直接采用wcc和wcsc。 由于咱们没有wcc和wcsc的源码,因此只能借助wxss-transpiler和wxml-transpiler来帮助咱们理解wxml/wxss的构建原理。
wxss-transpiler调用了一个PostCSS的插件,用来处理wxss。 PostCSS 提供了一种方式用 JavaScript 代码来处理 CSS。它负责把 CSS 代码解析成抽象语法树结构(Abstract Syntax Tree,AST),再交由插件来进行处理。插件基于 CSS 代码的 AST 所能进行的操做是多种多样的,好比能够支持变量和混入(mixin),增长浏览器相关的声明前缀,或是把使用未来的 CSS 规范的样式规则转译(transpile)成当前的 CSS 规范支持的格式。
wxml-transpiler:实现了一个转译器的工做,好比postcss也是转译器,包括解释器(parser),代码转换器(Transformer),代码生成器(Generator)。这个是闭源的。
更多实现原理见这篇文章
小程序在App中执行时的时候分为三个不一样的模块,View/Service/Native,各司其职。
View和Service都在WKWebView中执行,互相没法调用。他们之间经过Native层通讯。
Native和WebView之间经过webkit.messagehandler和evaluateJavascript互相调用。
WeixinJSBridge.publish: view和service之间的透传,在WKWebView之间传递消息。
WeixinJSBridge.subscribe: 注册监听,监听view和service之间的消息调用。
WeixinJSBridge.invoke: View或者Service传递消息到Native,而后Native使用逻辑调用js callback。
WeixinJSBridge.on:监听Native的事件。
这里以iOS为例介绍Native执行过程。安卓相似。
经过解压微信的ipa能够拿到WAService.js和WAWebView.js两个基础库文件,文件内容与hera的service.js/view.js已经有了较大的区别。 咱们采用小程序的架构和hera的两个webView的方案,尽量模仿小程序的执行过程。
View部分是比较直观的,就是WKWebView加载web页。这里须要在app-config.json里读取到首页的路径,而后加载该页面。这个路径下的xxx/index.html是没法直接加载的,须要作一些处理。要引入本地执行SDK里的index.css和view.js, 而后把page-frame.html
里的virtual-dom所有塞进该页面。 而后loadHTML便可。
View全部的WKWebView也是要注册WKUserContentController的,用于通讯。 经过反汇编能够得知这个类在微信中叫YYWAWebView
,调用js是直接调用-evaluateJavaScript:completionHandler:
方法的。
view.js中包含的逻辑:
Service部分的实现,Hera和微信小程序采起的了不一样的架构。 Hera的实现较为简洁,跟View部分保持一致,采用了WKWebView,调用-evaluateJavaScript:completionHandler:
方法执行js,js回调OC时使用WKScriptMessageHandler。 经过反汇编能够得知这个类在微信中叫WAJSCoreService
,js和OC之间的调用是采用JavascriptCore互相调用。
JavascriptCore它首先要加载app-config.json并把这个配置赋给一个全局对象__wxConfig。而后他要加载service.js是SDK基础,再而后他要加载app-service.js,这里面包含了用户编写的js逻辑。最后它发出全局消息 WeixinJSBridge.publish('serviceReady',,);</script>
唤起小程序app的初始化。
Service.js中包含的逻辑:
Native执行的问题比较复杂,由于基本是黑盒,里面发生了什么并不知道。 hera的方案在构建过程就已经跟小程序实际的方案有所区别,会提升维护成本。因此咱们只能靠猜想来实现Native的执行过程。
Native部分就是做为入口,运行环境,跳转,转发消息,实现扩展。包括网络模块/摄像头/tabbar实现的都是扩展。 咱们能够得知的是消息传递的协议。而后只能经过safari来调试webView,根据协议的名称和出入参来猜想协议的内容。
小程序是颠覆我对Web的固有印象,最初还觉得是相似weex或者rn的调用原生的方式,没想到几乎彻底是运行在WKWebView之上的。
存在的问题:
setData:
这种传递整个model对象,是两次对象的深拷贝,可能会增长两次json的序列化和反序列化,若是model对象很复杂对性能影响比较大。固然已经比纯web页强不少了。目前来看仍是只适合轻量化的应用。受制于架构以及微信的平台,我的认为是对Web的替代和改善。可是就算在可见的将来,仍是很难跟native抗衡。
现代浏览器和操做系统之间的界限愈来愈模糊。App的"下载/安装"过程自己就是一种妥协。只要小程序的体验足够好,应该没有人会拒绝。