写点什么

深入分析小程序运行环境框架原理

用户头像
小风以北
关注
发布于: 2021 年 03 月 31 日

目前小程序凭借其高曝光率、开发成本低、运行更流畅等优势和特点,一经推出就被广泛使用,面对小程序的火爆,自然而然地,就有很多开发者转战小程序领域,今天就让我来带你了解下小程序运行环境背后的故事吧。

 

但是对于想要学习了解这些内部架构来说,目前市面上的教程更多是告诉你如何使用现有规则开发一款小程序功能,少有说明白一套小程序内部机制是如何运行起来的。所以,今天我会给你分享小程序的运行原理。

 

为了让你更好地理解本文所讲的内容,我们先对小程序的运行环境进行一个大概的理解。然后从开发者工具分析破解、核心文件解读和架构流程图解这三个层面来加深对小程序运行原理的理解。

 

小程序运行环境

根据微信小程序开发文档可以得知小程序在三端的运行环境场景:

  • iOS :小程序逻辑层的 JavaScript 代码运行在 JavaScriptCore 中,视图层是由 WKWebView 来渲染的。

  • Android:小程序逻辑层的 JavaScript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Mobile Chrome 内核来渲染的;

  • 开发工具:小程序逻辑层的 JavaScript 代码是运行在 NW.js 中,视图层是由 Chromium Webview 来渲染的。

 

从小程序在三端中的运行环境可以看出来,它们存在逻辑层和渲染层之间的交互,具体是如何交互的呢?我们可以从渲染层和逻辑层之间的通信模型来找答案:

 


从这张图中,我们可以看出小程序采用了一种较为合适的技术方案,实现渲染层和逻辑层分别由 2 个线程管理:渲染层的界面使用了 WebView 进行渲染,逻辑层采用 JsCore 线程运行 JS 脚本。当一个小程序存在多个界面时,渲染层就会存在多个 WebView 线程,这两个线程之间的通信会经由微信客户端来做中转,逻辑层发送的网络请求也经由 Native 转发,

 

为什么要采用这种技术方案呢?主要原因是小程序的管控限制,比如不能直接操作 DOM 树、页面跳转等管控措施,更好地形成自己的生态闭环。

 

现在我们已经对小程序运行环境的基本组成有了一些了解,下面我就从开发者工具分析破解、文件解读和架构流程图解这三个层面来讲述小程序运行环境的具体知识点。

 

微信开发者工具分析破解

我们先从微信开发者工具分析破解讲起。

 

首先,我们从微信开发者工具中打开官方提供的小程序 demo 项目:

 


从编辑栏和文档中,我们可以知道一个页面的组成结构存在四种文件格式,我们来看下是哪四种格式呢?

  1. .js 后缀文件表示当前页面逻辑

  2. .wxml 后缀文件是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构

  3. .wxss 后缀文件用于表示一套样式语言,用于描述 WXML 的组件样式

4. .json 后缀文件表示是页面的配置原则

 

这些是我们大部分开发者看到或知道的一些表面内容。你可能会问,什么是深层次的内容呢?下面我们就来一一分析。

 

刚才我们也讲到了小程序中存在逻辑层和渲染层,那怎么在开发者工具中发现它呢?

 

鼠标点击 微信开发者工具–》调试–》调试微信开发者工具 

你可以拿出鼠标按照这样的顺序来操作,点击微信开发者工具,然后点击调试,点击调试微信开发者工具。之后就会弹出这样一个页面:

 


可以看到我做了两处标记,第一处标记的 webview 是渲染层,每个页面 src 对应一个地址,第二处标记的 webview 就是逻辑层。

 

仅仅是这样一个页面,我们是没办法直接查看 webview 中的具体内容的,还需要一些操作。你可以在刚才打开的控制台 Console 中输入找到对应标签,查看对应的 webview:

document.getElementsByTagName('webview')
复制代码

 

再通过这个命令查看具体的 webview 内容:

