tauri first try -- rmusic

First try with Tauri

Recently, I have been trying to learn Tauri, a framework for building desktop applications using web technologies. I decided to create a simple music player application called “rmusic” as my first project.

For back, I use Rust and choose crates like rodio and tokio to handle audio playback and asynchronous tasks, respectively. The application is designed to be lightweight and efficient, making it suitable for various platforms.

For front, I use Vue.js and Vite to build the user interface. The combination of Tauri, Vue.js, and Rust allows me to create a modern desktop application with a responsive design and smooth performance.

Here is the github link for the project: rmusic

Init with Tauri

1
npm create tauri-app

Dependencies

1
2
3
4
5
6
7
8
9
# Cargo.toml
[dependencies]
tauri = { version = "2", features = ["tray-icon"] }
tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tauri-plugin-dialog = "2"
rodio = "0.20.1"
tokio = { version = "1.44.2", features = ["full", "rt-multi-thread"] }
1
2
3
4
5
6
7
8
9
10
11
// package.json
...
"dependencies": {
"vue": "^3.5.13",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "^2.2.1",
"@tauri-apps/plugin-opener": "^2",
"element-plus": "^2.9.8",
"vue-router": "^4.5.0"
},
...

Permissions

For tauri, you need to set permissions in /capabilities/default.json, which gives permissions to frontend.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"opener:default",
"core:window:allow-create",
"core:webview:allow-create-webview-window",
"core:window:allow-show",
"core:window:allow-hide",
"core:window:allow-close",
"core:window:allow-set-focus",
"dialog:allow-open"
]
}

Begin

Now everything is ready, and you can start building your Tauri application. You can run the application using the following command:

1
npm run tauri dev

Some details

The point of this project is the state sharing between the front and back. Tauri offers a way to share state between the front and back using the invoke method. You can call Rust functions from JavaScript and vice versa.

Also, Tauri provides a way to manage global state using manage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let music = Music::new();
tauri::Builder::default()
.setup(|app| {
// setup the tray icon
setup_tray(app).unwrap();

Ok(())
})
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![
is_sink_empty,
handle_event,
scan_files,
])
// share sender and sink with the frontend
.manage(music.event_sender)
.manage(music.sink)
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

.invoke_handler is used to register the Rust functions that can be called from JavaScript. The manage method is used to share the state between the front and back. In this case, we are sharing the event_sender and sink objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// src/music.rs
pub struct Music {
pub event_sender: Sender<MusicState>,
_stream: OutputStream,
pub sink: Arc<Mutex<Sink>>,
}

#[derive(Debug, Clone)]
pub enum MusicState {
Play(String),
Recovery,
Pause,
Volume(f32),
Quit,
}

// one part of the event match
// p.s. you should use `tokio::spawn` and `Arc<Mutex<Sink>>` to handle the sink
...
match event {
MusicState::Play(path) => {
let file = BufReader::new(File::open(path).unwrap());
let source = Decoder::new(file).unwrap();
sink.clear();
if sink.is_paused() {
sink.append(source);
sink.play();
}
}
MusicState::Recovery => {
sink.play();
}
MusicState::Pause => {
sink.pause();
}
MusicState::Volume(volume) => {
sink.set_volume(volume / 50.0);
}
MusicState::Quit => {
sink.stop();
}
}
...

Update

I add another service to rmusic to handle online music. This repo can help you to get the online music. I use reqwest to get the data from the API. The API is a little bit slow, but it works.

So, before you use the new feature, you should run the server first.

1
2
cd KuGouMusicApi
npm i && npm run dev

Now localhost:3000 is the API server. You can use it to get the online music.

Conclusion

In conclusion, Tauri is a powerful framework for building desktop applications using web technologies. It allows you to create lightweight and efficient applications with a modern user interface. The combination of Rust and JavaScript provides a great development experience, and the ability to share state between the front and back makes it easy to manage application logic.

However, I find it difficult to search for the information I need. In my opinion, the documentation is very good. But nowadays, there are little examples for Tauri.