第六期 - 「工程化 之 PC客户端各生命周期详解」 - 2020.4.18

359 阅读22分钟

PPT首页.png

本文是第六期分享主题 -「PC客户端各生命周期详解」的文字稿,可以通过查看来巩固知识点。

一、前言

本文是根据2020.04.18 日,第六期分享主题「PC客户端各生命周期详解」整理而来的文字稿。

本文分享以 “过程” 为切入点,对PC桌面应用程序开发主要生命周期关注点展开话题,以思路引导为主,带你全面理解开发应用程序各关注点。

二、介绍

1. 我是谁?

SCM,2009年参加工作,直到2014年中旬前主要从事后端JAVA开发,期间善于使用ExtJs,那会还没有明确的前后端之分,处于全栈开发时期。一个偶然的契机,接手了公司的前端框架,出于些特殊原因,要重新写一套适合公司的框架,EraJs应运而生,这目前还是公司占80%以上项目PC WEB项目的首选框架。这一从事前端框架开发,2014 ~ 至今,6年过去了,期间整过Jquery、Bootstrap、Zepto、Jquery UI、第三方UI插件等等源码,也产出了Eui1.0、T2.0、T3.0、T3.5(T系列框架主要使用于PC客户端)。构建从Grunt到后来的Gulp,再到现在的Webpack,现在主攻React方向中后端最佳解决方案,可视化开发、工程化建设、基建完善。

2. 我们的团队

我所带领的前端框架组,目前主要3个人,主要服务于公司PC WEB、PC客户端项目框架支撑工作,逐渐完善框架体系,更好的提效,做好技术支撑工作。

3. 怎么联系我?

下面是我的微信二维码,对前端基建充满兴趣的可以加我交流,我们也会定期的分享更多框架相关的主题。

WechatIMG1.jpeg

三、主题背景


在开发中,可能会存在以下疑问:

  • 对客户端开发各阶段没有一个直观的了解
  • 只知道如何开发业务功能,对工程体系一无所知
  • 效率不高,出问题坐等支持,自己不知所措
  • ...


 针对以上困惑,接下来从工程体系各阶段做全面的解读,带你全面了解工程化各生命周期。 

四、初始化工程


在介绍工程脚手架之前,我们先来了解下yeoman。

4.1 什么是Yeoman?


Yeoman帮助我们创建项目,提供更好的工具来使我们的项目更多样化,Yeoman其实是三个工具的集合:yo、grunt、bower。这里我们主要使用的yo(脚手架)工具。
Yeoman提供generator系统,一个generator是一个插件,在我们在一个完整的项目上使用yo命令时,会运行该generator。

4.2 安装yo以及脚手架


命令行执行:

npm install yo -g


针对titanOne3.0框架,我们开发了自定义的generator,可以更便捷的创建项目并开发,脚手架名为: generator-titanone

命令行执行:

npm install generator-titanone -g

4.3 创建工程


_generator-titanone_脚手架安装完成之后,在任意目录创建文件夹并进入:

mkdir titanOne-demo && cd titanOne-demo


执行命令:

yo titanone

根据提示依次操作:

  1. 输入工程目录名(默认为titanOne-quickstart)
  2. 选择运行环境(electron/web,使用光标上下键切换)
  3. 输入项目应用名(默认为quickstart)


完成输入/选择之后,依次按回车键确认,待命令执行完毕,项目创建成功。

4.4 创建业务模块


首次创建业务模块时,需要在应用根目录(例如:titanOne-demo-pc)的目录下打开命令行并执行脚手架命令,之后则对命令行的打开目录则无强制要求。

yo titanone:module

依次提示:

  1. 选择当前语言环境
  2. 输入作者姓名
  3. 输入模块路径
  4. 输入模块名称(默认为index)


完成输入/选择之后按回车键确认,命令执行完毕,在titanOne-demo-pc/app/views目录下创建业务模块路径成功。查看模块下文件,包含标准的entry_index.page、entry_index.js、以及国际化目录i18n等相关文件。

4.5 创建多应用


脚手架支持在工程目录下创建多个应用目录,需要在工程根目录下打开命令行并执行脚手架命令:

yo titanone:ex

执行命令之后,依次提示:

  1. 输入应用名称
  2. 选择运行环境(electron/web)


完成输入/选择之后按回车键确认,命令执行完毕,应用目录创建成功。

五、工程规范

5.1 标准工程目录及配置


