打造《黑神话:悟空》壁纸软件:使用 Tauri 快速上手

简介: 本文首发于微信公众号“前端徐徐”。作者分享了如何仅用半天时间实现《黑神话:悟空》桌面壁纸软件的过程,并展示了实际效果。文中详细介绍了使用 Tauri 开发跨平台桌面应用的核心流程与关键技术,包括下载壁纸、更换壁纸以及前后端交互等细节。此外,还提供了源码和下载链接供读者体验。

本文首发微信公众号:前端徐徐。

大家好,我是徐徐!在这里跟大家分享一下我如何用半天时间实现一款《黑神话:悟空》桌面壁纸软件的。先看效果图。

  • Windows

  • Mac

前言

最近 《黑神话:悟空》这款游戏太火爆了,里面的场景和画面都非常的美丽,就想到是不是可以把里面的图片设置成桌面壁纸呢,然后我就在网上看了一下图片,发现了 Wegame 的官网有图片,但是需要一张张下载,要么就是需要下载 Wegame 然后设置桌面壁纸,我就想想我办公电脑肯定不能下载 Wegame,然后也不想一张张下载图片,于是就直接想着写个桌面应用程序来设置壁纸得了。话不多说,让我们来看看如何用 Tauri 快速完成一个桌面端的壁纸软件吧!

前期准备

在开始项目之前需要完成 rust 环境安装和 tauri 项目初始化的准备工作。具体参考如下:

核心流程

其实核心流程很简单,如下图所示。

步骤就是很常规的流式流程,中规中矩。

当然上面的是从 GUI 前端界面操作的,我们还有在系统托盘的功能,就是上一张下一张的快捷切换壁纸的功能,流程跟这个有所差别,但是核心逻辑都差不多,具体逻辑如下图所示。

上面的两个流程最核心的就是下载壁纸和更换壁纸,这两个地方也是最难的地方。

如何实现下载和更换壁纸

下载壁纸实现

#[command]
async fn download_and_set_wallpaper(url: String, file_name: String) -> Result<(), String> {
    let mut image_path = dirs::home_dir().unwrap_or(PathBuf::from("."));
    let file_name_with_extension = format!("{}.jpg", file_name);
    image_path.push(file_name_with_extension);
    let response = reqwest::get(&url).await.map_err(|e| e.to_string())?;
    let bytes = response.bytes().await.map_err(|e| e.to_string())?;
    let mut file = File::create(&image_path).map_err(|e| e.to_string())?;
    file.write_all(&bytes).map_err(|e| e.to_string())?;
    change_wallpaper(image_path.to_str().unwrap().to_string())
}

这段代码定义了一个异步函数 download_and_set_wallpaper,用于从指定的 url 下载图片并将其设置为桌面壁纸。

  • 它先确定图片的保存路径为用户主目录,并生成带 .jpg 后缀的文件名。
  • 通过 reqwest 发送 HTTP 请求下载图片数据,并保存到本地文件。
  • 下载完成后,调用 change_wallpaper 函数将该图片设置为桌面壁纸。

更换壁纸实现

fn change_wallpaper(image_path: String) -> Result<(), String> {
    #[cfg(target_os = "windows")]
    {
        let c_image_path = CString::new(image_path).map_err(|e| e.to_string())?;
        unsafe {
            if SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, c_image_path.as_ptr() as *mut _, 0)
                == 0
            {
                return Err("Failed to set wallpaper".into());
            }
        }
    }
    #[cfg(target_os = "macos")]
    {
        let script = format!(
            r#"tell application "System Events"
                set desktopCount to count of desktops
                repeat with desktopNumber from 1 to desktopCount
                    tell desktop desktopNumber
                        set picture to POSIX file "{}"
                    end tell
                end repeat
            end tell"#,
            image_path
        );
        let output = Command::new("osascript")
            .arg("-e")
            .arg(&script)
            .output()
            .map_err(|e| e.to_string())?;
        if !output.status.success() {
            return Err(String::from_utf8_lossy(&output.stderr).to_string());
        }
    }
    Ok(())
}

