写点什么

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

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

评论

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

Windows AD巡检报错处理

BigYoung

windows AD 报错 巡检

吐血整理Windows电脑入侵自检大全

BigYoung

黑客 windows 日志 异常 自检

Django 表单处理流程详解

BigYoung

django 表单 流程

为什么越来越多的非计算机领域企业,在自主做软件时都选择使用快速开发工具?

Learun

Java 敏捷开发 快速开发 .net core

Nginx配置80端口用于多个域名

石云升

nginx 域名配置 80端口共用

「分布式一致性协议」从2PC、3PC、Paxos到 ZAB

大头星

Linux入门系列1--环境准备及Linux安装

黑马腾云

Linux centos 运维 操作系统

linux入门系列2--CentOs图形界面操作及目录结构

黑马腾云

Linux centos7 操作系统 系统运维

当代一线城市年轻人工作生活实录(HR篇)

Learun

Java 敏捷开发 快速开发 .net core

不懂 ZooKeeper?没关系,这一篇给你讲的明明白白

大头星

Java zookeeper 分布式

十年磨一剑-BIGO全球音视频技术解决方案

InfoQ_3597a20b53cc

人工智能 大数据 技术

CentOS 7 配置Supervisor 服务遇到的坑总结

BigYoung

centos 报错 Supervisor

Kotlin这么火!如何快速从Java过渡到Kotlin

华章IT

Java kotlin 协程 安卓

LeetCode题解:88. 合并两个有序数组,双指针+从后往前,JavaScript,详细注释

Lee Chen

大前端 LeetCode

低/零代码平台的优点有哪些?

代码制造者

编程语言 低代码 零代码 信息化 编程开发

linux入门系列5--新手必会的linux命令

黑马腾云

Linux centos7 Shell linux命令 linux操作

对于一款软件而言,完备的功能固然重要,但交互体验也不该被忽视

Philips

Java 敏捷开发 UI .net core 交互设计

当代一线城市年轻人工作生活实录(HR篇)

Philips

Java 敏捷开发 快速开发 .net core

白话讲解:消息队列到底解决了什么问题?

博文视点Broadview

读书笔记 分布式 RocketMQ 中间件 消息队列

艺术与科技的碰撞!Tristan Easton携手英特尔为漫威粉丝带来十代酷睿《复联》收藏版

最新动态

linux入门系列3--常见的linux远程登陆管理工具

黑马腾云

Linux xshell securecrt putty finallshell

对于一款软件而言,完备的功能固然重要,但交互体验也不该被忽视

Learun

Java 敏捷开发 快速开发 .net core

lgloo Software 的 Jira Cloud 转型之旅

Atlassian

项目管理 DevOps 敏捷开发 Jira Cloud

linux入门系列4--vi/vim编辑器

黑马腾云

vim Linux centos7 操作系统 VI

Django2.x中url路由的path()与re_path()参数解释

BigYoung

django path url re_path 参数

CIC国信公链:做坚实的底层技术支撑,让区块链为现代农业插上腾飞的翅膀

CNG农业公链

区块链 农业发展 CIC国信公链 CNG农业链 赵其刚

当代一线城市年轻人生活工作实录(蓝领打工仔篇)

Philips

Java .net 敏捷开发 快速开发 MES系统

《漫威复联》PC版游戏即将登陆,英特尔为其独家 CPU 合作伙伴

最新动态

话题讨论 | 特斯拉和拼多多杠上了,你有什么看法?

InfoQ写作社区官方

写作平台 话题讨论

为什么越来越多的非计算机领域企业,在自主做软件时都选择使用快速开发工具?

Philips

Java 敏捷开发 快速开发 .net core

跟我一起基于Karma搭建一个测试环境(上)

Jack Q

大前端 Karma 测试框架搭建

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