基于脚手架创建的标准工程目录结构是这样的:

titanOne-demo
├── bin
├── ├── electron.bat
├── ├── electron.sh
├── config
├── ├── electron
├── ├── ├── init.json
├── ├── ├── version.json
├── README.md
├── titanOne-demo-pc
├── ├── app
├── ├── ├── public
├── ├── ├── ├──  js
├── ├── ├── ├──  ├── common.js
├── ├── main.js
├── ├── mapping.json
├── ├── node_modules
├── ├── npm-scripts
├── ├── ├── before-build.script.js
├── ├── ├── generate.entry.file.js
├── ├── package.json
├── ├── README.md
├── ├── tests
├── ├── ├── data
├── ├── ├── ├── desktop.json
├── ├── ├── ├── menu.json
├── ├── ├── init.json
├── ├── ├── mapping.json
├── ├── webpack.config.js
├── tool
├── ├── app
├── ├── ├── electron
├── ├── ├── ├── app
├── ├── ├── ├── ├── main.js
├── ├── ├── ├── ├── package.json
├── ├── ├── ├── Gruntfile.js
├── ├── ├── ├── package.json
├── ├── ├── utils
├── ├── ├── ├── index.js
├── ├── electron
├── ├── ├── package.json
├── ├── theme
├── ├── ├── asserts
├── ├── ├── electron
├── ├── ├── ├── Gruntfile.js
├── ├── ├── ├── package.json
├── ├── utils
├── ├── ├── config.js

5.1.1 主要目录介绍

  • bin:  快速编译构建脚本目录
  • config: 发布版本配置文件目录
  • dist: 编译输出asar临时目录
  • setup: 打包脚本.iss及输出Output目录
  • tool: 打包编译框架app.asar,theme.asar包工程等
  • tool/app/asserts: 公共共享资源目录,比如:多个项目公共引用的图表包eKLine等,开发阶段会引用到上下文
  • tool/theme/asserts: 覆盖框架样式资源文件目录,比如:登录,主页logo图片替换或自定义customCss资源等
  • config.json: 打包阶段编译构建选项配置,比如:theme,i18n等
  • .titanOne: 项目下的webpack约定配置,主要为了webpack构建灵活性

5.1.2 webpack.config.js

**
框架已经将webpack相关构建封装到@erayt/titanOne-webpack-dependency包中,一个标准的简单工程只需要定义引用:

module.exports = require('@erayt/titanOne-webpack-dependency');


默认webpack封装包做了什么?

底层包默认封装了对entry_.js,entry_.page解析编译及devServer相关配置,打包发布优化编译等。

默认resolve定义alias:

 alias: {
    commonjs: path.resolve(publicDir,'js/common.js'),
    artHelpers: path.resolve(publicDir,'js/artHelpers.js')
}


默认对约定public目录下的common.js、artHelper.js做了别名约定,即:

项目js中可以像下面这样引用:

require('commonjs');


默认devtool:
项目优化原则,打包阶段关闭sourceMap,开发阶段开启:

  • 开发阶段:"source-map"
  • 打包阶段:false


如何重写框架约定的webpack构建?

框架公共封装包对外暴露webpack配置,所以,我们可以在webpack.config.js重写默认配置,比如:

'use strict';

const path = require('path');
const merge = require('webpack-merge');
const libsDir = './app/asserts/libs';
let webpackConfigs = require('@erayt/titanOne-webpack-dependency');

module.exports = merge.smart(webpackConfigs,{
    resolve: {
        alias: {
            echarts: path.resolve(libsDir,'echarts/echarts.min.js')
        }
    },
    devServer: {
        contentBase: [
            path.join(__dirname,"../tool/theme/asserts")
        ]
    }
});

备注:定义自定义的配置,通过调用merge.smart深度合并到默认配置即可。


如果个别项目开发过程,编译慢,卡顿比较明显,可在此配置:

devtool: false

5.1.3 .titanOne


该配置作为项目中webpack灵活集成的约定配置文件,主要用来定义服务代理,打包优化,主题引用等。

