2023年11月06日
如何在Electron浏览器中本地使用Swift脚本
Electron是一个使用HTML、CSS和JavaScript等Web技术构建厚客户端应用程序的框架。Electron提供了灵活性,可以维护一个JavaScript代码库来创建支持Windows、macOS和Linux的跨平台应用程序。基本上,您只需编写一次代码,就可以在各个平台上运行。
JavaScript几乎可以很好地满足应用程序中几乎所有所需的功能,但当需要与特定操作系统的本机API进行交互时,问题就会出现。在使用基于Electron的浏览器时,我遇到了这样的问题。有一个特定的需求,需要在Mac上特定时间间隔(几秒钟)内找到打开的应用程序窗口列表。Node或JavaScript没有提供任何接口来从操作系统层访问这些信息,因此我不得不想出一个自定义解决方案。
初始解决方案
最初,我通过编写OSAScript来解决这个问题。OSAScript能够提供Mac上打开窗口的列表,但在测试过程中我们发现的主要问题是CPU使用率。由于OSAScript在间隔期间运行,导致CPU使用率飙升了40%至50%,因此这个解决方案是不可接受的。
接下来呢?
在搜索后,我偶然发现了各种解决方案,比如:
- 使用Python Cocoa库(PyCocoa): 这提供了Python和Cocoa之间的接口,可以在JavaScript中使用。
- JsCocoa库: 我尝试集成了它,但没有成功。
- 自定义Flask服务器: 有一些帖子建议在浏览器中运行自定义Flask服务器,并从JavaScript中使用API。
所有这些方法要么太麻烦,要么会导致更高的延迟和增加的应用程序大小。
解决方案
使用SWIFT和child_process.exec()
: 最后,我决定使用Cocoa编写一个本机SWIFT脚本来识别进程窗口,并使用Xcode Playground进行测试。SWIFT脚本将输出一个JSON,可以轻松地进行消耗和解析。测试完成后,我将其编译为可执行文件,使用以下命令:
swiftc sample.swift -o sample
这为我提供了一个可执行文件sample
,可以使用./sample
来执行,并输出JSON。
接下来的步骤是将其打包到Electron中,并在child_process.exec()
方法中使用。为了打包,我将此文件放在一个文件夹中,假设为executable
,并更新了复制脚本以在打包代码时包含此文件的内容。一旦可执行文件存在于捆绑包中,我将可执行文件路径提供给[child_process.exec()](https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback)
命令。使用此命令的回调,我成功地能够检索SWIFT输出的JSON,以便在Electron应用程序中做出决定。
结果
这导致CPU开销由OSAScript引入的几乎40%降低到了几乎0%。
结论
- 为Mac等特定操作系统创建类似SWIFT的二进制文件
- 将此可执行文件打包到您的Electron应用程序中
- 使用
child_process
命令来执行打包的二进制可执行文件 - 在您的Electron应用程序中使用响应来做出决定!