如何开发一款支持插件的桌面应用?-iToolBox诞生记

1,364 阅读3分钟

序言

两年前,因为自己的需要我开发了一款桌面软件,目的在于把一下常用的工具放在本地,没有网络的情况下,可以使用大部分软件,因此iTools就这样诞生了。

一年前在放出了部分截图后,很多人都作出了评价。

具体看 这样的工具类应用,不知各位大佬有没有需要? - #掘金沸点#

随着功能的增加,越来越多的功能需求需要往里添加,每次增加一个小的功能就需要重新打包发布。于此同时,我再评论中看到了一个这样的评论:

image.png

抱着学习一下的目的,我下载了 uTools 。

我发现 uTools 使用了和我相同的框架 Electron ,于此同时做到了可插件化的增加功能,于是我就开始研究这个要怎么做,我的工具也能做到插件化,于是就开始了 iTools 的插件化之路。

目标

此次的重构目标为:插件化。

所有的改动都只为实现插件化的目标。

结果

iToolBox 应运而生。

主要变化

  • 支持插件化增加功能
  • 工具版本和api版本分离,单独维护,互不影响

截图:

主界面:

image.png

菜单

image.png

扩展管理

image.png

关于

image.png

目前已有的API大类主要有以下:

image.png

技术浅析

Electron 的 webview 标签提供了一个preload的属性,可以用来加载一个脚本,在打开的页面中。

因此我们只要写一个脚本,实现主线程(ipcMain)与Webview的渲染线程进行通讯就可以了。

目前我所了解到的实现方案为两种:

  1. 直接通讯Webview => ipcRenderer => ipcMain
  2. WebSocket 通讯,在主线程中建立websocket,在webview中链接socket

我采用了第一种方案,具体实现伪代码为:

main.js

// 添加监听
ipcMain.on('api-name', async (event, params) => {
    // 执行相应api的功能,并返回结果
    const res = await apiFunction(params);
    // 传递结果会 ipcRender
    event.sender.send('api-name-result', res);
});

icpRender.js

// 与 主线程 通讯
const sendActionToMain = (apiName, params) => {
    ipcRenderer.send(apiName, params);
    rerurn new Promise((resolve, reject) => {
        ipcRenderer.once(`${apiName}-result`, (event, result) => {
            result ? resolve(result) : reject();
        });
    });
};

webview.js

// 添加 webview 的消息监听
webview.addEventListener('ipc-message', async (event) => {
    // 发送给主进程执行
    const result = await sendActionToMain(event.channel, event.args[0] || {});
    webview.send(`${event.channel}-result`, res);
});
// webview 中发送消息到应用渲染进程
const sendActionToRender = (apiName, params) => {
    // 发送消息到webview所在的渲染进程
    ipcRenderer.sendToHost(apiName, params);
    return new Promise((resolve, reject) => {
        // 接收返回结果
        ipcRenderer.once(`${apiName}-result`, (event, res) => {
            res ? resolve(res) : reject(false);
        });
    });
};

扩展

为了更好的完善项目,保证插件的简易化开发,相应的我也写了插件的CLI工具,能够快速的完成插件的项目搭建、配置、打包等。

CLI

iToolBox-cli

感想

由于 iToolBox 实现了插件化功能,所以插件的功能更新与版本升级,可以完全脱离主项目的打包,实现完全的分离。相应的通过这种模式,我们也可以实现桌面版微信一样的功能,如打开公众号文章页面、打开小程序等相类似的功能。并且使用了 Electron 我们可以很完美的使用 Node 的相关生态,为桌面端应用提供更多的能力。