Files
CodePilot/electron/preload.ts
T
7418andClaude Sonnet 4.6 0e38e4460e feat: macOS Developer ID 签名 + notarization + 原生热更新
签名 & 公证:
- build/entitlements.mac.plist, build/entitlements.mac.inherit.plist — Electron hardened runtime 所需权限(JIT、unsigned memory、disable library validation)
- electron-builder.yml — 启用 hardenedRuntime、entitlements、notarize: true
- scripts/after-sign.js — 环境变量 + codesign -d 双重检测,有 Developer ID 时跳过 ad-hoc;无证书时 fallback ad-hoc
- .github/workflows/build.yml — 映射签名 secrets(MAC_CERT_P12_BASE64 等),验证步骤断言 Developer ID Authority + TeamIdentifier,遍历双架构 .app

原生热更新:
- electron/updater.ts — 从 no-op 重写为完整 electron-updater 实现(autoDownload:false, IPC handlers, 启动 10s 延迟检查)
- electron/preload.ts — 恢复 updater IPC bridge
- src/components/layout/AppShell.tsx — 运行时检测 native updater,useEffect 监听 updater:status 事件,native 优先 + browser fallback

其他:
- README_CN.md — 更新自动更新功能描述
- package.json — 版本号升至 0.23.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 00:46:51 +08:00

42 lines
1.7 KiB
TypeScript

// eslint-disable-next-line @typescript-eslint/no-require-imports
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
versions: {
electron: process.versions.electron,
node: process.versions.node,
chrome: process.versions.chrome,
},
shell: {
openPath: (folderPath: string) => ipcRenderer.invoke('shell:open-path', folderPath),
},
dialog: {
openFolder: (options?: { defaultPath?: string; title?: string }) =>
ipcRenderer.invoke('dialog:open-folder', options),
},
install: {
checkPrerequisites: () => ipcRenderer.invoke('install:check-prerequisites'),
start: (options?: { includeNode?: boolean }) => ipcRenderer.invoke('install:start', options),
cancel: () => ipcRenderer.invoke('install:cancel'),
getLogs: () => ipcRenderer.invoke('install:get-logs'),
onProgress: (callback: (data: unknown) => void) => {
const listener = (_event: unknown, data: unknown) => callback(data);
ipcRenderer.on('install:progress', listener);
return () => { ipcRenderer.removeListener('install:progress', listener); };
},
},
bridge: {
isActive: () => ipcRenderer.invoke('bridge:is-active'),
},
updater: {
checkForUpdates: () => ipcRenderer.invoke('updater:check'),
downloadUpdate: () => ipcRenderer.invoke('updater:download'),
quitAndInstall: () => ipcRenderer.invoke('updater:quit-and-install'),
onStatus: (callback: (data: unknown) => void) => {
const listener = (_event: unknown, data: unknown) => callback(data);
ipcRenderer.on('updater:status', listener);
return () => { ipcRenderer.removeListener('updater:status', listener); };
},
},
});