Skip to content

插件系统

我们很高兴地宣布,在 Paperlib 3.0 中,我引入插件系统,这意味着你可以为 Paperlib 中开发插件进行功能扩展了!🎉🎉🎉

前言

本文介绍插件系统的整体设计,便于理解开发过程中可能涉及的每个部分。如果你只是想开发一个简易插件,可以跳过此文。如果你在开发一个相对复杂的插件,强烈推荐阅读本文。

进程与插件运行环境

为了妥协多平台开发,Paperlib 选择基于 Electron。因此在整个程序中,我们有三个主要的进程:

  • 主进程 (Main Process):负责管理整个程序的生命周期,以及与系统进行交互,如上下文菜单等。
  • 渲染进程 (Renderer Process):负责渲染界面,以及大部分的程序逻辑。
  • 插件进程 (Extension Process):负责插件的管理和运行。

每个插件都运行在插件进程中,且代码在单独的 node VM 中执行,因此,插件的崩溃并不会导致 Paperlib 的崩溃,各个插件之间也互不干扰。因此每个插件运行的环境都是 node 环境,没有 html 等相关环境(New Window 插件例外)。

进程间通信

插件进程除了运行插件的代码之外,还负责插件的下载更新、加载、卸载,以及偏好设置。而大部分的逻辑代码都运行在主或者渲染进程里。因此 Paperlib 通过扩展 MessagePort,实现了 Remote Procedure Calling (RPC) 来暴露主/渲染进程中的各个服务(service)的方法来供插件调用。

每一个跨进程方法调用,都会在内部被转换为一个 json 字符串并发给对应进程。这里面包含了想要调用的方法,传入的参数等必须信息。对应进程收到消息之后,会解析 json,运行相应方法,得到结果并返回给调用者所在的进程。除此之外,我们还实现了跨进程事件监听,让开发更为方便。具体的实现细节请浏览 Github

服务 Service

在每个进程中,都有许多服务提供各种各样的方法,来完成 Paperlib 的功能。比如主进程的 ContextMenuService 负责右键菜单相关的功能,渲染进程里面的 PaperService 负责最主要的论文相关的增删改查。相关实现可以在如 Github 找到。

Paperlib 中的服务的几乎所有方法都暴露给了插件进程以供调用。在插件进程中几乎可以实现操作 Paperlib 的全部部分。

服务事件 Service Event

几乎所有的服务都是 Eventable 的。这意味着每个服务都会在不同时机触发一些事件。在其他代码位置、进程可以监听对应的事件触发,来执行自己的代码。比如你可以监听用户选择的论文变化了,然后运行你的方法。

跨进程调用 API

为了方便开发,我们对插件进程暴露了主进程、渲染进程,以及插件进程的服务,并把他们集中在了三个对应的 API 中。你在接下来的文档中将会时常遇到这三个 API 组:

  • PLMainAPI: 包含了所有的主进程服务。
  • PLAPI: 包含了所有的渲染进程服务。
  • PLExtAPI:包含了所有的插件进程服务。

当你想调用一个进程对应服务的方法的时候,只需要在你的插件代码中编写如下:

ts
// const result = await APIGroup.serviceName.methodName(...)
const papers = await PLAPI.paperService.load(...)

因为是跨进程调用,所以几乎任何调用我们都需要使用 await 来等待异步结果的返回。如果你是在调用 PLExtAPI,因为是同一个进程,所以同步或异步视情况而定,请参考开发时的类型提示。

插件类型

我们设计了五种不同形式的插件:

  • Simple Extension:简单的功能,自己运行一些东西。
  • Command Extension:用户通过 3.0 版本引入的 command bar 触发命令,然后运行相应功能。
  • Hook Extension:通过在 Paperlib 生命流程中的不同钩子点注册钩子,来截断、修改流程中的内容。
  • UI Extension:修改 UI 界面的部分内容。
  • New Window Extension:创建一个全新的窗口,实现完全自定义的复杂的功能。

这五种插件涵盖了大部分插件场景,并可以相互混合。我们提供了对应的例子,会在之后详细介绍。

插件发布与下载

每一个插件,都是一个 npm 包,发布时与你发布一个 npm 包类似。其余的约定和限制我们会在之后解释。

在 Paperlib 设置界面的插件页面中,插件可以通过本地路径加载,或者搜索插件市场来下载。我们的插件市场依托于 npmjs.com

总结

总的来说。插件是运行在一个单独进程中,通过我们暴露的 API 进行操作 Paperlib 的 npm 包形式的一些代码。接下来我们推荐阅读开发环境设置,来开始开发你的插件吧!

Created by Future Scholars. Contact: hi@paperlib.app