写点什么

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

  • 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:081871

评论

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

超全算法笔试模拟题精解合集,这份《程序员面试宝典》简直太牛了

Java架构之路

Java 数据结构 面试 算法 编程语言

第二周作业二-学习总结

道长

极客大学架构师训练营

最新整理国内知名大厂7篇Java岗面试真题,奥利给!

Java架构师迁哥

2020年高频Java面试题集锦(含答案),让你的面试之路畅通无阻!

Java架构之路

Java 程序员 面试 编程语言

UML练习2

何毅曦

第二周 作业二:框架设计学习总结【未陌】

a d e

设计模式 架构设计

区块链+跨境贸易:让跨境数据高效共享可信

CECBC

区块链 跨境贸易 跨境电子商务

linux虚拟摄像头vivid配置

良知犹存

Linux 虚拟摄像

听说有人不了解柔性数组

C语言与CPP编程

程序员 数组 编程语言 C语言

架构师第二周总结

悠哉

腾讯某Java程序员为了肝出《300页图解网络知识》+《计算机底层操作系统》超全教程差点猝死!

Java架构之路

Java 程序员 面试 编程语言 操作系统

食堂就餐卡系统设计

谭明华

极客大学架构师训练营

第二周作业

华美而火锅

架构1期-第二周作业一

道长

极客大学架构师训练营

架构师第二周作业

悠哉

极客大学架构师训练营

flutter 中的video player对比学习

Daniel

第二周学习总结

饭桶

框架设计-第二周作业

睁眼看世界

极客大学架构师训练营 软件设计原则

C语言/C++基本语句编程风格

C语言与CPP编程

程序员 编程语言 C语言

架构师训练营 - week2 - 个人学习心得总结

谭明华

极客大学架构师训练营

极客时间架构师培训 1 期 - 第 2 周作业

Kaven

数据结构与算法:递归

Java架构师迁哥

Java 编程 程序员 算法

周总结二

何毅曦

小白也能看懂的REDIS教学基础篇——REDIS基础数据结构

Java 数据库 redis

原来我写的软件里面都是臭味 - 架构师训练营第 1 期 - 第二周总结

Todd-Lee

极客大学架构师训练营

第二周作业

饭桶

开放的是金融服务 必须确保持牌经营

CECBC

金融 银行

第二周 作业一【未陌】

a d e

设计模式 架构设计原则 基本原则

架构师训练营 - week1 - 个人学习心得总结

谭明华

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

Gosling

极客大学架构师训练营

const关键字应用总结

C语言与CPP编程

程序员 编程语言 C语言

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