fix: 修复 macOS 打包后的图标、spawn ENOENT 和 dylib 路径问题

- 新增 resources/icon.icns(由 public/logo.png 转换)
- package.json: 配置 build.icon 和 build.mac.icon 使用 .icns
- main.ts: BrowserWindow 图标改为平台感知,darwin 用 .icns,其他用 .ico
- keyServiceMac.ts: pgrep/ps/pkill 改用绝对路径,修复打包后 PATH 受限导致的 spawn ENOENT
This commit is contained in:
hicccc77
2026-03-14 18:45:12 +08:00
parent 8d5527990b
commit f47610b98a
4 changed files with 35 additions and 13 deletions

View File

@@ -258,7 +258,9 @@ function createWindow(options: { autoShow?: boolean } = {}) {
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
const win = new BrowserWindow({
width: 1400,
@@ -381,7 +383,9 @@ function createAgreementWindow() {
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
const isDark = nativeTheme.shouldUseDarkColors
@@ -431,7 +435,9 @@ function createSplashWindow(): BrowserWindow {
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
splashWindow = new BrowserWindow({
width: 760,
@@ -502,7 +508,9 @@ function createOnboardingWindow() {
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
onboardingWindow = new BrowserWindow({
width: 960,
@@ -548,7 +556,9 @@ function createVideoPlayerWindow(videoPath: string, videoWidth?: number, videoHe
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
// 获取屏幕尺寸
const { screen } = require('electron')
@@ -646,7 +656,9 @@ function createImageViewerWindow(imagePath: string, liveVideoPath?: string) {
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
const win = new BrowserWindow({
width: 900,
@@ -704,7 +716,9 @@ function createChatHistoryWindow(sessionId: string, messageId: number) {
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
// 根据系统主题设置窗口背景色
const isDark = nativeTheme.shouldUseDarkColors
@@ -779,7 +793,9 @@ function createSessionChatWindow(sessionId: string, options?: OpenSessionChatWin
const isDev = !!process.env.VITE_DEV_SERVER_URL
const iconPath = isDev
? join(__dirname, '../public/icon.ico')
: join(process.resourcesPath, 'icon.ico')
: (process.platform === 'darwin'
? join(process.resourcesPath, 'icon.icns')
: join(process.resourcesPath, 'icon.ico'))
const isDark = nativeTheme.shouldUseDarkColors

View File

@@ -178,14 +178,14 @@ export class KeyServiceMac {
try {
// 优先使用 pgrep避免 ps 的 comm 列被截断导致识别失败
try {
const { stdout } = await execFileAsync('pgrep', ['-x', 'WeChat'])
const { stdout } = await execFileAsync('/usr/bin/pgrep', ['-x', 'WeChat'])
const ids = stdout.split(/\r?\n/).map(s => parseInt(s.trim(), 10)).filter(n => Number.isFinite(n) && n > 0)
if (ids.length > 0) return Math.max(...ids)
} catch {
// ignore and fallback to ps
}
const { stdout } = await execFileAsync('ps', ['-A', '-o', 'pid,comm,command'])
const { stdout } = await execFileAsync('/bin/ps', ['-A', '-o', 'pid,comm,command'])
const lines = stdout.split('\n').slice(1)
const candidates: Array<{ pid: number; command: string }> = []
@@ -231,7 +231,7 @@ export class KeyServiceMac {
const pid = await this.getWeChatPid()
onStatus?.(`已找到微信进程 PID=${pid},正在定位目标函数...`, 0)
// 最佳努力清理同路径残留 helper普通权限
try { await execFileAsync('pkill', ['-f', helperPath], { timeout: 2000 }) } catch { }
try { await execFileAsync('/usr/bin/pkill', ['-f', helperPath], { timeout: 2000 }) } catch { }
return await new Promise<string>((resolve, reject) => {
// xkey_helper 参数协议helper <pid> [timeout_ms]

View File

@@ -79,7 +79,8 @@
"hardenedRuntime": false,
"gatekeeperAssess": false,
"entitlements": "electron/entitlements.mac.plist",
"entitlementsInherit": "electron/entitlements.mac.plist"
"entitlementsInherit": "electron/entitlements.mac.plist",
"icon": "resources/icon.icns"
},
"win": {
"target": [
@@ -120,6 +121,10 @@
{
"from": "electron/assets/wasm/",
"to": "assets/wasm/"
},
{
"from": "resources/icon.icns",
"to": "icon.icns"
}
],
"files": [
@@ -150,6 +155,7 @@
"from": "resources/vcruntime140_1.dll",
"to": "."
}
]
],
"icon": "resources/icon.icns"
}
}

BIN
resources/icon.icns Normal file

Binary file not shown.