写点什么

实现微信小程序编译和运行环境系列 (核心篇三)

  • 2020-06-22
  • 本文字数:3690 字

    阅读完需:约 12 分钟

实现微信小程序编译和运行环境系列(核心篇三)

本章节就带大家通过微信官方的创建项目部分代码来讲解一下这些对外 api 如何通过我们自己方式来实现和微信相同的功能操作,我们通过微信开发者工具来自动创建一个默认的小程序项目 一个首页和日志页。



这个项目大家应该都比较熟悉吧,应该第一次接触小程序开始时引入眼前的场景,具体的其他内容我们就不在这里啰嗦了,直接看下它的 app.js 文件,编辑器打开后可以看到里面写了这些.


 //app.jsApp({  onLaunch: function () {    // 展示本地存储能力    var logs = wx.getStorageSync('logs') || []    logs.unshift(Date.now())    wx.setStorageSync('logs', logs)
// 登录 wx.login({ success: res => { // 发送 res.code 到后台换取 openId, sessionKey, unionId } }) // 获取用户信息 wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 wx.getUserInfo({ success: res => { } }) } } }) }, globalData: { userInfo: null }})
复制代码


先给大家把接下来部分要说明的消息事件整理出来让大家可以看的清楚一些,后面的内容主要是围绕这个消息事件和代码来说明



上面这个图就是从微信开发者工具里面打开页面时候出现的事件和消息类型以及有关数据,分析一下可以看出:


1、首先调用了同步 api getSystemInfo,我们可以看到在我们的项目代码里面没有存在这个 api,但是开发者工具第一步就调用了,所以在项目编译初始化的时候就触发了,至于 Receive 的数据返回的就是工具界面左上角的一些配置数据,大家可以打开自己的开发者工具看看,一些参数是你可以直接从上面观察到的,如手机型号 屏幕占比 网络类型等,这个同步 api 是系统自动调用的不用我们做写什么操作,而且它会比较频繁的调用。(这点我也没理解,当我打开控制台的时候他会调用很多次)


  • 在前面的文章中讲到同步的 api 都是通过走 http 协议’/apihelper/assdk’链接过来的,里面携带了 api 名和一些参数,所以我们可以直接拦截’/apihelper/assdk’请求进行处理


实例代码展示


     router.post('/apihelper/assdk', async (ctx, next) => {    const { api, args } = JSON.parse(ctx.request.body);    if (api === 'getSystemInfo') {      ctx.body = {        'errMsg': 'getSystemInfo:ok',        'model': 'iPhone 7 Plus',        'pixelRatio': 3,        'windowWidth': 414,        'windowHeight': 624,        'system': 'iOS 10.0.1',        'language': 'en',        'version': '7.0.4',        'screenWidth': 414,        'screenHeight': 736,        'SDKVersion': '2.7.1',        'brand': 'devtools',        'fontSizeSetting': 16,        'benchmarkLevel': 1,        'batteryLevel': 100,        'statusBarHeight': 20,        'safeArea': { 'right': 414, 'bottom': 736, 'left': 0, 'top': 20, 'width': 414, 'height': 716 }      };    }    })
复制代码


ctx.body 的结果集可以直接复制开发者工具中的数据就可以,如果要实际使用的话需要把部分参数改成动态获取的。


2、当代码执行 wx.getStorageSync(‘logs’) wx.setStorageSync(‘logs’, logs)的时候(标签二)通过前面的日志描述可以知道它们都是 appservice sdk 调用的同步的 api,就是我们普通使用的 Storage 它们包装做了一层转换,因为这个页面是初始化的时候调用的所以这里面的数据都是空的。当点击 log 页面的时候,就可以看到调用了 APPSERVICE_PUBLISH 事件类型,此类型是 view 层发给 service 层的我们看到它的 webviewID 存在值。



看出 data 里面的数据就是 Storage 存储的 Date.now()时间, wx.setStorageSync wx.getStorageSync 在源码对应的地方。