document.getElementsByTagName('webview')[0].showDevTools(true,null)
复制代码

 

如果你直接打开对应的 dom 树,第一个 webview 展示的就是渲染层相关信息:



比如从这张图中我们就可以看到这个页面渲染层所依赖的一些文件和一些方法,通过结果论来推断这些文件从何而来有何作用。

 

而对于 service 逻辑层的 webview,可以直接在开发者工具右下方控制台 Console 输入 document,这样就能查看了:

 


经过上面的介绍,你就能知道,通过 dom 树和 source 资源可以看出加载的一些本地文件资源。那么接下来,我再告诉你如何找到这些文件的出处,包含文件本身的引用和代码执行返回的结果。

 

我们从刚才那张图中看到 script 引入了一些 WA 开头的文件,这些文件其实就是小程序运行时核心的基础库文件了,我们在控制台输入 openVendor()命令,会自动弹出对应的文件框:

 


这些.wxvpkg 后缀文件就是微信基础库的版本文件,通过相关工具解压后可以看到文件内容格式:

 


需要特别注意的是,还存在两个 wcc 和 wcsc 可执行文件,这两个文件有什么作用呢?

 

先来说说 wcc 文件,wcc 将微信小程序设计的一套 wxml 标签语言,用于构建出页面结构,转为 WebView 可以理解的标签,毕竟渲染层还是运行在 webview 中,我们可以通过一张图来看下它的编译流程。

 


它的编译流程是这样的,先加载小程序所有页面中 wxml 格式的文件代码,将它们转换成一个 $gwx(pagePath)的 js 函数,注入到 webview 中。然后,在小程序运行时,可以知道当前的页面路径,执行这个函数会生成该页面的结构函数,之后接受页面数据,输出一段描述页面结构的 virtual dom json 对象,最后通过小程序内部组件生成页面对应的 HTML 标签,页面标签通过 wcc 编译转化成我们熟悉的节点。

 

那么 wxss 文件的作用是什么呢?它主要负责把 wxss 内容转换为视图可使用的 css 内容,它同时会分析文件之间的引用关系,添加尺寸单位 rpx 转换,还能根据屏幕宽度自适应以及样式导入,最后会生成一个 eval()函数用于处理 rpx,输出一个样式信息数组。

 

小程序核心基础库文件解读

刚才我们看到了小程序运行时核心的基础库文件,其中 WAservice.js、WAwebView.js、appservice.js 等文件是承载小程序运行环境的最核心文件,所以,有必要对这几个文件进行重点解读,

 

先来看下 WAservice.js 文件,直接打开它是一个打包混淆后的文件,有大约 6 万多行:

 


为了更直观、更具可读性,我们可以使用 js-beautify 美化,在 VS Code 采用函数缩放,可以使代码的可读性大大增高。



这样一看其实很清晰了,我们可以看到一些常听说的微信对象,比如:

  • WeixinJSBridge:用于消息通信封装调用,主要微信环境与 native,开发环境与开发者工具后台服务的通信

  • appServiceEngine:用于定义页面全局的方法,如 define,require, App,Page,Component,getApp 等

  • virtualDOM:和 Vue、React 中 virtualDOM 实现相似,但这里它主要模拟了 DOM 接口上面的 element 对象

  • expraser:它是用于框架组件的方法定义,意味着逻辑层也具有一定的组件树组织能力。

 

还有一些其他对象和内容就不描述了,感兴趣的话,你可以自己下载下来看看。

 

经过上面的美化和工具处理,可以看到对象里面有很多个 function(e,t,n)文件,对应的就是每个暴露的方法,下面要做的就是把这些方法的代码手动反编译回正常可读性高的源码文件。

 



小程序架构图及运行流程

 

通过对小程序运行环境和核心文件的了解,你可能对小程序的运行原理有了一个比较零散的认识,知道了小程序运行原理的一些特征和要素,下面我们通过小程序整体的架构层级图和运行流程来系统地了解它的运行原理。

 