配置项 类型 描述 默认值
appName String 应用名称,请保持与打包后的.asar名称及菜单配置中的applCode保持一致 'app'
port Number webpack服务端口 80
servers Object 代理服务配置,格式key(服务上下文):value(服务地址),开发阶段webpack生成代理来源 {}
theme String 当前应用主题,可选:'default' or 'blue' 'default'
changeOrigin Boolean 是否改变远程域,具体了解webpack的devServer下的proxy的配置说明 false
commons Boolean 是否提取app/public/js目录下公共js引用生成commons.min.js,minSize默认30000 true
devtool Boolean 生产阶段是否开启sourMap,具体可参考webpack介绍 false
PEO Boolean 是否为标准构建工程,为true时,开发阶段会引用tool/app/asserts、tool/theme/asserts目录下的资源赋值给devServer的contentBase false
inline Boolean 打包阶段是否内联模式,为true时,js,css都会写入html false
pdfviewer Boolean 是否集成pdf预览插件,为true会引用@erayt/titanOne-web-pdfviewer下的dist到contentBase false
equery Boolean 是否集成equery插件,为true会引用@erayt/titanOne-equery包下的build指定语言到contentBase false

5.1.4 config.json


该配置文件主要约定打包阶段编译配置。

配置项 类型 描述 默认值
theme String 引用主题,可选:"blue"或"default"(打包theme.asar引用) "default"
i18n String/Array 引用国际化版本,可选:"zh_CN","en",需支持多语言时配置成数组格式 "zh_CN"
pdfviewer Boolean 是否集成pdf预览插件,为true时会打包到app.asar false

5.2 项目规范


框架结合webpack开发构建,为了项目组开发人员更好的将重心放在业务上,webpack构建的脚本做了统一约定解析。

5.2.1 工程目录结构

- ~root/app/
   - public/                      //公共资源路径,其中包括:css、js、tpl;
       		- /css/common.css           //项目公共样式文件(项目中各个模块需要的公共样式文件,可放在该文件中);
          - /js/common.js             // 项目公共js入口文件(项目中各个模块需要引用的公共代码);
          - /tpl/*.hbs                //项目公共模板(无需修改);
   - views/                      //业务代码路径;
          ...             
   - npm-scripts                 // 构建支持脚本
   - tests                       // 配置信息及测试数据
        - data                  // 桌面及菜单测试数据,开发阶段更方便维护菜单
      	- init.json             // 服务及代理信息配置
        - mapping.json          // 开发阶段,initjs及其他支持配置
       ...                           // .babelrc,.gitignore,.npmignore等
   webpack.config.js             // webpack相关定义
   .titanone                     // 应用名,端口,服务,主题及其他定义


业务代码必须在~root/app/views/目录下,原则上每个业务模块为一个独立的目录,目录下包含入口页面文件(*.page)以及静态资源目录~root/app/views/模块名称/static/, 资源文件目录中包含js、css、json、i18n、validation等。

5.2.2 模块目录结构


目录结构如下:

- module
    - static
        - i18n
        - css
        - js
        - modals
        - validation
    entry_*.page

注意:每个.page页面对应个同名的js文件,框架会自动引入script。

5.2.3 关键文件规范


**1. **入口页面 entry*.page_

每个业务功能,都会有一个页面文件,这个文件的命名规则为entry_*.page,必须以entry_作为前缀,.page作为文件类型。(调试时,webpack会解析文件,将其生成对应的html文件)。

  • .page 支持HTML标准语法及Handlebars语法
  • 页面支持国际化,需要国际化的文字以{{i18n.*.*}}替代即可,*.*对应国际化文件中的key值或者对象路径
  • 页面中需要引用该功能模块内相对资源文件(*.json或者.hbs),引用定义格式:{{basePath}}/static/**/*.json
  • 页面中DOM的id命名时,建议以project_module_*的方式命名(项目简称_模块名_id),避免不同项目和不同模块间的命名重复(单页面div模式需注意)
  1. **入口js文件 entry*.js**_


每个入口页面会对应一个入口js,名称与页面名称一致,格式:entry_*.js,调试时,webpack会解析该文件,将其生成对应的js文件,并将引用脚本写入对应的html页面文件中,其写法规范如下:

引用公共js代码:

require('commonjs');

备注:其中commonjs为webpack配置中定义的别名,详情可查看webpack的resolve的alias定义。


引用css(.less or .css)样式文件,一般放在static/css目录下:

require('../css/*.less')


功能需要对外暴露的方法或者属性,需要以**export var objectName={}**对象封装,以全局变量在外部(页面中)调用。 objectName即为全局变量,命名时需要避免模块间的重复,命名规范:模块路径(驼峰命名规则) + Modal(固定后缀),例如:test模块下entry_index.js内objectName为testMoal,test模块下entry_test.js内objectName为testTestMoal(非index文件需要加上文件名称)。

  • onRender:function类型,在页面渲染准备就绪之后,会自动解析该方法,相当于老版本框架的_Eui.onReady_方法
  • onMessage:Object类型,封装在该对象中的属性,页面加载之后,会在页面中注册各消息通道,供监听事件