var r = re.IS_IOS ? "setStorage" : "setStorageSync"var r = re.IS_IOS ? "getStorage" : "getStorageSync"
复制代码


看出如果是 ios 的话就只能调用 setStorage getStorage 方式。


模拟代码展示:


const storage = new Map();
const getStorage = function (key) { return storage.get(key);};const setStorage = function (key, value) { storage.set(key, value);};const removeStorage = function (key) { storage.delete(key);};
module.exports = { getStorage, setStorage, removeStorage};
复制代码


如果想模拟全局的存储简单的可以直接使用 map 进行操作,然后在调用的时候获取对应的 api 进行获取和设置操作,完善的话存储可以采用浏览器的 LocalStorage,SessionStorage 或者一些 npm 包进行处理。


3、我们比较常用的一个 api 通过 wx.login 换取 code 可以看出(标签三)中,是通过逻辑层 service 自发自收的,发起一个请求通过 service 逻辑层处理后在回调回去,通过微信 api 源码可以看到调用的地方



这一块要想要弄的很好不是很容易,涉及到用户体系就要和服务端彻底打通,好在登录授权这块微信也是采用 OAuth2 协议实现的


如果有朋友对 OAuth2 还不是很了解明白的话,建议看下这个文档比市面上 90%的相关内容讲的更彻底通透。


4、当在小程序中打开页面时触发了 onAppRoute 事件,通过日志看出发送了 APPSERVICE_ON_EVENT 事件,path 表示当前页面,openType 表示操作类型,openType 如果不是很明显的话我们试着点击一下,从日志页面返回首页的后退操作。



看到"openType":"navigateBack"这个应该比较好理解解释了。


到这里我们会有一些不一样的地方了,因为这里的操作的是事件处理不是简单的 api 处理就 ok 了,所有前端页面操作的控制器都是一个整体,首先我们要先搭建这个载体容器存放各个部分。


模拟代码实例:


构建一个总管理处理的信息


constructor(wxConfig = {}, socketPort) {    super();    this.wxConfig = wxConfig;    this.systemManager = new SystemManager(this, wxConfig);    this.navigatorManager = new NavigatorManager(this, wxConfig);    this.pageManager = new PageManager(wxConfig, socketPort);    this.tabbarManager = new TabbarManager(this, wxConfig);    this._render();    this._launch();    window.socketClient.setEmitter(this);  }
复制代码


然后 render 页面信息,结合 node 后台服务渲染前端展示


    this.domElement = document.createElement('div');    this.domElement.id = 'container';    this.domElement.style = ` height: ${global.simulator.height}px; width: ${global.simulator.width}px;`    // system    this.domElement.appendChild(this.systemManager.domElement);    // navigator    this.domElement.appendChild(this.navigatorManager.domElement);    // pages    this.domElement.appendChild(this.pageManager.domElement);    // tabbar    this.domElement.appendChild(this.tabbarManager.domElement);
复制代码


后面就是监听各个事件控制和各种业务处理,核心还是要按照开发者工具的消息顺序和内容来实现。


例如上面我们提到的 navigateBack 我们自己这边实现按照平常的业务写法就 ok。


  navigateBack (path, query) {    let currentWebview = this.domElement.children.item(0);    let currentIndex = currentWebview.style['z-index'];    this.domElement.removeChild(currentWebview);
let targetPage = null; for (let i = 0; i < this.domElement.children.length; i++) { let webview = this.domElement.children.item(i); if (webview.style['z-index'] === `${currentIndex - 1}`) {
let viewId = +webview.getAttribute('data-view-id'); let path = webview.getAttribute('data-view-path'); let query = JSON.parse(webview.getAttribute('data-view-query')); window.socketClient.send(WebsocketMessage.onAppRoute(viewId, path, query, 'navigateBack')); window.socketClient.send(WebsocketMessage.onAppRouteDone(viewId, path, query, 'navigateBack')); targetPage = path; break; } } return targetPage; }
复制代码


重要的还是 socketClient.send 消息的正确传递才可以和基础库正确的交互


