用 Electron 写了一个 macOS 版本的 wallpaper(附源码、下载地址)

Mac 上一直未能找到免费且好用的类似 Wallpaper Engine 的动态壁纸软件。所以直接想着自己搞一个。

本文主要记录核心技术点的实现,包括"将窗口置于桌面图标下层"、"多显示器支持"、"系统托盘常驻"。

效果展示:

功能支持

  • 控制中心 (Dashboard):提供独立的控制面板,可为每个显示器单独管理壁纸。
  • 丰富的媒体支持
    • 图片:支持 JPG, PNG, GIF, WebP 等常见格式。
    • 视频:支持 MP4, WebM, MKV, MOV (自动静音循环播放)。
    • HTML:支持将任意本地 HTML 文件设置为交互式壁纸。
  • 自动保存状态:应用重启后,自动恢复上次设置的壁纸配置。
  • 历史记录:自动记录最近使用的壁纸,方便快速切换回之前的喜爱内容。
  • 多显示器支持:自动检测接入的显示器,并支持多屏独立设置。
  • 在线画廊:内置在线资源库,可一键下载包括《绝区零》、《原神》、《鸣潮》等热门游戏的高清静态与动态壁纸。

核心技术实现

1. 将窗口置于桌面图标下层

这是最核心的功能。Electron 的 BrowserWindow 提供了一个 type: 'desktop' 属性,在 macOS 上会将窗口置于最底层。

javascript 复制代码
const win = new BrowserWindow({
  type: 'desktop', // 关键配置:设置为桌面类型
  enableLargerThanScreen: true,
  frame: false,    // 无边框
  show: false,     // 先隐藏,加载完再显示
  webPreferences: {
    nodeIntegration: true,
    contextIsolation: false,
    webSecurity: false // 允许加载本地资源
  }
});

仅仅这样还不够,为了保证交互体验,我们需要让这个窗口无法被聚焦和移动,像真正的壁纸一样。

2. 多显示器支持

现在的开发环境通常都有多个屏幕。通过 Electron 的 screen 模块获取所有显示器,并为每个显示器创建一个独立的 BrowserWindow 实例。

javascript 复制代码
const { screen } = require('electron');

const displays = screen.getAllDisplays();

displays.forEach((display) => {
  createWallpaperWindow(display);
});

function createWallpaperWindow(display) {
  const { x, y, width, height } = display.bounds;
  const win = new BrowserWindow({
    x, y, width, height, // 填满当前屏幕
    // ... 其他配置
  });
  
  // 加载资源
  win.loadFile('path/to/wallpaper.html');
}

3. 资源获取 (爬虫)

为了解决壁纸来源问题,内置了一个简单的爬虫(基于 Node.js fetch),抓取米游社等平台的同人图和官方壁纸。

主要难点在于处理接口的 Referer 校验和数据分页。

4. 甚至支持关闭主窗口后常驻后台

为了不让应用在关闭设置面板(主窗口)时直接退出,需要利用 Tray 模块和拦截 window-all-closed 事件。

javascript 复制代码
// 拦截主窗口关闭事件,改为隐藏
mainWindow.on('close', (event) => {
  if (!app.isQuitting) {
    event.preventDefault();
    mainWindow.hide();
  }
});

// 实现托盘菜单
const tray = new Tray(iconPath);
const contextMenu = Menu.buildFromTemplate([
  { label: '打开面板', click: () => showMainWindow() },
  { label: '退出', click: () => {
      app.isQuitting = true;
      app.quit();
    } 
  }
]);
tray.setContextMenu(contextMenu);

构建与分发

1. 双架构打包

为了同时支持 M1/M2/M3 (Apple Silicon) 和旧款 Intel Mac,配置了 electron-builder 的 universal 构建或分别构建。

package.json 配置:

json 复制代码
"mac": {
  "target": {
    "target": "default",
    "arch": ["x64", "arm64"]
  }
}

2. "应用已损坏,无法打开" 的解决

因为没有购买 Apple 昂贵的开发者证书进行签名,编译出的 .app 在别人的电脑上运行时会被 macOS Gatekeeper 拦截,提示"应用已损坏"。

这是一个常见问题,解决方法是移除苹果的隔离属性。用户需要执行一次终端命令:

bash 复制代码
sudo xattr -rd com.apple.quarantine /Applications/Wallpaper-Mac.app

源码与下载

项目已开源,虽然功能简单,但足以满足日常动态壁纸需求(支持视频、图片)。

欢迎 Star 和 PR。

相关推荐
qetfw7 小时前
MXU:Tauri 2 + React 的 MaaFramework 跨平台 GUI 源码
前端·python·react.js·前端框架·开源项目·效率工具
甲维斯7 小时前
我要开始吹牛逼了!Kimi K3 “宇宙无敌”!
前端·人工智能
a1117767 小时前
微光小屋-前端养成小游戏 开源项目
前端
kyriewen7 小时前
我让AI给前端项目做了一次完整的Code Review——它和人类的差距,比我想的大得多
前端·javascript·ai编程
张鑫旭7 小时前
快速过下我2026年上半年的前端学了些啥
前端
এ慕ོ冬℘゜7 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
hoLzwEge8 小时前
拯救低效调试!code-inspector-plugin 让代码定位如虎添翼
前端·前端框架·node.js
J船长8 小时前
烂笔头扫盲:LLM Eval 入门:从「感觉挺好」到「数据说话」的工程化落地
前端
skiyee8 小时前
被多个 UView 系 UI 库 “抄” 的 @uni-ku/root 究竟怎么实现?
前端