用 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。

相关推荐
程序猿DD4 小时前
OctaFuse Gateway 2.11.0:流式请求优化、用户折扣策略与错误契约升级
前端·后端
尾善爱看海5 小时前
《JavaScript 数组操作全攻略:12 类 API + 30 个实战场景 + 20 个避坑指南》
前端·javascript·面试
Bs_MoneyMagnet5 小时前
基于springboot+vue的非遗物质文化遗产系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
计算机毕设定制辅导-无忧学长5 小时前
《基于SpringBoot的未成年人健康知识科普平台的设计与实现》
java·开发语言·vue.js·spring boot·未成年人健康知识科普平台
计算机魔术师5 小时前
Anthropic 估值冲 4 万亿,但企业客户已经偷偷换了便宜模型
前端
王六米。5 小时前
RAG知识库建设 文档解析 切分与索引如何衔接
服务器·前端·网络·企业数字化转型·智钳智能盒子
名字还没想好☜5 小时前
React 文件上传实战:预览 URL 回收、多文件逐个进度与拖拽放置区踩坑
前端·react·next.js
console.log('npc')5 小时前
06 — Model 层:数据模型与操作
前端·后端·node.js·express
linux_cfan5 小时前
16 · `custom-media-element`:属性拦截与转发
前端·javascript·音视频
右耳朵猫AI6 小时前
Web前端周刊2026W38 | React 19.3 发布、StyleX 深潜、jsdom 30.1 提速
前端·javascript·react.js·typescript·node.js