其他的很多对外的 api 实现方式都是大同小异,主要是在接收到消息后怎么处理设计


我们知道了核心的流程,下面要做的就是模仿设计,模仿它的消息格式和返回结构,设计自己的各系统模块的关联


对于小游戏而言大致是一样的,主要有几个点不同:


  1. 小游戏是通过根目录下的 game.json 来对小游戏进行全局配置,决定相关界面渲染和属性设置等;

  2. 在小游戏的运行环境里面不存在 BOM 和 DOM API,只有 wx API 对它们进行了包装,所以无法直接使用;

  3. 小游戏的运行层只有一层在 view 里面跑;

  4. 小游戏的大部分 api 主要都是对文件系统和网络的处理。


上面的一些总结主要是根据一些 api 的实现来描述扩展了一些,看完后希望大家对此有所了解,后面我打算从全局来讲下怎么从代码设计方面来设计整个浏览器运行环境实现方案。


2020-06-22 11:082467

评论

发布
暂无评论
发现更多内容

架构师训练营 - 第五周课后练习

joshuamai

Java踩坑记系列之BigDecimal

Java老k

BigDecimal

「干货总结」程序员必知必会的十大排序算法

bigsai

排序 排序算法 快速排序

甲方日常 57

句子

工作 随笔杂谈 日常

开源认证和访问控制的利器keycloak使用简介

程序那些事

开源 程序那些事 授权框架 keycloak 认证授权

802.11抓包软件对比之Microsoft Network Monitor

IoT云工坊

wifi 嵌入式 抓包

讯飞推出充电宝式便携拾音器,重新定义传统拾音

Talk A.I.

肝了一周的 UDP 基础知识终于出来了。

苹果看辽宁体育

计算机网络 计算机基础

成德眉资现代农业园区大联动促发展,“1链3e”引领四市农业产业数字化建设

CNG农业公链

家庭留白、中屏崛起与硬件棋局

脑极体

架构师训练营 W06 作业

Geek_f06ede

java: Compilation failed: internal java compiler error解决办法

LSJ

IDEA

表格控件Spread.NET V14.0 发布:支持 .NET 5 和 .NET Core 3.1

葡萄城技术团队

一期二班-吴水金-第六课作业

吴水金

Architecture Phase1 Week10:Summarize

phylony-lu

极客大学架构师训练营

熬夜不睡觉整理ELK技术文档,从此摆脱靠百度的工作(附源码)

996小迁

Java 编程 架构 面试 ELK

Alibaba官方发文:阿里技术人的成长路径与方法论

Java架构师迁哥

架构师训练营 - 第五周学习总结

joshuamai

Java踩坑记系列之Arrays.AsList

Java老k

Java

推荐几款MySQL相关工具

Simon

MySQL 工具 percona server

计算机核心课程必读书目——《高级数据结构:理论与应用》

计算机与AI

数据结构 算法

关于 AWS Lambda 中的冷启动,你想了解的信息都在这!

donghui

Serverless Faas 函数计算

Thread.start() ,它是怎么让线程启动的呢?

小傅哥

Java 线程 JVM 小傅哥 Thread

“奋斗者”号下潜10909米:我们为什么要做深海探索?

脑极体

大厂经验:一套Web自动曝光埋点技术方案

阿亮

埋点 曝光埋点 点击埋点 自动化埋点

为什么说应用架构需要分类思维?

Java架构师迁哥

面试者必看:Java8中的默认方法

Silently9527

java8 默认方法

《华为数据之道》读书笔记:第 4 章 面向“业务交易”的信息架构建设

方志

数据中台 数字化转型 数据治理

京东千亿订单背后的纵深安全防御体系

京东科技开发者

安全 网络 云服务 云安全

SpringBoot-技术专题-如何提高吞吐量

码界西柚

JVM-技术专题-垃圾回收策略

码界西柚

实现微信小程序编译和运行环境系列(核心篇三)_语言 & 开发_风逝_InfoQ精选文章