实例:比如views目录有个_test_模块(test/entry_index.page),那么test/static/js目录下必有_entry_index.js_文件,内容如下:

export var testMoal = {
    ...
    
    onRender: function(){
        // 如果调用了Eui.onReady方法,必须定义在该事件内部
    },
    onMesssage: {       // 非必须定义,如果有自定义接收消息通道数据,则需定义,方便框架解析
        '自定义通道名称': function(e,args){
            // args 包含title,time,data三个属性
        }
    }
};

友情提示: 非必须对页面暴露的方法及属性不建议定义在_testModal_中,框架提供的默认通道可查看特殊消息通道详解。

5.2.4 自定义样式存放目录


在项目中需要引用外部的资源文件或需要根据项目自定义样式。可将资源文件放在根目录下的tool目录下的asserts:

~root/tool/                            
    - theme/                           // 重写样式目录
        - asserts/
            - index/                   // 主页重写样式
                - /static/css/
                    - /custom.css
                    - /img
            - login/                    // 登录页替换图片
                - /static/css/img
    - app/                             // 资源文件存放目录 
        - asserts/                   
            - iframe/                  // iframe模块 
            - index/                   // index模块
            - libs/
                - charts/
                    - /eKLine.js       // 例如引入图表js
  • 引入第三方JS包:存放的目录结构与框架引入模块的结构保持一致,编译时会进行拷贝。页面的调用路径为../libs/charts/eKLine.js
  • 重写框架样式:在init.json中配置customCss自定义css文件名

备注:图片的对应路径node_modules/@erayt/titanOne3.0-theme-index/dist/{{theme}}/css/img,图片名称对应会进行替换。


友情提醒:如何开启引用自定义样式?
_
可在init.json中配置:

{
    "customCss": "custom.css"
}


特别注意:自定义的样式一定是放在_index/static/css_目录下。

备注:登录模块支持替换图片,对应路径node_modules/@erayt/titanOne3.0-theme-login/dist/{{theme}}/css/img,图片名称对应会进行替换。

5.3 配置文件


子应用主要涉及到以下配置文件:

  • init.json
  • mapping.json
  • menu.json
  • desktop.json
  • .titanOne

备注:这里不做详解解释,可访问文档查看。

六、主应用启动过程


资金计划系统交互图.jpg

七、开发阶段


开发阶段你可能会关注以下点:

  • 配置文件维护(mapping.json、setting.json、init.json、.titanOne等)
  • API文档快速查找
  • 集成框架功能
  • 个性化存储/定制
  • Mock接口使用(推荐使用EasyMock)
  • 合理记录日志
  • 等等


这里今天不做详细一一解说,相关可以直接查找向导文档熟悉,这里今天主要讲下合理记录日志。

为了方便调试,提供打印输出日志,可以指定不同的日志级别,大于等于全局设置日志级别level将会控制台上输出。

全局日志级别由init.json中配置:

"logLevel": "warn"

提示:默认日志级别false,即不记录任何日志。


输出日志的方法_Eui.Logger.log_或者 Eui.log,两个方法等价。

参数 类型 描述
level String 日志级别,支持: silly、debug、info、warn、error
message String 日志内容,支持占位,比如:"The type '{0}' is not support!"
format Boolean 是否需要格式化日志内容,如果有{0}占位符情况设置true

备注:参数传递遵循第一个参数定义日志级别,最后一个参数如果是boolean类型即format,中间可以有多个占位符的参数,比如:{0} - {1} - {2}。

Eui.Logger.log("warn","It not support!");
Eui.Logger.log("info","hello {0},welcome.","SCM",true);
Eui.Logger.log("error","The type '{0}' is not support!","panel",true);
Eui.log("debug", "今天是第%s期 -「{1}」分享。", "六","PC客户端各生命周期详解", true);
Eui.log("debug", "今天是第%s期 -「%s」分享。", "六","PC客户端各生命周期详解");


当然该日志记录方法也支持console_** **_记录日志用法(占位符方式)。

八、入库发布版本

8.1 维护配置


发布版本涉及到应用相关配置,以及全局版本及服务相关配置文件的维护。