这段代码定义了一个 change_wallpaper 函数,用于在 Windows 和 macOS 系统上设置桌面壁纸。根据操作系统的不同,代码路径也不同:

  1. Windows (target_os = "windows"):
  • 将图片路径 image_path 转换为 C 风格的字符串(CString)。
  • 使用 SystemParametersInfoA 函数设置桌面壁纸。如果设置失败,返回错误信息。
  • 该部分代码是通过 #[cfg(target_os = "windows")] 宏条件编译的,确保只在 Windows 系统上编译和运行。
  1. macOS (target_os = "macos"):
  • 使用 AppleScript 生成一个脚本,设置所有桌面的壁纸为指定的 image_path
  • 使用 osascript 命令执行该 AppleScript 脚本。
  • 如果脚本执行失败,返回错误信息。

设置壁纸这一块也有很多其他的方法,我暂时觉得上面的两个方法更加简单方便,如果你有其他的方案也可以替换。

前后端如何交互

前后端交互主要是用到两个方法,前端向后端发消息使用 invoke,前端收后端的消息使用 listen

大概分四大块,分别是:

  • 前端向后端发送消息
const handleChangeWallpaper = async (item: any, index: number, showLoading = true) => {
  setTip('设置中...')
  currentIndex = index;
  if (showLoading) {
    setLoading(true);
  }
  try {
    // 向后端发出指令
    await invoke('download_and_set_wallpaper', {
      url: item.url,
      fileName: item.file_id,
      wallpapers: wallPapers
    });
    if (showLoading) {
      message.success('壁纸更改成功!');
    }
  } catch (error) {
    if (showLoading) {
      message.error(`更改壁纸失败: ${error}`);
    }
  } finally {
    setLoading(false);
  }
};
  • 后端处理前端消息
#[command]
async fn download_and_set_wallpaper(url: String, file_name: String) -> Result<(), String> {}
  • 后端发送消息给前端
SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
                // 点击发送事件
                "next" => {
                    app.emit_all("change_wallpaper", Payload { message: "next_wallpaper".into() }).unwrap();
                }
                "previous" => {
                    app.emit_all("change_wallpaper", Payload { message: "previous_wallpaper".into() }).unwrap();
                }
                _ => {}
            },
  • 前端接受后端的消息
useEffect(() => {
    const changeWallpaperListen = listen("change_wallpaper", (data:any) => {
      const currentIndex = Number(localStorage.getItem("currentIndex")) || 0;
      console.log("currentIndex",currentIndex)
      const { message } = data.payload || {};
      if (message === "next_wallpaper") {
        let indexData = currentIndex + 1;
        if (indexData > wallPapers.length - 1){
          indexData = 0
        }
        if (wallPapers[indexData]) {
          handleChangeWallpaper(wallPapers[indexData], indexData, false);
        } else {
          // 兜底
          handleChangeWallpaper(WALLPAPERS[0], 0, false);
        }
      }
      if (message === "previous_wallpaper") {
        let indexData = currentIndex - 1
        if (indexData < 0){
          indexData = wallPapers.length - 1
        }
        if (wallPapers[indexData]) {
          handleChangeWallpaper(wallPapers[indexData], indexData, false);
        } else {
          handleChangeWallpaper(WALLPAPERS[0], 0, false);
        }
      }
    });
    return () => {
      changeWallpaperListen.then((unlisten) => unlisten());
    };
  }, [wallPapers]);

到这里其实所有的核心代码逻辑就完成了,然后只需要测试修改添加一些其他的辅助功能就可以使用了。

一些已知问题

  • Mac 端扩展屏幕壁纸不同步,确保扩展屏幕在主屏幕即可
  • Mac 首次使用文件权限提醒

直接允许之后就可以使用。

  • Windows 下载 & 安装阻止

解除限制即可使用,原因是因为没有签名。

源码

