feat: 实现 Chromium 喜报应用
- 创建 Chromium/Electron 应用检测器 - 设计喜报风格的 UI 界面 - 添加应用列表查看功能 - 配置应用图标和颜色资源 - 添加 README 文档 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@ -86,11 +86,11 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 45F070D32E249A0700B1170B /* Build configuration list for PBXProject "ChromiumCertificate" */;
|
buildConfigurationList = 45F070D32E249A0700B1170B /* Build configuration list for PBXProject "ChromiumCertificate" */;
|
||||||
developmentRegion = en;
|
developmentRegion = "zh-Hans";
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
en,
|
|
||||||
Base,
|
Base,
|
||||||
|
"zh-Hans",
|
||||||
);
|
);
|
||||||
mainGroup = 45F070CF2E249A0700B1170B;
|
mainGroup = 45F070CF2E249A0700B1170B;
|
||||||
minimizedProjectReferenceProxies = 1;
|
minimizedProjectReferenceProxies = 1;
|
||||||
|
@ -252,8 +252,11 @@
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = U496NXS4BR;
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Chromium 喜报";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
@ -277,8 +280,11 @@
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = U496NXS4BR;
|
||||||
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = "Chromium 喜报";
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Bucket
|
||||||
|
uuid = "3F09E1D6-128F-4462-8367-9B46EA2D3AB6"
|
||||||
|
type = "1"
|
||||||
|
version = "2.0">
|
||||||
|
</Bucket>
|
12
ChromiumCertificate/Assets.xcassets/AnnouncementBg.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "bg.png",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
ChromiumCertificate/Assets.xcassets/AnnouncementBg.imageset/bg.png
vendored
Normal file
After Width: | Height: | Size: 1.2 MiB |
|
@ -1,51 +1,61 @@
|
||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_16x16.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "16x16"
|
"size" : "16x16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_16x16@2x.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "16x16"
|
"size" : "16x16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_32x32.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "32x32"
|
"size" : "32x32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_32x32@2x.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "32x32"
|
"size" : "32x32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_128x128.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "128x128"
|
"size" : "128x128"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_128x128@2x.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "128x128"
|
"size" : "128x128"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_256x256.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "256x256"
|
"size" : "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_256x256@2x.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "256x256"
|
"size" : "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_512x512.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "1x",
|
"scale" : "1x",
|
||||||
"size" : "512x512"
|
"size" : "512x512"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"filename" : "icon_512x512@2x.png",
|
||||||
"idiom" : "mac",
|
"idiom" : "mac",
|
||||||
"scale" : "2x",
|
"scale" : "2x",
|
||||||
"size" : "512x512"
|
"size" : "512x512"
|
||||||
|
|
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 759 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 238 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 238 KiB |
After Width: | Height: | Size: 1.0 MiB |
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x00",
|
||||||
|
"green" : "0xFF",
|
||||||
|
"red" : "0xFE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x00",
|
||||||
|
"green" : "0x00",
|
||||||
|
"red" : "0xD0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
56
ChromiumCertificate/ChromiumBasedAppListView.swift
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
//
|
||||||
|
// ChromiumBasedAppListView.swift
|
||||||
|
// ChromiumCertificate
|
||||||
|
//
|
||||||
|
// Created by Astrian Zheng on 14/7/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ChromiumBasedAppListView: View {
|
||||||
|
@Binding var isPresented: Bool
|
||||||
|
|
||||||
|
let chromiumAppsList: [ChromiumApp] = ChromiumDetector.detectChromiumApps()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
HStack {
|
||||||
|
Text("所有带有 Chromium 的应用程序").font(.headline)
|
||||||
|
Spacer()
|
||||||
|
Button {
|
||||||
|
self.isPresented.toggle()
|
||||||
|
} label: {
|
||||||
|
Text("关闭")
|
||||||
|
}
|
||||||
|
}.padding()
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
if chromiumAppsList.isEmpty {
|
||||||
|
Text("你的电脑没有遭受 Chromium 的荼毒!望君继续努力。").multilineTextAlignment(.center).padding()
|
||||||
|
}
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
ForEach(Array(chromiumAppsList.enumerated()), id: \.element.id) { index, chromiumApp in
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text(chromiumApp.name).bold()
|
||||||
|
Text(chromiumApp.path)
|
||||||
|
.font(.system(.caption, design: .monospaced))
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if index < chromiumAppsList.count - 1 {
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.padding()
|
||||||
|
}
|
||||||
|
}.frame(width: 300).frame(minHeight: 0, maxHeight: 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
ChromiumBasedAppListView(isPresented: .constant(true))
|
||||||
|
}
|
|
@ -13,5 +13,8 @@ struct ChromiumCertificateApp: App {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
ContentView()
|
||||||
}
|
}
|
||||||
|
.windowResizability(.contentSize)
|
||||||
|
.defaultSize(width: 640, height: 480)
|
||||||
|
.windowStyle(.hiddenTitleBar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
158
ChromiumCertificate/ChromiumDetector.swift
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
//
|
||||||
|
// ChromiumDetector.swift
|
||||||
|
// ChromiumCertificate
|
||||||
|
//
|
||||||
|
// Created by Astrian Zheng on 14/7/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct ChromiumApp: Identifiable {
|
||||||
|
let id = UUID()
|
||||||
|
let name: String
|
||||||
|
let type: ChromiumType
|
||||||
|
let path: String
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ChromiumType: String, CaseIterable {
|
||||||
|
case electron = "Electron"
|
||||||
|
case chromium = "Chromium"
|
||||||
|
case chromiumLibrary = "Chromium库"
|
||||||
|
case electronIdentifier = "Electron标识"
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChromiumDetector {
|
||||||
|
|
||||||
|
static func detectChromiumApps() -> [ChromiumApp] {
|
||||||
|
var chromiumApps: [ChromiumApp] = []
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
let applicationsURL = URL(fileURLWithPath: "/Applications")
|
||||||
|
|
||||||
|
do {
|
||||||
|
let appURLs = try fileManager.contentsOfDirectory(
|
||||||
|
at: applicationsURL,
|
||||||
|
includingPropertiesForKeys: [.isDirectoryKey],
|
||||||
|
options: [.skipsHiddenFiles]
|
||||||
|
)
|
||||||
|
|
||||||
|
for appURL in appURLs {
|
||||||
|
if appURL.pathExtension == "app" {
|
||||||
|
if let chromiumApp = analyzeApp(at: appURL) {
|
||||||
|
chromiumApps.append(chromiumApp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("Error reading applications directory: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return chromiumApps.sorted { $0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func analyzeApp(at appURL: URL) -> ChromiumApp? {
|
||||||
|
let appName = appURL.deletingPathExtension().lastPathComponent
|
||||||
|
let contentsURL = appURL.appendingPathComponent("Contents")
|
||||||
|
let frameworksURL = contentsURL.appendingPathComponent("Frameworks")
|
||||||
|
let infoPlistURL = contentsURL.appendingPathComponent("Info.plist")
|
||||||
|
|
||||||
|
// 检查 Electron Framework
|
||||||
|
let electronFrameworkURL = frameworksURL.appendingPathComponent("Electron Framework.framework")
|
||||||
|
if FileManager.default.fileExists(atPath: electronFrameworkURL.path) {
|
||||||
|
return ChromiumApp(name: appName, type: .electron, path: appURL.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 Chromium 相关框架
|
||||||
|
if hasChromiumFrameworks(at: frameworksURL) {
|
||||||
|
return ChromiumApp(name: appName, type: .chromium, path: appURL.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查可执行文件是否链接到 Chromium 库
|
||||||
|
let executableURL = contentsURL.appendingPathComponent("MacOS").appendingPathComponent(appName)
|
||||||
|
if hasChromiumLibraries(executablePath: executableURL.path) {
|
||||||
|
return ChromiumApp(name: appName, type: .chromiumLibrary, path: appURL.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 Info.plist 中的 Electron 标识
|
||||||
|
if hasElectronIdentifier(infoPlistPath: infoPlistURL.path) {
|
||||||
|
return ChromiumApp(name: appName, type: .electronIdentifier, path: appURL.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func hasChromiumFrameworks(at frameworksURL: URL) -> Bool {
|
||||||
|
do {
|
||||||
|
let frameworks = try FileManager.default.contentsOfDirectory(atPath: frameworksURL.path)
|
||||||
|
return frameworks.contains { $0.localizedCaseInsensitiveContains("chromium") }
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func hasChromiumLibraries(executablePath: String) -> Bool {
|
||||||
|
guard FileManager.default.fileExists(atPath: executablePath) else { return false }
|
||||||
|
|
||||||
|
let task = Process()
|
||||||
|
task.launchPath = "/usr/bin/otool"
|
||||||
|
task.arguments = ["-L", executablePath]
|
||||||
|
|
||||||
|
let pipe = Pipe()
|
||||||
|
task.standardOutput = pipe
|
||||||
|
task.standardError = Pipe()
|
||||||
|
|
||||||
|
do {
|
||||||
|
try task.run()
|
||||||
|
task.waitUntilExit()
|
||||||
|
|
||||||
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
let output = String(data: data, encoding: .utf8) ?? ""
|
||||||
|
|
||||||
|
return output.localizedCaseInsensitiveContains("chromium")
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func hasElectronIdentifier(infoPlistPath: String) -> Bool {
|
||||||
|
guard FileManager.default.fileExists(atPath: infoPlistPath) else { return false }
|
||||||
|
|
||||||
|
let task = Process()
|
||||||
|
task.launchPath = "/usr/libexec/PlistBuddy"
|
||||||
|
task.arguments = ["-c", "Print CFBundleIdentifier", infoPlistPath]
|
||||||
|
|
||||||
|
let pipe = Pipe()
|
||||||
|
task.standardOutput = pipe
|
||||||
|
task.standardError = Pipe()
|
||||||
|
|
||||||
|
do {
|
||||||
|
try task.run()
|
||||||
|
task.waitUntilExit()
|
||||||
|
|
||||||
|
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
let output = String(data: data, encoding: .utf8) ?? ""
|
||||||
|
|
||||||
|
return output.localizedCaseInsensitiveContains("electron")
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func getChromiumAppCount() -> Int {
|
||||||
|
return detectChromiumApps().count
|
||||||
|
}
|
||||||
|
|
||||||
|
static func getChromiumAppNames() -> [String] {
|
||||||
|
return detectChromiumApps().map { $0.name }
|
||||||
|
}
|
||||||
|
|
||||||
|
static func getChromiumAppsByType() -> [ChromiumType: [ChromiumApp]] {
|
||||||
|
let apps = detectChromiumApps()
|
||||||
|
var groupedApps: [ChromiumType: [ChromiumApp]] = [:]
|
||||||
|
|
||||||
|
for type in ChromiumType.allCases {
|
||||||
|
groupedApps[type] = apps.filter { $0.type == type }
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupedApps
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,15 +7,54 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ContentView: View {
|
struct StrokeText: ViewModifier {
|
||||||
var body: some View {
|
var strokeSize: CGFloat = 1
|
||||||
VStack {
|
var strokeColor: Color = .black
|
||||||
Image(systemName: "globe")
|
|
||||||
.imageScale(.large)
|
func body(content: Content) -> some View {
|
||||||
.foregroundStyle(.tint)
|
content
|
||||||
Text("Hello, world!")
|
.background(
|
||||||
|
Rectangle()
|
||||||
|
.foregroundColor(strokeColor)
|
||||||
|
.mask(content)
|
||||||
|
.blur(radius: strokeSize)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.padding()
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func stroke(color: Color = .black, width: CGFloat = 1) -> some View {
|
||||||
|
modifier(StrokeText(strokeSize: width, strokeColor: color))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ContentView: View {
|
||||||
|
let count = ChromiumDetector.getChromiumAppCount()
|
||||||
|
|
||||||
|
@State private var presentSheet: Bool = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
Image("AnnouncementBg").resizable().frame(width: 640, height: 480)
|
||||||
|
VStack {
|
||||||
|
Text(count != 0 ? "这台 Mac 上一共有 \(count) 个 Chromium" : "这台 Mac 一个 Chromium 都没有!")
|
||||||
|
.font(.system(size: 35, weight: .semibold))
|
||||||
|
.foregroundColor(Color("TextColor"))
|
||||||
|
.stroke(color: Color("TextBorderColor"), width: 5)
|
||||||
|
|
||||||
|
Button {
|
||||||
|
self.presentSheet.toggle()
|
||||||
|
} label: {
|
||||||
|
Text("查看列表").font(.system(size: 20)).padding(.horizontal).padding(.vertical, 8)
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
|
.tint(.red)
|
||||||
|
.sheet(isPresented: self.$presentSheet) {
|
||||||
|
ChromiumBasedAppListView(isPresented: self.$presentSheet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(width: 640, height: 420)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
67
README.md
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# 🎉 Chromium 喜报 - 您的 Mac 健康检测工具
|
||||||
|
|
||||||
|
> 热烈祝贺您的 Mac 电脑成功安装了 N 个基于 Chromium 的应用程序!
|
||||||
|
|
||||||
|
## 🏆 这是什么?
|
||||||
|
|
||||||
|
一个能够帮您统计 Mac 上到底有多少个 Chromium/Electron 应用的"健康检测"工具。运行后会以喜报的形式展示检测结果,让您充分认识到自己的电脑已经被 Chromium 占领到何种程度。
|
||||||
|
|
||||||
|
## 🎯 功能特色
|
||||||
|
|
||||||
|
- **精准检测**:扫描您的 /Applications 目录,识别所有基于 Chromium/Electron 的应用
|
||||||
|
- **喜报展示**:采用传统喜报设计,红底金字,喜气洋洋
|
||||||
|
- **详细列表**:查看具体是哪些应用在"助力"您的内存消耗
|
||||||
|
- **一键查看**:简洁明了的界面,让您快速了解"战况"
|
||||||
|
|
||||||
|
## 📸 效果预览
|
||||||
|
|
||||||
|
想象一下,打开应用后看到:
|
||||||
|
|
||||||
|
```
|
||||||
|
🎊 喜报 🎊
|
||||||
|
这台 Mac 上一共有 23 个 Chromium
|
||||||
|
[查看列表]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🤔 为什么要做这个?
|
||||||
|
|
||||||
|
在这个美好的时代,我们的电脑里充斥着各种 Electron 应用:
|
||||||
|
- VS Code(写代码)
|
||||||
|
- Slack(聊天)
|
||||||
|
- Discord(游戏聊天)
|
||||||
|
- Notion(笔记)
|
||||||
|
- Figma(设计)
|
||||||
|
- ...
|
||||||
|
|
||||||
|
每个都是独立的 Chromium 实例,每个都在努力地消耗您的内存。是时候让我们正视这个"喜人"的现实了!
|
||||||
|
|
||||||
|
## 🚀 使用方法
|
||||||
|
|
||||||
|
1. 下载 DMG 文件
|
||||||
|
2. 拖拽到 Applications 文件夹
|
||||||
|
3. 运行应用
|
||||||
|
4. 欣赏您的"成就"
|
||||||
|
5. 分享到朋友圈,让大家一起"喜悦"
|
||||||
|
|
||||||
|
## 💭 检测原理
|
||||||
|
|
||||||
|
应用会检查以下特征来识别 Chromium/Electron 应用:
|
||||||
|
- Electron Framework 存在
|
||||||
|
- Chromium 相关框架
|
||||||
|
- 动态链接库中的 Chromium 依赖
|
||||||
|
- Info.plist 中的 Electron 标识
|
||||||
|
|
||||||
|
## 🎈 温馨提示
|
||||||
|
|
||||||
|
- 检测结果仅供娱乐参考
|
||||||
|
- Chromium 应用并非都是坏事(真的吗?)
|
||||||
|
- 如果数字太大,请保持冷静
|
||||||
|
- 建议定期检测,见证数字的增长
|
||||||
|
|
||||||
|
## 📝 开源协议
|
||||||
|
|
||||||
|
本项目采用 MIT 协议开源,欢迎 fork、star、提 issue。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*记住:每一个 Chromium 应用都是对您 16GB 内存的考验!*
|