清理电脑时发现一个痛点:国外的卸载工具(Geek、IObit)不识别国内软件的捆绑生态,一些'安全管家'类软件自己就带捆绑安装。于是用 C# + WebView2 自己动手实现了一个系统清理引擎(已开源,GPLv3),本文分享架构设计和踩坑记录。
本文分享架构设计和开发过程中踩的坑。
一、整体架构:C# 核心 + WebView2 UI
bash
┌─────────────────────────────────────┐
│ WebView2 前端 UI 层 │ HTML/CSS/JS 单文件,macOS 风格
├─────────────────────────────────────┤
│ AddHostObjectToScript 通信桥 │ JsBridge.cs,前后端互调
├─────────────────────────────────────┤
│ C# 核心业务层 │ 扫描/清理/备份/特征库,无UI依赖
├─────────────────────────────────────┤
│ 专业版插件层(闭源) │ 独立 dll 动态加载,双授权
└─────────────────────────────────────┘
为什么用混合架构?
-
核心逻辑用 C# 写,稳定、性能好、易调试
-
UI 用 Web 技术,迭代快、样式灵活、不用搞 GDI+ 自绘
-
前后端通过 JsBridge 解耦,UI 改版不影响核心代码
二、核心模块设计
1. Scanner.cs --- 扫描引擎
静态类,扫描启动项/服务/计划任务/浏览器主页/快捷方式/右键菜单/AppData 残留,按风险等级排序返回。
2. Cleaner.cs --- 强制卸载
实现完整清理链路:停服务 → 杀进程 → 删计划任务 → 重置浏览器 → 删文件 → MoveFileEx 重启延迟删除。
3. Signatures.cs --- 特征库
-
BadKeywords:200+ 捆绑软件特征
-
WhiteList:白名单(驱动/热键/系统组件)
-
PreinstalledList:品牌预装软件分类(建议卸载/可卸载/必须保留)
-
厂商识别:WMI 读 Manufacturer + Model,交叉验证,游戏本自动识别保留控制中心
4. BackupManager.cs --- 备份撤销
清理前备份文件和注册表,支持一键恢复,这是安全底线。驱动、热键、电源管理类软件直接进白名单不显示,游戏本控制中心自动识别保留。
三、前后端通信实现
WebView2 通过 AddHostObjectToScript 将 C# 对象暴露给前端,前端 JS 可以直接调用:
csharp
// JsBridge.cs - 前后端通信桥
[ComVisible(true)]
public class JsBridge
{
private readonly MainForm _mainForm;
public JsBridge(MainForm mainForm)
{
_mainForm = mainForm;
}
// 前端调用:扫描系统
public string Scan()
{
var results = Scanner.ScanAll();
return new JavaScriptSerializer().Serialize(results);
}
// 前端调用:清理选中项(按 Name+Path+Type 唯一匹配,避免索引错位)
public string Clean(string selectedItemsJson)
{
var items = ParseItems(selectedItemsJson);
var results = items.Select(item => Cleaner.Clean(item)).ToList();
return new JavaScriptSerializer().Serialize(results);
}
// 前端调用:撤销上次清理
public string Undo()
{
var result = BackupManager.RestoreLastBackup();
return new JavaScriptSerializer().Serialize(result);
}
}
前端 JS 直接调用:
javascript
const results = await window.chrome.webview.hostObjects.bridge.Scan();
四、双授权模式实现
免费版 GPLv3 开源,专业版商业闭源。关键设计:
-
专业版做成独立 dll 插件,通过接口动态加载
-
插件与核心通过公开 API 通信,尽量规避 GPL 传染范围
-
账号、付费、会员校验逻辑全部在插件里,不进开源代码
五、踩坑记录
1. WebView2 界面发糊
三个条件必须同时满足:app.manifest 开启 PerMonitorV2 DPI 感知 + WebView2 开启 GPU 硬件加速 + 强制 100% 缩放。少一个就会发糊。
2. 清理按索引匹配导致删错对象
早期用列表索引匹配,前端排序后索引错位就会删错。改成按 Name+Path+Type 唯一匹配,彻底解决。
3. Chrome 主页修改假清理
进程占用时改注册表不生效,增加进程占用检测和重试机制。
4. 高 DPI 下悬浮球跳动
GDI+ 自绘悬浮球,hover 时重绘导致位置偏移。最终方案是尺寸恒定、只更新数字角标,hover 不重绘主体。
六、项目信息
-
运行环境:.NET Framework 4.7.2 + WebView2
-
协议:GPLv3(免费版)
代码已开源(GPLv3),特征库误杀是当前最关注的问题,欢迎交流指正。