https://github.com/Xutaotaotao/wukong-wallpaper

下载地址

https://github.com/Xutaotaotao/wukong-wallpaper/releases

结语

这个应用纯粹是个人玩具,图片源自于 Wegame 官网,如果大家有兴趣可以下载使用体验体验。空闲时间做一些好玩的东西也是不错的,可以锻炼技术,还可以让自己方便,何乐而不为?

相关文章
|
存储 人工智能 弹性计算
从“云+原神”到“云上星穹”,阿里云支持米哈游新游全球首发
近日,阿里云支持米哈游新作《崩坏:星穹铁道》正式上线,首发当天全网下载量突破2000万,当日登上iOS免费榜与畅销榜的总榜第一及其他多国榜首。
|
存储 Rust 前端开发
Tauri 开发实践 — Tauri 配置介绍
本文首发于微信公众号“前端徐徐”,主要讲解`package.json`、`Cargo.toml`及`tauri.conf.json`三个文件的配置。其中,`tauri.conf.json`最为复杂,涉及众多配置项。`package.json`用于配置前端依赖与脚本;`Cargo.toml`用于声明Rust应用依赖;`tauri.conf.json`则管理前端资源、API白名单等。这些配置对于Tauri应用的开发至关重要。
947 5
|
11月前
|
人工智能 算法 机器人
票房登顶第一!从《哪吒2》看中国科技企业集体“闹海”
《哪吒之魔童闹海》以“我命由我不由天”的精神点燃观众热血,五年后再次以“若前方无路,我便踏出一条路”的态度唤醒少年气。电影不仅刷新了国内票房纪录,更象征着中国科技企业集体逆袭的精神。从九牧卫浴到DeepSeek、华为、比亚迪等企业,它们用创新和勇气打破成见,改写规则,在全球市场中崭露头角,展现了“哪吒精神”的现实对照。
309 1
|
存储 人工智能 物联网
FLUX第三弹:直面天命,FLUX.1-LoRA/IP-adapter「黑神话:悟空」生图实战
应近日来诸多社区开发者的学习诉求,特为大家推出一期 FLUX.1-LoRA/IP-adapter+ComfyUI +“顶流”IP「黑神话:悟空」的模型推理实战教程,玩转一把AI悟空生图 👀
|
存储 安全 Cloud Native
阿里云支持米哈游新游《绝区零》全球开服!
阿里云支持米哈游新游《绝区零》全球开服!
3623 5
|
数据采集 数据可视化 Python
用Python爬取《王者荣耀》英雄皮肤数据并可视化分析,用图说话
带大家分析一波当前热门手游《王者荣耀》英雄皮肤,比如**皮肤上线时间**、**皮肤类型**(勇者;史诗;传说等)、**价格**。
1159 0
用Python爬取《王者荣耀》英雄皮肤数据并可视化分析,用图说话
|
编解码 机器人 程序员
程序员的炫酷动态科幻桌面壁纸
程序员的炫酷动态科幻桌面壁纸
1225 0
|
存储 编解码 人工智能
15M安装包就能玩《原神》,带你了解云游戏背后的技术秘密
对于大多数玩家来说,云游戏已经不是一个陌生的概念,它经常和秒玩、不吃设备、大屏临场感、上手门槛低、真香等字眼一起出现在评论留言区。的确,对于既想尝试高品质游戏大作又不想一直卷装备的玩家来说,云游戏做到了从“不能”到“能玩”到历史性突破。2021年,它也当之无愧走上了游戏圈的C位。
3003 0
15M安装包就能玩《原神》,带你了解云游戏背后的技术秘密
|
数据采集 开发者
[PaddleSpeech 原神] 音色克隆之胡桃
[PaddleSpeech 原神] 音色克隆之胡桃
|
Android开发
王者荣耀安卓区修改荣耀战区方法 | 最低战力查询(附带视频与安装包)
王者荣耀安卓区修改荣耀战区方法 | 最低战力查询(附带视频与安装包)
1179 0