8.1.1 子应用mapping.json配置


该文件用来定义预加载页面(始终隐藏状态)、自定义参数设置、嵌入预执行JS相关配置。

{
    "initjs":"ws/static/js/initParam.min.js"
}


注意项:

  • 打包发布阶段,维护应用根目录下的mapping.json,注意与开发阶段文件的区分
  • initjs指向的文件路径相对于views目录,打包阶段文件后缀为.min.js, 注意与开发阶段.bundle.js区分
  • 如果没有需要定义配置,可不需要此文件(加载本地桌面/菜单数据除外,需定义{})。

8.1.2 子应用setting.json配置


除系统默认全局参数外,每个子应用都可以定义自定义参数项,来达到业务更灵活的个性化需求。开发与生产阶段存储目录有所不同。

  • 开发阶段: ~root/tests/setting.json,放在tests目录下
  • 打包阶段: setting.json的存放根目录下,最终打包进xxx.asar包


框架会读取合并所有应用参数配置,最终暴露Eui.Setting对象供调用,该对象是CacheMemory类的实例化,存储缓存key均以_'system:param'_作为key的前缀,可调用该类的所有方法,比如get,set,remove,batchSet方法。

调用方法示例:

// 缓存中存储的实际key为:'system:param:widgetZoom'
var widgetZoom = Eui.Setting.get('widgetZoom');
Eui.log('debug', widgetZoom); // 打印的值为:'true'

8.1.3 主应用version.json配置


该配置文件用来定义程序最新发布版本的增量版本(appVersion)号及全量版本号(frameVersion)。

提示:入库发布阶段,该文件在主工程根目录下的_config/electron/version.json_目录下。


比如:

{
  "frameVersion":"1.0.0",
  "appVersion": "1.1.0"
}

提醒:该配置文件根据入库实际情况维护,遵循版本增量递增原则,如果仅发布增量版本,全量版本号无需更新。

8.1.4 主应用init.json配置


该配置文件用来定义服务的相关上下文代理信息,以及一些个性化配置等。

提示:入库发布阶段,该文件在主工程根目录下的_config/electron/init.json_目录下。


比如:

{
  "proxy": {
    "ecas": {
      "server":"http://192.168.10.129:8080"
    },
    "equery":{
      "server":"192.168.10.138:8080"
    }
  }
}

8.1.5 FAQ


Q: 出于敏感信息保护,不希望_app.asar.unpacked_目录下的init.json暴露太多配置?

A:我们可以修改_tool/app/electron_目录下package.json下的

"compile:asar": "asar pack app ../../../dist/electron/app.asar --unpack {init,version}.json",

变更为:

"compile:asar": "asar pack app ../../../dist/electron/app.asar --unpack \"version.json\"",

这样,**init.json**将不会被打包到_dist/electron/app.asar.unpacked_目录下。

如果部分配置期望对外暴露,我们可以直接修改app.asar.unpack目录下的init.json,可能您不期望不受信任的配置有效,那么可以配置allowUnpackOptions(更多说明查看文档)来限制。

8.2 版本入库


服务端的编译是通过选择不同的"编译环境类型"来解析对应的描述文件执行构建任务。现就对客户端入库的相关文件作详细的说明,构建类型:

  • Node.js打包 : 定义模块需要执行yarn upgrade更新包及npm run build命令编译
  • Setup : 执行setup目录下的.iss文件制作exe
  • Node.js : 入库框架模块,最终需要发布npm到152私服

备注:常规的PC客户端入库需要选择"Node.js打包"和"Setup",特殊情况下,比如:需要入库自定义登录模块的,必须选择"Node.js"类型(建议与项目代码不同分支管理)。


特别提醒:基于titanOne3.5开发的项目入库必须是yarn编译,入库之前必须先找版本管理员指定yarn编译服务器,切记,切记,切记!!!

8.2.1 Node.js打包


该类型是客户端入库必选编译环境类型,包含tmp_update_Node.js.lst和tmp_Node.js.lst两个文件,格式:编译类型 + 仓库名:多个文件路径(以,分割)。

实例如下,tmp_update_Node.js.lst 内容模版:

yarn_erayt_release_cnpm_public:examples,tool\theme\electron,tool\app\electron,tool\app\electron\app,tool\electron


备注:以上内容是以titanOne quickstart的electron版本作介绍。

