学习备份(仅用于个人记录)
结论:用不了,但是可以将插件变更为自研插件系统
Electron打包的软件 ctrl+shift+I和F12调出的系统不同,从控制台打印typeof require 结果不一样
(不确定是否是偶发)
即使你没有 Electron 软件 A 的源码 (即只有打包后的 .exe 或 app.asar),只要满足以下任一条件,依然可以实现"自研 JS 插件系统":
- ✅ 你能解包并重新打包该软件(例如用于内部部署或二次开发)
- ✅ 该软件的 渲染进程启用了
nodeIntegration: true(可通过 DevTools 控制台验证) - ✅ 你可以注入外部脚本(如通过启动参数、环境变量、或劫持 preload)
下面我将给出 无需原始源码、仅基于已打包 Electron 应用 的 完整插件系统实现方案,分为两种场景:
🎯 场景一:你能修改/重打包软件(推荐)
步骤 1:解包 ASAR
bash
npx asar extract app.asar app-unpacked
步骤 2:在主进程添加插件加载逻辑
编辑 app-unpacked/main.js(或你的主入口文件):
js
// ====== 新增:插件系统 ======
function loadExternalPlugins(win) {
const fs = require('fs');
const path = require('path');
const pluginDir = path.join(app.getPath('userData'), 'plugins');
console.log('pluginDir',pluginDir);
if (!fs.existsSync(pluginDir)) return;
const files = fs.readdirSync(pluginDir).filter(f => f.endsWith('.plugin.js'));
for (const file of files) {
try {
// 使用 require 动态加载插件(主进程执行)
const pluginPath = path.join(pluginDir, file);
delete require.cache[require.resolve(pluginPath)]; // 避免缓存
const plugin = require(pluginPath);
if (typeof plugin.activate === 'function') {
plugin.activate(win); // 插件可操作 BrowserWindow
console.log(`✅ Loaded plugin: ${file}`);
}
} catch (err) {
console.error(`❌ Failed to load plugin ${file}:`, err);
}
}
}
在创建窗口后调用:
js
createWindow();
loadExternalPlugins(win); // ← 新增这行
步骤 3:打包回去
bash
npx asar pack app-unpacked app.asar
步骤 4:用户如何安装插件?
让用户在 %APPDATA%/<YourApp>/plugins/(Windows)下放入 .plugin.js 文件,例如:
js
// hello.plugin.js
module.exports = {
activate: (win) => {
// 向渲染进程注入代码
win.webContents.executeJavaScript(`
console.log('Hello from external plugin!');
window.EXTERNAL_PLUGIN_LOADED = true;
`);
}
};
✅ 优点:完全可控、安全(运行在主进程)、无需网络
🎯 场景二:你不能改主进程(只能用控制台/渲染进程)
前提:渲染进程必须能访问 Node.js(即
nodeIntegration: true或通过 preload 暴露了require)
方法:通过 DevTools Console 动态加载远程/本地插件
步骤 1:确认是否支持 Node.js
在应用的 DevTools Console 中运行:
js
typeof require // 如果返回 "function",说明可用
步骤 2:加载本地插件(用户放一个 JS 文件)
js
// 在 DevTools Console 中执行(假设插件在桌面)
(async () => {
const fs = require('fs');
const path = require('path');
const pluginPath = path.join(require('os').homedir(), 'Desktop', 'my-plugin.js');
const code = fs.readFileSync(pluginPath, 'utf8');
eval(code); // 或用 Function() 更安全
})();
步骤 3:插件内容示例(my-plugin.js)
js
// my-plugin.js
(function () {
console.log('🚀 自研插件已注入!');
// 修改页面行为
document.body.style.border = '5px solid red';
// 添加按钮
const btn = document.createElement('button');
btn.innerText = 'Plugin Action';
btn.onclick = () => alert('Hello from plugin!');
document.body.appendChild(btn);
// 暴露全局标志
window.MY_PLUGIN_ACTIVE = true;
})();
⚠️ 注意:这种方式每次重启都会失效,适合临时调试。
🛡 安全建议(如果你分发插件)
- 不要直接
eval()用户代码 → 改用vm模块沙箱(主进程) - 校验插件签名或哈希
- 限制插件权限(如禁止
require('child_process'))
🔧 高级:自动加载插件(无需手动执行 Console)
如果软件启动时会加载某个本地 HTML/JS(比如 index.html),你可以:
-
解包 ASAR
-
修改
index.html,在<head>中加入:html<script src="../plugins/loader.js"></script> -
创建
resources/plugins/loader.js:js// 自动加载 plugins 目录下的所有 .js const fs = require('fs'); const path = require('path'); const pluginDir = path.join(require('electron').remote.app.getPath('userData'), 'plugins'); if (fs.existsSync(pluginDir)) { fs.readdirSync(pluginDir) .filter(f => f.endsWith('.js')) .forEach(f => { const code = fs.readFileSync(path.join(pluginDir, f), 'utf8'); new Function(code)(); // 沙箱执行 }); }
✅ 这样用户只需把
.js放入 plugins 文件夹,启动即生效!
✅ 总结:无源码也能加插件的方案
| 条件 | 方案 | 持久性 | 安全性 |
|---|---|---|---|
| 能重打包 ASAR | 主进程动态 require 插件 |
✅ 永久 | ✅ 高(可控) |
不能改主进程,但 nodeIntegration=true |
DevTools 手动 eval 插件 |
❌ 临时 | ⚠️ 低 |
| 能改 ASAR 中的 HTML | 注入 loader.js 自动加载 |
✅ 永久 | ✅ 中(可用 Function 沙箱) |
💡 最终建议
即使没有源码,解包 → 修改主进程/HTML → 重打包 是最稳定、最接近"原生插件系统"的方式。
Electron 应用天生就是"可破解可扩展"的,这是它的特性,不是漏洞。
如果你需要,我可以提供:
- 一键解包/打包脚本
- 插件加载器模板
- 沙箱执行示例
只需告诉我你的操作系统和软件是否允许重打包 😊