开发SWHelper插件
SWHelper 允许编写 JavaScript 插件并在Render Thread 中运行。通过 IPC 通信,插件还可以请求主进程执行更高权限的操作。
核心概念
- 运行环境: 插件代码默认在管家的渲染进程中执行
- 通信机制: 使用
ipcRenderer与主进程通讯 - 鉴权密钥: 必须使用固定的
apiKey和channel才能通过主进程的校验(防止被屏蔽)
插件开发模板
点击展开示例插件模板
javascript
// 引入依赖 (利用 remote 模块调用系统 API)
const fs = require('electron').remote.require('fs');
const path = require('electron').remote.require('path');
const os = require('electron').remote.require('os');
const { ipcRenderer } = require('electron');
// 必须保留的固定常量,用于通过主进程校验
const apiKey = '7c5a1bae0eae82d8246c6cb70be0beb5';
const channel = 'channel-0a4efbc3';
// === 配置文件路径 ===
const configFilePath = path.join(os.homedir(), '.swhelper.config');
// === 核心功能封装 ===
/**
* 请求主进程执行 JS 代码 (Action: exec)
* @param {string} script 要在主进程执行的 JS 代码字符串
*/
function doEval(script) {
ipcRenderer.send(channel, {
apiKey: apiKey,
action: 'exec',
data: script
});
}
/**
* 请求注入代码 - 仅一次 (Action: i)
* @param {string} script 要注入的代码
*/
function doInjectOnce(script) {
ipcRenderer.send(channel, {
apiKey: apiKey,
action: 'i',
data: script
});
}
/**
* 请求注入代码 - 循环注入 (Action: j)
* 适用于页面刷新后需要重新生效的场景
* @param {string} script 要注入的代码
*/
function doInjectLoop(script) {
ipcRenderer.send(channel, {
apiKey: apiKey,
action: 'j',
data: script
});
}
// === 接收主进程的反馈 ===
ipcRenderer.on(channel + '-reply', (event, data) => {
const { ok, act, err, ret } = data;
if (!ok) {
console.error(`[Plugin] Action ${act} failed:`, err);
} else {
console.log(`[Plugin] Action ${act} success. Return:`, ret);
}
});
// === 配置读写辅助函数 ===
function loadConfig() {
try {
return JSON.parse(fs.readFileSync(configFilePath, 'utf-8'));
} catch (e) {
return {}; // 读取失败返回空对象
}
}
function saveConfig(newConfig) {
fs.writeFileSync(configFilePath, JSON.stringify(newConfig));
}
// ============================================
// 🚀 在此处编写你的插件逻辑
// ============================================
// 示例 1: 简单的弹窗 (在渲染进程执行)
alert("插件加载成功!Hello from SWHelper Plugin");
// 示例 2: 读取当前配置并打印
let currentConfig = loadConfig();
console.log("当前配置:", currentConfig);
// 示例 3: 让主进程弹出一个消息框 (跨进程执行)
// doEval("const { dialog } = require('electron'); dialog.showMessageBox({ message: '这是来自主进程的消息' });");API 详解
插件通过 ipcRenderer.send 发送指令对象,结构如下:
javascript
{
apiKey: '...', // 固定密钥
action: '...', // 指令动作
data: '...' // 具体的脚本内容
}可用 action:
exec: 直接在Main Thread 上下文中执行data中的 JS 代码,可调用大部分主进程 APIi: 将代码注入到所有窗口中执行一次,需插件自行判断是否为目标窗口j: 将代码加入循环队列,定期注入,这对于需要对抗页面刷新或重置逻辑的功能非常有用
安装插件
编写好 .js 文件后(例如 C:\Users\seewo\my-plugin.js),需要在配置文件的 plugins 字段中注册,参见:配置 (plugins)
Main Thread 插件注意事项
当你在配置文件中将插件的 loadType 设置为 mainThread 时,代码将直接在主进程中运行:
WARNING
在主进程注入的上下文中,默认无法直接使用 require 函数
你需要使用加载器特供的全局函数 global.___r_ 来加载模块,并使用特定的全局函数来向渲染进程注入代码
因此,如果你编写的是 mainThread 插件,请务必把所有的 require('xx') 替换为 global.___r_('xx')。
主进程专用 API 示例:
javascript
// === 获取模块 (替代 require) ===
// 在 mainThread 中必须这样引入模块
const electron = global.___r_('electron');
const fs = global.___r_('fs');
const path = global.___r_('path');
// === 向渲染进程注入代码 ===
// 1. 只注入一次 (相当于 Renderer 的 doInjectOnce)
// content: 要注入的 JS 字符串
global.___i_("console.log('Main process says hello once');");
// 2. 循环注入 (相当于 Renderer 的 doInjectLoop)
// content: 要注入的 JS 字符串 (每 5ms 尝试注入一次)
global.___j_("console.log('Main process is keeping this alive');");