yarn_erayt_release_cnpm_public为固定文本(编译环境指定的npm源仓库别名),":"后的为工程的目录(需要执行yarn upgrade来更新依赖的工程)。

tmp_build.lst 内容模版:

examples,tool\theme\electron,tool\app\electron

备注:该描述文件用来定义需要执行npm run build命令(build定义在package.json中的scripts中)的工程目录,多目录以,号区分。

8.2.2 Setup


如果需要制作exe安装包,那么需要选择该编译环境类型,约定回去执行setup目录下的所有.iss文件(如果该目录包含logo.ico,那么会替换exe的安装桌面快捷图标)。

8.2.3 Node.js


如果入库的模块需要发布到公司npm私服,那么需要选择该类型。包含描述文件:tmp_Node.js.lst 和 tmp_update_Node.js.lst,内容模版如下:

yarn_erayt_release_cnpm_public:


备注:以上内容为固定文本,:后定义执行命令的目录,多个以,号区分。规则同tmp_update_Node.js.lst文件定义。

文件功能说明:

  • tmp_Node.js.lst:执行npm publish命令的工程目录定义
  • tmp_update_Node.js.lst:执行yarn upgrade命令再执行npm publish命令的命令。

8.2.4 FAQ


Q: 如何入库发布自定义模块到私服?

  • 申请入库分支,编译环境类型必须为"Node.js"
  • 通知版本管理员(马XX),指定编译服务器
  • 初始化入库工程,模块以及描述文件tmp_Node.js.lst 和 tmp_update_Node.js.lst,具体注意项可参考上述。

九、预投产演练阶段


投产演练阶段,还有个重要的环节,维护自动更新服务报文数据。

9.1 自动更新


自动更新服务接口作为PC客户端检测判断一个重要数据来源,版本信息中主要包含:平台信息、版本信息、加密MD5值、资源下载地址、变更日志等信息。

提醒:优先检测全量版本号。

9.1.1 版本配置


在version.json中我们可以配置版本信息。

配置项介绍如下:

配置项 类型 描述
frameVersion String 全量包版本号
appVersion String 增量包版本号

9.1.2 开启自动更新检测


通过在init.json中配置_checkUpdateUrl_来开启自动更新检测:

"checkUpdateUrl": "http://127.0.0.1/update.json"

备注:更新服务可以指向一个可访问的json请求地址,也可以是一个.action请求接口。

9.1.3 建议文件结构

version                   // 自动更新文件夹
			- appVersion            //用来存放增量包的文件夹
								- ResourceSetup.exe //增量包exe文件
			- frameVersion          	 //用来存放全量包的文件夹
								- Setup.exe      //全量包exe文件
changelog.txt         //自动更新日志
update.json           //自动更新配置文件

9.1.4 自动更新服务报文内容


update.json内容如下:

{
  "windows": {
      "appVersion": "0.0.1",
      "frameVersion": "0.0.1",
      "appUpdateUrl": "http://****/**/ResourceSetup.exe",
      "frameUpdateUrl": "http://****/**/Setup.exe",
      "appSign":"e3681da227e879fecc3e0b071a8787b0",
      "frameSign":"8c89e13fd3bbfed0c485c429d9a617d1",
      "forceUpdate":false,
      "more":{
        "updateTime":"2018-2-6",
        "changelog":"http://****/**/changelog.txt"
      }
  }
}


配置项说明:

配置项 参数类型 描述
appVersion String 增量包所对应的版本号,需要与项目中version.json中的增量版本号对应
frameVersion String 全量包所对应的版本号,需要与项目中version.json中的全量版本号对应
appUpdateUrl String 增量包下载地址
frameUpdateUrl String 全量包下载地址
appSign String 增量包文件MD5加密码 由MOCK工具生成
frameSign String 全量包文件MD5加密码 由MOCK工具生成
forceUpdate Boolean 是否强制更新
more Object 自动更新的提示内容;包含updateTime(更新时间)和changelog(更新提示的内容)属性

9.2 开启完整性检测


为了保障客户端运行环境的安全,对关键electron文件(.dll等)及项目资源包(.asar)做md5校验,保障运行环境中客户端是完整未被篡改的。
为了方便不同使用人员快速对客户端文件生成加密串,提供了包括:命令式 和 工具exe。

9.2.1 客户端集成方法


可根据服务端支持情况,通过配置开启防篡改功能,可在init.json配置中增加:

"enableTamperValidate": true


