惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
腾讯CDC
G
Google Developers Blog
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
有赞技术团队
有赞技术团队
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
美团技术团队
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志

博客园 - liulun

开源自荐:功能齐全的截图软件(仅1M) 开源自荐:功能齐全的截图工具(含录屏、截长图,体积仅780KB) 自荐:开源截图工具ScreenCapture:超多控制指令,支持截长图 脚踏esbuild祥云,胸怀tsx利刃,身披scss羽衣,追寻前端的本质 开源项目自荐:截图工具(小、快、功能丰富) 如何开发Vite3插件构建Electron开发环境 Electron是什么以及可以做什么 线上Electron应用具备哪些特征? 桌面软件开发框架大赏 微软要放弃Electron了???聊聊WebView2 自己实现一个Electron跨进程消息组件(兼新书自荐) 一个Electron的设计缺陷及应对方案 如何点击穿透Electron不规则窗体的透明区域 Electron团队为什么要干掉remote模块 谈Vite在Electron环境下吃花卷拉馒头的现象 公司只提供签名服务,不提供证书文件,如何打包Electron应用 vue3微前端架构——基于蚂蚁qiankun框架 Vite ❤ Electron——基于Vite搭建Electron+Vue3的开发环境【一】 Electron安装过程深入解析(读完此文解决Electron安装失败导致的无法启动,无法打包的问题) 大型Electron应用本地数据库技术选型 极客手中的利器Electron
如何把Electron做成一个Runtime,让多个应用共享同一个Electron
liulun · 2021-12-24 · via 博客园 - liulun

这个问题涉及到很多知识,而且要想把这个Runtime做好很绕。

下面我就说一下我的思路:
(以下内容以Windows平台为基础,Mac平台和Linux平台还得去调查一下,才能确定是否可行)

首先,我们先区分三类用户:

  1. Runtime建设者(就是我们)
  2. Runtime使用者(就是使用Runtime的开发者)
  3. 最终用户(就是使用Runtime开发者开发的应用的那些用户)

接下来我们就以Runtime建设者的视角来审视这项工作

首先我们要为Runtime使用者提供一个专有的打包工具,我们就叫它:打包工具。这个打包工具还内置了几个可执行程序,我们给他们起个名字,分别叫:

  • 最终安装程序
  • 最终执行程序
  • 最终卸载程序

好,我们一个一个聊他们的职责

打包工具的职责
按Runtime使用者的要求修改最终执行程序的图标、应用签名、版本、版权、文件名等资源信息;
按Runtime使用者的要求修改最终卸载程序的图标、应用签名、版本、版权、文件名等资源信息;
把最终执行程序、最终卸载程序与Runtime使用者开发好的HTML/CSS/JS等静态文件放到一起,压缩成一个压缩包,我们叫他:资源文件
把这个资源文件以资源的形式封装到最终安装程序中;
按Runtime使用者的要求修改这个最终安装程序的图标、应用签名、版本、版权、文件名等资源信息;
(修改资源的代码,后文有介绍)

这几个工作完成之后,Runtime使用者就可以把这个最终安装程序分发给最终用户了。

最终安装程序的职责
这个最终安装程序在最终用户的电脑上运行时,会完成以下工作:

检查最终用户的注册表,看其是否安装了我们的Electron Runtime
如果没有安装,则下载Electron的发行版,释放到一个特定目录下,并在注册表记下来。
在这个特定目录下记录当前应用的信息(卸载当前应用时要用到);
把自身的资源释放到最终用户指定的目录内,也就是前文说的资源文件
解压缩资源文件得到最终执行程序、最终卸载程序和Runtime使用者开发的HTML/CSS/JS等静态文件
写注册表记录最终卸载程序的位置,这样用户就可以在控制面板里卸载我们的程序了。
按最终用户的要求,创建开始菜单图标、桌面图标,这些图标均指向最终执行程序
(读取资源的代码,后文有介绍)

如果最终用户工作在没有网络的环境下,那么我们也可以允许Runtime使用者把Electron Runtime打包到最终安装程序内,这是打包工具的职责。

如果担心Electron官方提供的下载地址速度慢,可以考虑使用国内镜像地址:​npmmirror.com/mirrors/electron/

最终执行程序的职责
检查用户注册表,找到Electron Runtime的放置路径
启动Electron Runtime并把当前应用的入口程序当做参数传给Electron.exe,应用入口程序就是Runtime使用者开发HTML/CSS/JS等静态文件之一,
electron.exe path/to/entry.js
最终卸载程序的职责
删除安装目录下的文件
删除注册表的卸载程序信息
删除Electron Runtime所在目录下的应用程序信息,如果发现没有别的应用在依赖Electron Runtime了,那么就把Electron Runtime所在目录也删掉。


把一个文件作为资源写入一个可执行程序的代码如下所示:

HANDLE hFile;
DWORD dwFileSize,dwBytesRead;
LPBYTE lpBuffer;
char szFile[MAX_PATH+1] = {0};
::GetDlgItemText(hwnd,EditId,szFile,MAX_PATH);
hFile = CreateFile(szFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
dwFileSize = GetFileSize(hFile, NULL);
lpBuffer = new BYTE[dwFileSize];
ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL);
HANDLE hResource = BeginUpdateResource(szFilePath, FALSE);
UpdateResource(hResource,RT_RCDATA,MAKEINTRESOURCE(EditId),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPVOID)lpBuffer,dwFileSize);
EndUpdateResource(hResource, FALSE);
delete [] lpBuffer;
CloseHandle(hFile);
return 1;

可执行程序读取自身资源,把资源写到指定路径下的代码如下:

HMODULE hInstance = ::GetModuleHandle(NULL);
TCHAR szFilePath[MAX_PATH + 1];
GetPath(szFilePath,resourceName,hInstance);
HRSRC hResID = ::FindResource(hInstance,resourceID,RT_RCDATA);
HGLOBAL hRes = ::LoadResource(hInstance,hResID);
LPVOID pRes = ::LockResource(hRes);
DWORD dwResSize = ::SizeofResource(hInstance,hResID);
if(!dwResSize) return 0;
HANDLE hResFile = CreateFile(szFilePath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
DWORD dwWritten = 0;
WriteFile(hResFile,pRes,dwResSize,&dwWritten,NULL);
CloseHandle(hResFile);
if(dwResSize == dwWritten) return 1;
return 0;

这两段代码是从我的一个项目中摘抄出来的,仅供参考。

遗留的问题
我们并没有考虑多Electron版本共存的问题;
此方案高度依赖Windows API,跨平台实现差异肯定会比较大;
应用程序启动后,任务栏的图标是Electron Runtime的图标,而非Runtime使用者指定的图标(这是有解决办法的);