从这张图中,自上而下可以看出大致的一个层次结构:

  • 展现层:这是小程序的页面显示,包括菜单、标题等展示内容

  • 控制层:包括 UI 控制、中枢控制

  • 然后来看消息处理层:包含了通信消息分发处理、缓存

  • 服务层就是包括网络、存储、文件等服务

  • 还可以看到,基础设施层包括日志文件、数据存储

  • 基础本地层是访问本身设备相机通讯等功能

  • 操作系统层就是运行载体平台,比如 ios、Android

 

了解了小程序的架构图,接下来我们从运行环境流程层面来分析启动时 controller webview 和通讯之间的关系。



首会先加载小程序系统配置文件:主要包含 app.json 相关文件和场景。然后创建 servicewebview 自动连接到 socketserver 获取网络信息,再根据配置创建 pagewebview 用于解析主页路径创建主页 Webview。之后通知 Socket Server 路由信息,在 pagewebview 创建之前,发送 onAppRoute 信息,创建后,发 onAppRouteDone 信息通知,并且 Socket server 转发控制层信息到 appservice,最后 APPSERVICE 通知 PAGEFRAME 渲染,PAGEFRAME 告知 APPSERVICE 渲染的状态。

 

可能你听完这些内容会有点不知所云,前面没有提到有消息通知说明啊,但其实在微信开发者工具,有一个消息中心底层模块维持着一个 WebSocket 服务器,

 

小程序逻辑层的 WebView 和渲染层的 WebView 通过 WebSocket 与开发者工具底层建立长连,使用 WebSocket 的 protocol 字段来区分 Socket 的来源,

 

那么,具体来说,消息处理的类型发送和接收是怎么做的呢?

 


主要是通过不同的消息类型来进行处理,常见的几种消息类型如下:

 

1.APPSERVICE_ON_EVENT

消息由控制层发出,APPSERVICE 和 WEBVIEW 层接收后无需处理直接 callback

 

2.APPSERVICE_INVOKE

消息由 APPSERVICE 层发出,APPSERVICE 和 WEBVIEW 层接收后处理对应的 api 方法实现,再按需 callback

 

3.APPSERVICE_PUBLISH

消息由 APPSERVICE 发出,WEBVIEW 层接收后无需处理直接 callback

 

4.WEBVIEW_ON_INVOKE

消息由 WEBVIEW 层发出,WEBVIEW 层接收后处理对应的 api 方法实现,再按需 callback

 

5,WEBVIEW_PUBLISH

消息由 WEBVIEW 发出,APPSERVICE 层接收后无需处理直接 callback

 

以上就是小程序工具端实现的一些消息类型和传输方式,当然在客户端肯定不会直接采用 socket 方式进行链接,因为在客户端上处理效率性能和稳定性问题不是最合适宜的解决方案、

 

以上就是本文的一些内容,最后我来总结一下。我们主要是从开发者工具破解、小程序核心基础库文件解读和小程序架构这三个层面来讲述小程序的环境运行原理。需要注意的重点内容是,我们要知道小程序与普通网页区别采用了渲染层和逻辑层,还要知道自定义的标签和样式怎么编译转换成 webview 可以识别节点和样式,另外,消息通信与处理也需要重点学习。

 

如果你想了解如何完成小程序代码编译打包和多端运行环境平台的具体实现,你可以关注开源项目

https://github.com/gongmw/blog,在这里你会找到相关的文档

wept(https://github.com/wetools/wept)实现浏览器 iOS 小程序运行环境

 

我是来自《小风以北》公众号的小风,我们下期再见
发布于: 2021 年 03 月 31 日阅读数: 8
用户头像

小风以北

关注

公众号【小风以北】 2020.04.09 加入

一个不只会撸代码的程序员

评论

发布
暂无评论
深入分析小程序运行环境框架原理