说明
APP右键打开文件,即如下图所示: 当鼠标在相应文件(比如图片)上面右键的时候,可以在打开方式中关联到我们自己开发的应用,进一步也可以将该程序设置为默认打开程序,但是后者是操作系统的行为,这里不赘述。本文主要讲如何将使用tauri开发的APP关联到对应格式的文件上面,使得在文件上右键的时候能够找到我们开发的应用程序。
配置
在tauri.conf.json
文件中添加如下配置,其中ext为必填项,表示为哪些格式的文件添加右键打开方式,description表示右键菜单显示什么名称。还有其他一些可选配置,这里不做介绍,需要可以自行查阅官方文档。
json
"bundle":{
"fileAssociations": [
{
"description": "sharpify",
"ext": [
"jpg",
"jpeg",
"png"
]
}
]
}
上述配置完成以后,将程序进行打包,在jpg、jpeg、png三种图片格式的文件上右键以后,就可以看到已经能够关联我们开发的APP了。
但是还没结束。
虽然已经关联右键菜单了,但是触发右键菜单的行为现在还没有需要我们自己实现。
实现逻辑比较简单,在后端main函数,tauri构建的时候,在setup()函数里面可以得到需要打开的文件全路径,代码如下:
rust
fn main() {
tauri::Builder::default()
.setup(|app| {
let args: Vec<String> = std::env::args().collect();
for arg in args {
if arg.ends_with(".jpg") || arg.ends_with(".png") {
// 我们右键文件的路径名称
println!(arg)
}
}
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
如果需要将文件在前端展示的话,就需要涉及跟前端交互的动作,总体来说有两种思路:
- 当后端(rust)获取图片以后,使用
app.emit('open-image', arg)
的方式,向前端(vue)发送信息,前端监听该事件 - 后端获取到要打开的文件路径以后,先存储起来,等前端就绪以后,主动调用后端获取需要的内容
思路一
第一种思路看起来更合理一些,拿到结果以后,主动向前端推送。但是有个问题,这种推送-监听
的方式容易丢失数据,比如如果后端先准备好了,他使用emit推送数据了,但是前端并没有准备好,等准备好以后再listen,这时候数据已经不存在了,就无法监听到了。
部分代码如下:
rust
fn main() {
tauri::Builder::default()
.setup(|app| {
// 将路径传给前端 Vue
log::info!("emit args:{}", &arg);
match window.emit_str("open-image", arg) {
Ok(_) => log::info!("arg emit successful "),
Err(e) => log::error!("something wrong {}", e)
}
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
js
onMounted(async () => {
// 前端通过listen监听后端数据
fileAssociationUnListen = await listen("open-image", event => {
filePath.value = event.payload;
console.log("11111", filePath)
setTimeout(()=>{
info("-----image:" + filePath)
}, 10*1000)
info('image 文件路径:{}' + filePath);
});
})
上述代码看起来比较合理,但是如果后端加载先于前端,就会导致前端拿不到数据,事实经过测试也确实是这样的。
思路二
后端拿到数据以后将文件路径存储起来,当前端就绪以后,主动调用后端方法,获取文件路径,然后进行显示:
rust
use tauri::{Manager, State};
use std::sync::Mutex;
#[derive(Default)]
struct StartupImagePath(Mutex<Option<String>>);
#[tauri::command]
fn get_startup_image_path(state: State<StartupImagePath>) -> Option<String> {
state.0.lock().unwrap().clone()
}
fn main() {
tauri::Builder::default()
.manage(StartupImagePath::default()) // ✅ 注册状态
.setup(|app| {
let args: Vec<String> = std::env::args().collect();
for arg in args {
if arg.ends_with(".jpg") || arg.ends_with(".png") {
app.state::<StartupImagePath>()
.0
.lock()
.unwrap()
.replace(arg);
}
}
Ok(())
})
.invoke_handler(tauri::generate_handler![get_startup_image_path])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
js
invoke('get_startup_image_path').then(path => {
if (path){
console.log("path=", path)
filePath.value = path
info("path" + path);
}
})
上述代码可以实现我们的需求,但是有一个潜在问题:我们希望右键文件打开app的时候能够触发这套逻辑,但是如果这么写的话,正常双击app图标打开也会调用完整的代码。
总结
本文主要描述了如何为tauri开发的app关联右键菜单。以后关联后如何触发后续软件的行为。 同时介绍了一种比较特殊的情况:当需要将后端数据传递给前端的时候,采用什么方式比较有效。但是仍然存在一定的问题。如果各位有更好的方式、欢迎留言。