相关配置说明:

  • tamperResistantUrl: 默认接口地址'tamperProofing.action'
  • enableTamperValidate: 是否启用防篡改验证功能,默认false


检测过程:

  1. 请求接口
  2. 解密报文
  3. 判断istamper是否为"1"
  4. 通过filelist生成sign值与接口数据sign是否一致,如果false,立即退出,返回检测结果"不通过"

备注:当检测不通过时,过8秒自动关闭客户端。

9.2.2 前提


服务端支持防篡权请求接口tamperProofing.action通过init.json中tamperResistantUrl来修改请求服务地址。

  1. 请求接口参数格式:
  let  requestJson = {
        platform: "4",
        versions: [
            { version:”0.1.0”,type: “1”},
            { version:”0.1.0”,type: “2”}
        ]
    }

备注:请求参数使用RSA加密(与握手秘钥相同)。


参数描述:

参数 说明 类型
platform 平台类型,1:'IOS',2:'Android',3:'PC',4:'electron' String
type 资源类型, 1: 框架资源(根目录下dll,exe等,排除resources,locales之外), 2: resources 资源 String
version 版本号,对应version.json中appVersion(对应type值为"2"),frameVersion(对应type值为"1") Array
  1. 返回数据格式:
{
    "data":{
        "result": {
            "istamper": "1",
            "resData": [
                {"sign":"","filelist":"","type":"1"},
                {"sign":"","filelist":"","type":"2"}
            ]
        }
    },
    "success": true
}

备注:返回报文是使用RSA加密,客户端做解密,istamper字段标识是否客户端需要做防篡改校验。


字段说明:

  • sign: 生成的hash加密串
  • filelist: 加密文件列表,以","分割

9.2.3 基于命令生成加密hash


前提电脑已经安装node.js并指定公司npm源。

指定引用公司源:

npm config set registry http://192.168.10.152:7001


全局安装包:

npm i @erayt/hfile -g


用法:

$ hfile --help

  Usage: hfile [options] [command]

  Manipulate hfile archive files

  Options:
    -V, --version                    output the version number
    -h, --help                       output usage information

  Commands:
    hash|h [options] <dir> <output>  create hfile archive


排除多个文件:

Given:

    app
(a) ├── x1
(b) ├── x2
(c) ├── y3
(d) │   ├── x1
(e) │   └── z1
(f) │       └── x2
(g) └── z4
(h)     └── w1


Exclude: a, b

$ hfile h app sign.txt --unpack-dir "{x1,x2}"


Exclude: a, b, d, f

$ hfile h app sign.txt --unpack-dir "**/{x1,x2}"


Exclude: a, b, d, f, h

$ hfile h app sign.txt --unpack-dir "{**/x1,**/x2,z4/w1}"


对客户端资源文件生成hash:

$ cd root
hfile h ./resources ../resources.txt

备注:root为客户端根目录。


对electron底层相关dll等生成hash,忽略resources,locales目录:

hfile h . ../frame.txt --unpack-dir="{resources,locales}" --unpack=unins000.*

备注:unins000.dat,unins000.exe 为安装程序时生成,属于动态文件所以要忽略。

9.2.4 基于加密工具客户端生成


为了不同人员需求,提供客户端版本供使用,操作界面如下:

tool.png

备注:可点击"copy"将值复制到剪贴板。

十、异常信息收集


投产的项目从表面现象根据客户描述我们很难定位排查到具体问题。所以异常信息的收集并记录显得尤为重要。虽然我们的项目非自运营产品,没有配套的日志监控系统等基础建设来支撑,但是我们可以对_window.onerror_做统一监听,并把日志记录到日志文件。

系统主进程相关过程默认会有相关启动日志,根据情况合理设置日志级别:

"logLevel": "warn"

Q:如何开启error日志监听?
A:可init.json中配置"reportJsError": true来开启全局监听,系统右下角提示,并记录日志文件(方便问题排查定位)。

十一、更多关注

11.1 微信公众号

可关注公众号"Zebra前端进阶架构分享会",分享预告及所有技术、框架、方案分析等沉淀精选文章会通过公众号推送。

11.2 Zebra 语雀技术专栏

可以关注语雀知识库:www.yuque.com/zebratalk/

11.3 Zebra掘金技术专栏

可以关注掘金:juejin.cn/user/114004…

11.4 Zebra知乎技术专栏

可以关注知乎:www.zhihu.com/people/zebr…

11.5 微博

可以关注微博:weibo.com/zebratalk