Flutter + Tauri + Vite.
APACHE-2.0 License
This template should help get you started developing with Tauri in Flutter, JS/TS and Rust.
pnpm install
flutter pub get
Run the VSCode task Dev
to start the development server. This will start the Tauri dev server, the Flutter dev server.
Run the VSCode task Build
to build the app. This will build the Flutter app, build the Tauri app and bundle the JS/TS app.
Rust interop src-tauri/src/main.rs
:
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Rust dependencies can be added to src-tauri/Cargo.toml
.
JS/TS interop src/api.ts
:
import { invoke } from "@tauri-apps/api/tauri";
function invokeRust<T>(cmd: string, args: string): Promise<T> {
return invoke(cmd, JSON.parse(args));
}
function evalJs(js: string): any {
return eval(js);
}
declare global {
interface Window {
invokeRust: typeof invokeRust;
evalJs: typeof evalJs;
}
}
window.invokeRust = invokeRust;
window.evalJs = evalJs;
JS/TS dependencies can be added to package.json
.
Vite will build this file into
web/js
and Flutter will include it in theweb.index.html
.
Dart interop lib/api.dart
:
@JS()
library static_interop;
import 'dart:convert';
import 'dart:html' as html;
import 'dart:js_util';
import 'package:js/js.dart';
@JS()
@staticInterop
class JSWindow {}
extension JSWindowExtension on JSWindow {
external Function invokeRust;
external Function evalJs;
}
Future<T?> invokeRust<T>(String command, Map<String, Object?> args) async {
try {
final jsWindow = html.window as JSWindow;
final argsJson = jsonEncode(args);
final function = jsWindow.invokeRust(command, argsJson);
final future = promiseToFuture(function);
final result = await future;
return result;
} catch (e) {
return null;
}
}
Future<T?> evalJs<T>(String code) async {
try {
final jsWindow = html.window as JSWindow;
final function = jsWindow.evalJs(code);
final result = function;
return result;
} catch (e) {
return null;
}
}
Flutter dependencies can be added to pubspec.yaml
.
Example usage in lib/main.dart
:
import 'package:flutter/material.dart';
import 'api.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter + Tauri + Vite'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? rustMessage;
String? jsMessage;
@override
void initState() {
invokeRust('greet', {'name': 'Flutter'}).then((result) {
if (mounted) {
setState(() {
rustMessage = result;
});
}
});
evalJs('(function() { return "Hello from JS"; })()').then((result) {
if (mounted) {
setState(() {
jsMessage = result;
});
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
children: [
ListTile(
title: const Text('Rust says:'),
subtitle: Text(rustMessage ?? 'Loading...'),
),
ListTile(
title: const Text('JS says:'),
subtitle: Text(jsMessage ?? 'Loading...'),
),
],
),
);
}
}