Screenpipe SDK 的 Electron 集成:构建一个可运行的最小屏幕录制桌面应用
发布时间:2026/9/13 11:54:41 作者:尧图编辑部 阅读量:1,286

Screenpipe SDK 的 Electron 集成构建一个可运行的最小屏幕录制桌面应用【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe本指南以screenpipe/sdk官方 Electron 示例应用packages/sdk/examples/electron-app为主线完整讲解如何从零构建一个嵌入原生屏幕录制能力的 Electron 应用从权限申请、MP4 录制、实时预览到文件定位并深入解析其主进程 IPC、preload 桥接、paired-capture 数据管线与打包发布注意事项。读完本文你将掌握在 Electron 主进程中安全加载原生.node模块、通过 context-isolated preload 暴露录制 API、并以最小代码量实现“开始录制 → 轮询状态 → 停止并显示文件”完整闭环的工程方法。背景Electron 为什么需要这套 SDK 辅助层screenpipe/sdkpackages/sdk/README.md是 screenpipe 项目对外提供的商业屏幕录制 SDK把原生 screenpipe 栈的采集原语封装成可供 Electron、Swift、Tauri、Node 应用直接调用的 API。SDK 表面上覆盖四类宿主其中 Electron 是较为“挑剔”的一类原生.node预编译模块native addon只能在主进程中加载渲染进程无法直接require渲染进程默认开启contextIsolation且关闭nodeIntegration任何对 Node 能力的访问都必须经过 preload 桥接录制过程中需要同时处理系统权限macOS 屏幕录制、麦克风、辅助功能、文件写入路径、窗口焦点监控等多个来源的异步事件。Electron 示例应用的目标就是演示如何用官方提供的screenpipe/sdk/electron辅助层把这些约束一次解决。它位于 packages/sdk/examples/electron-app同仓库还提供了 Swift 示例 与 Tauri 示例 供横向参考。示例应用能力一览按官方文档说明这个最小 Electron 应用演示了四项核心能力请求系统权限点击按钮触发 macOS 屏幕录制权限弹窗麦克风权限随平台而定开始录制将屏幕录制写入 Videos 目录下的 MP4 文件停止录制并在文件管理器中显示结束录制、刷新文件并调用系统文件管理器定位实时轮询状态每秒拉取 JPEG 预览、帧数、文件大小、麦克风电平和当前焦点应用。从源码看这四项能力分别对应主进程main.js、preloadpreload.js、渲染进程renderer.js三个文件的分工下面逐一拆解。运行环境准备与启动步骤第一步构建 SDK 预编译产物示例应用通过screenpipe/sdk: file:../..见 package.json直接引用仓库内的 SDK 包因此必须先构建原生 addon。官方推荐在仓库根目录执行 release 构建cd /path/to/screenpipe/packages/sdk bun install bun run build # release 构建 —— 真实性能场景推荐为什么强调 release 构建bun run build:debug会产出调试版原生模块其 PNG 编码器比 release 慢约 500 倍。用 debug 构建运行示例时录制的 MP4 可能是 0 字节或极短原因就在这里。第二步安装依赖并启动示例cd examples/electron-app npm install # 拉取 ElectronSDK 通过 file:../.. 本地引入 npm start首次启动后依次点击1. Request permissionsmacOS 会弹出屏幕录制授权需授予→2. Start recording→3. Stop即可完成一次完整录制闭环。录制文件默认落在app.getPath(videos)macOS 上解析为~/MoviesWindows 上为~/Videos是一个可靠、用户可访问的位置。包管理器说明SDK 构建与示例安装分别使用bun与npm这是官方文档与 package.json 中固定下来的组合按此执行即可。主进程用 registerScreenpipeIpc 一次性注册全部 IPC示例的主进程入口 main.js 是整个集成的核心。它只做了两件关键事情创建一个安全的BrowserWindow然后调用registerScreenpipeIpc()把录制能力挂到 IPC 上。安全窗口配置const win new BrowserWindow({ width: 720, height: 720, resizable: true, title: Screenpipe SDK — Example, webPreferences: { preload: path.join(__dirname, preload.js), contextIsolation: true, nodeIntegration: false, sandbox: false, // 见下方说明 }, });源码中有一段值得注意的注释Electron 20 在nodeIntegration: false时默认将渲染进程沙箱化sandboxed而沙箱会阻止 preload 脚本require()任意 npm 模块——这意味着require(screenpipe/sdk/electron/preload)会静默失败window.api永远不会被暴露渲染进程点击按钮时就会报Cannot read properties of undefined (reading permissions)。示例应用为了保持 preload 最简、直接导入 SDK 辅助函数选择关闭沙箱。对生产应用官方建议保留沙箱改用 esbuild/webpack 把 preload 打包使 SDK 代码内联、不再依赖外部require。registerScreenpipeIpc 注册的 IPC 通道registerScreenpipeIpc()由 packages/sdk/electron/index.js 提供它在内部创建一个createScreenpipeSession会话来自screenpipe/sdk/session并把以下通道注册到ipcMain.handle通道常量IPC channel 名称对应会话方法说明permissionsscreenpipe:permissionssession.permissions(args)请求/检查系统权限startscreenpipe:startsession.start(args)开始录制stopscreenpipe:stopsession.stop()停止录制并刷新 MP4statusscreenpipe:statussession.status()查询当前状态snapshotscreenpipe:snapshotsession.snapshot()返回 JPEG 预览 统计revealscreenpipe:revealsession.reveal(file)在文件管理器中显示文件eventscreenpipe:event主进程 → 渲染进程广播会话事件单向推送示例主进程的调用方式const { registerScreenpipeIpc } require(screenpipe/sdk/electron); screenpipe registerScreenpipeIpc({ ipcMain, app, shell, sessionOptions: { outputDir: () app.getPath(videos), filenamePrefix: screenpipe-electron, recorderOptions: { dataDir, // paired-capture 数据目录见下文 }, }, });从 electron/index.js 的实现看该函数还做了几件对生产有意义的事事件扇出broadcast它遍历SCREENPIPE_EVENTS把每个会话事件如recording_started、recording_paused通过webContents.send(channels.event, { event, data })广播给所有存活的渲染窗口也支持注入自定义broadcast函数便于无头测试自动清理返回的dispose()会移除所有 IPC handler、解绑事件监听并销毁会话同时监听app.on(before-quit)在退出前自动session.dispose()依赖可注入ipcMain、app、shell、BrowserWindow均支持显式传入这正是 smoke 测试能以纯 Node 桩stub运行的原因。paired-capture 数据管线源码中的进阶细节示例main.js还演示了 SDK 的新版 paired-capture 管线在app.getPath(userData)下创建screenpipe-data目录把recorderOptions.dataDir传给会话。启动后会以事件驱动方式click / typing_pause / app_switch / clipboard / visual_change / idle 等触发器在 SQLite 中为每次触发写入一帧记录和 JPEG 快照与 MP4 并行落盘。该 SQLite 使用与 screenpipe CLI 相同的 schema因此 SDK 录制的会话可以直接被现有screenpipe-jsHTTP 客户端或任何读取 CLI 数据库的工具查询。日志会打印[screenpipe-electron] paired-capture DB at userData/screenpipe-data/db.sqlite同时多显示器录制默认开启——只要不设置monitorId/mp4Monitors/pairedMonitors每个连接的显示器都会各自得到一个自动加后缀-monitor-{id}的 MP4 和对应的逐显示器行流。Preload 桥接contextIsolation 下的安全 APIpreload 脚本 preload.js 只有三行有效代码const { exposeScreenpipeApi } require(screenpipe/sdk/electron/preload); exposeScreenpipeApi({ name: api });exposeScreenpipeApi()实现在 packages/sdk/electron/preload.js它调用contextBridge.exposeInMainWorld(name, api)把一组调用ipcRenderer.invoke()的 Promise 方法暴露为window.apipermissions(options)、start(options)、stop()、status()、snapshot()、reveal(file)onEvent(callback, opts)订阅主进程广播的会话事件支持{ filter: [app_switched, ...] }白名单过滤过滤发生在 preload 内渲染进程监听器不会收到无关事件返回取消订阅函数。这样渲染进程在完全不开启 Node 集成的前提下也能以类型安全、context-isolated 的方式调用所有录制能力——这也是示例 README 强调的“First-class IPC helper Preload bridge”组合的意义所在。渲染进程每秒轮询的快照刷新循环渲染端 renderer.js 是纯 DOM 逻辑没有引入任何框架重点演示了window.api的用法权限流程点击 Permissions 后调用window.api.permissions()若screen授权成功立即启动 1 秒一轮的refreshSnapshot()轮询——即使尚未开始录制预览区也会变成“实时取景器”录制流程window.api.start()返回{ output }window.api.stop()返回{ output, frames, bytes }停止后渲染进程在状态栏插入“Reveal in Finder/Explorer”链接点击调用window.api.reveal(output)快照渲染window.api.snapshot()返回{ jpeg, frames, bytes, audioLevel, focusedApp }。主进程传回的Buffer在 ESM Electron 下到达渲染进程是Uint8Array需要用new Blob([jpeg], { type: image/jpeg })转成 object URL 后赋给img并记得在 onload 后URL.revokeObjectURL释放指标可视化audioLevel是[0, 1]的平滑麦克风 RMS 电平源码注释说明真实人声 RMS 约在 0.02–0.2 线性区间因此用Math.sqrt()映射到 0.15–0.45 的填充区间以增强视觉可读性focusedApp则展示当前焦点应用的名称、窗口标题与浏览器 URL。无头冒烟测试smoke.mjs 的桩驱动验证示例仓库还带了两套无头验证这是确认“集成本身正确”的最快路径对 CI 尤其有用npm --prefix examples/electron-app run smoke→ smoke.mjs不启动真实 Electron而是用内存桩模拟ipcMain/app/shell和一个SmokeRecorder走完permissions → start → snapshot → reveal → stop全生命周期断言npm --prefix examples/electron-app run smoke:app→smoke-app.mjs启动真实 Electron 应用并注入SCREENPIPE_ELECTRON_EXAMPLE_SMOKE1环境变量主进程runSmoke()用桩native模块见 main.js执行会话生命周期后自动退出。这两套机制之所以可行正是依赖registerScreenpipeIpc的依赖注入设计——nativeRecorderrequestPermissions、outputDir、filenamePrefix都可以在sessionOptions中替换测试与真实运行共用同一套 IPC 注册代码。Troubleshooting 官方排错清单示例 README 给出了三个高频问题的成因与解法结合源码可以进一步解释其根因Error: Cannot find module screenpipe/sdkat launch未先构建 SDK。回到packages/sdk目录执行bun run build后再启动示例。录制开始但 MP4 是 0 字节或极短处于 debug 构建bun run build:debugPNG 编码器慢约 500 倍。改用 release 构建bun run build即可。权限弹窗始终不出现macOS 会按 bundle identifier 缓存授权决定。如果之前运行过本示例并点了拒绝需要到 System Settings → Privacy Security → Screen Recording把 Electron 从列表移除后重新启动应用。生产发布前必须补齐的事项示例未覆盖示例 README 明确列出了三个“本示例不覆盖”的生产级问题集成到真实产品时务必处理代码签名Code Signing打包 SDK 的生产应用必须在签名脚本中包含.node文件。对electron-builder需要把dist/**/*.node加入extraResources并在 macOS 上用afterSign钩子完成公证notarization。本示例是未签名状态npm start运行没问题但不能直接发布安装包Packaging示例只能npm start。要产出.dmg或.exe需要自行补充electron-builder配置并接入签名/公证流程音频AudioSDK v0.1.0 录制的 MP4 是无声的音频支持计划在 v0.2.x 加入SDK 的microphone、systemAudio选项目前仅为向前兼容而接受。从 Electron 示例延伸到 SDK 其他表面如果你理解了 Electron 示例的“权限 → 会话 → 快照 → 事件”抽象会发现它与其他 SDK 表面共享同一套设计Node 直接new Recorder(...)requestPermissions()含ignoredWindows/ignoredUrls隐私过滤与filterStatus()/setFilters()运行时开关见 packages/sdk/README.md 的 Quick StartSwift 通过ScreenpipeClient.Configuration封装Tauri 则在 Rust 插件层做原生上报、无需配置 CSP。三个示例的启动与 smoke 命令汇总在 packages/sdk/examples/README.md完整集成注意事项在 packages/sdk/docs/integration.md。结语这个 Electron 示例的价值在于它把“原生采集能力嵌入 Electron 应用”这条容易踩坑的路径压缩到了最小闭环主进程registerScreenpipeIpc负责所有原生与 IPC 负担preload 一行暴露安全桥接渲染进程只管轮询与渲染。在此基础上paired-capture SQLite 管线让它天然可以被现有查询工具检索smoke 测试让它可以在 CI 中无头验证。对于要在自己产品里集成 screenpipe 录屏能力的团队这份示例既是可直接改用的模板也是理解screenpipe/sdk会话抽象的最佳入门读物。【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考