You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tauri Rust开发的Mac应用中添加右键菜单?集成Finder Sync扩展存疑

在Tauri Rust应用中集成Finder Sync扩展实现右键菜单选项

要给Mac上的Tauri Rust应用添加Finder右键菜单选项(比如“更换壁纸”),核心思路是通过Finder Sync Extension(苹果原生系统扩展)实现菜单渲染,再通过进程间通信(IPC)把选中的文件路径传递给Tauri主应用执行逻辑。下面是具体步骤:

1. 给Tauri项目添加Finder Sync扩展目标

Tauri生成的Xcode项目是基础,你需要在Xcode中给它添加一个新的扩展Target:

  • 打开Tauri项目的src-tauri/tauri.xcodeproj
  • 点击菜单栏File > New > Target,选择Finder Sync Extension(属于Application Extension分类)
  • 设置扩展的Bundle ID,必须和主应用Bundle ID关联(比如主应用是com.yourdomain.app,扩展设为com.yourdomain.app.FinderSync)
  • 确保扩展和主应用使用同一个开发者证书签名(测试阶段可以用本地开发证书)

2. 编写扩展的右键菜单逻辑

在扩展的FinderSync.swift文件中,重写菜单生成方法,添加自定义菜单项并处理点击事件:

import FinderSync

class FinderSync: FIFinderSync {
    override init() {
        super.init()
        // 设置要监听的目录(这里设为所有目录,也可以指定特定路径)
        FIFinderSyncController.default().directoryURLs = [URL(fileURLWithPath: "/")]
    }

    // 生成右键菜单
    override func menu(for menuKind: FIMenuKind) -> NSMenu? {
        let menu = NSMenu(title: "")
        let setWallpaperItem = NSMenuItem(title: "更换壁纸", action: #selector(handleSetWallpaper(_:)), keyEquivalent: "")
        setWallpaperItem.target = self
        menu.addItem(setWallpaperItem)
        return menu
    }

    // 处理菜单点击
    @objc func handleSetWallpaper(_ sender: NSMenuItem) {
        // 获取用户选中的文件URL
        guard let selectedURLs = FIFinderSyncController.default().selectedItemURLs else { return }
        let filePaths = selectedURLs.compactMap { $0.path }
        
        // 把路径传递给Tauri主应用(这里用分布式通知+共享UserDefaults示例)
        let sharedDefaults = UserDefaults(suiteName: "com.yourdomain.app.shared")!
        sharedDefaults.set(filePaths, forKey: "SelectedWallpaperPaths")
        sharedDefaults.synchronize()
        
        // 发送通知触发主应用处理
        DistributedNotificationCenter.default().post(
            name: NSNotification.Name("com.yourdomain.app.SetWallpaper"),
            object: nil
        )
    }
}

3. Tauri主应用接收并处理请求

在Rust代码中,监听扩展发送的分布式通知,读取共享的文件路径,然后执行更换壁纸的逻辑:

3.1 监听系统通知

用objc crate绑定Mac的分布式通知中心(需要在Cargo.toml中添加objc = "0.2"):

use objc::runtime::{Object, Sel};
use objc::{msg_send, sel, sel_impl};
use tauri::Manager;

fn listen_for_wallpaper_notification(app: tauri::AppHandle) {
    // 创建通知观察者
    let center = unsafe { msg_send![class!(NSDistributedNotificationCenter), defaultCenter] };
    let observer: *mut Object = unsafe {
        msg_send![center, addObserverForName: ns_string!("com.yourdomain.app.SetWallpaper") object: nil queue: nil usingBlock: block!({
            // 读取共享UserDefaults中的路径
            let shared_defaults = unsafe {
                msg_send![class!(NSUserDefaults), alloc]
            };
            let shared_defaults = unsafe {
                msg_send![shared_defaults, initWithSuiteName: ns_string!("com.yourdomain.app.shared")]
            };
            let paths: Vec<String> = unsafe {
                msg_send![shared_defaults, objectForKey: ns_string!("SelectedWallpaperPaths")]
            };
            
            // 执行更换壁纸逻辑
            if let Some(path) = paths.first() {
                set_wallpaper(&path);
            }
        })]
    };
    
    // 把观察者存到AppHandle的全局数据中,防止被释放
    app.state().insert(observer);
}

// 辅助函数:把Rust字符串转成NSString
fn ns_string(s: &str) -> *mut Object {
    unsafe {
        let str = msg_send![class!(NSString), stringWithUTF8String: s.as_ptr()];
        str
    }
}

3.2 实现更换壁纸逻辑

可以通过调用Mac的osascript命令或者直接调用系统API,这里用简单的命令行方式:

use std::process::Command;

fn set_wallpaper(path: &str) {
    let script = format!("tell application \"Finder\" to set desktop picture to POSIX file \"{}\"", path);
    if let Err(e) = Command::new("osascript")
        .arg("-e")
        .arg(&script)
        .output()
    {
        eprintln!("Failed to set wallpaper: {}", e);
    }
}

3.3 在Tauri启动时注册监听

在main.rs的setup方法中启动通知监听:

fn main() {
    tauri::Builder::default()
        .setup(|app| {
            listen_for_wallpaper_notification(app.handle());
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("Failed to run Tauri app");
}

4. 配置权限与打包

  • 在扩展的Info.plist中添加文件访问权限描述,比如NSDesktopFolderUsageDescription(说明为什么需要访问桌面文件)
  • 打包时,Xcode的Archive流程会自动把扩展包含在App Bundle中,确保签名一致
  • 测试时,需要在系统偏好设置 > 扩展 > Finder扩展中启用你的扩展

内容的提问来源于stack exchange,提问作者Nane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:24:52