A Flutter implementation of Velopack using flutter_rust_bridge for automated desktop app updates.
Flutter currently lacks a robust solution for distributing auto-updates for desktop applications, aside from the Microsoft and Mac App Stores. Velopack addresses this gap by providing a cross-platform installation and auto-update framework for desktop applications.
Learn more about Velopack at https://velopack.io/
This project leverages flutter_rust_bridge to interface with the Rust implementation of Velopack.
- Make sure Rust is installed: https://www.rust-lang.org/tools/install
- Add the velopack_flutter dependency to your
pubspec.yaml:
dependencies:
velopack_flutter: ^0.2.0- Import the package, initialize Velopack and handle Velopack app hooks in your main.dart:
import 'package:flutter/material.dart';
import 'package:velopack_flutter/velopack_flutter.dart';
Future<void> main(List<String> args) async {
await initializeVelopack(url: 'https://example.com/releases');
final veloCommands = ['--veloapp-install', '--veloapp-updated', '--veloapp-obsolete', '--veloapp-uninstall'];
if (veloCommands.any((cmd) => args.contains(cmd))) {
exit(0);
}
/* You can now call the API functions shown in the API section. E.g isUpdateAvailable();
Do note that the API functions will only function correctly in a vpk packed release.
isUpdateAvailable and the rest will just throw an exception if you call them while debugging.
*/
runApp(const MyApp());
}If your project has existing Rust bindings, you'll need to have a distinct library class name to prevent name conflicts.
This is what Velopack Flutter is doing by setting the following values in flutter_rust_bridge.yaml to make the class name "unique" and avoid conflicts.
dart_entrypoint_class_name: VelopackRustLibWe recommend you do the same on your own Rust bindings.
| Function | Description |
|---|---|
initializeVelopack({required String url}) |
Initializes the bridge and configures Velopack with the update server URL. |
isUpdateAvailable() |
Checks if an update is available. |
getLatestUpdateInfo() |
Gets detailed information about the latest available update. |
currentVersion() |
Returns the current application version as a string. |
checkAndDownloadUpdatesWithProgress() |
Checks for updates, downloads them, and returns a progress stream. |
updateAndRestart() |
Applies downloaded updates and restarts the application. |
updateAndExit() |
Applies downloaded updates and exits the application. |
waitExitThenUpdate({required bool silent, required bool restart}) |
Waits for the app to exit, then applies updates. If restart is true, the app will restart after applying updates. Use silent to suppress UI messages. |
- Install .NET Core SDK 6.0 and the
vpktool:
dotnet tool update -g vpk- Build your Flutter app:
flutter build [windows|macos|linux] --release- Navigate to your release build directory & package your app using
vpk:
cd build/windows/x64/runner
vpk pack --packId YourAppId --packVersion 1.0.0 --packDir Release --mainExe YourApp.execd build/macos/Build/Products/Release
vpk pack -u "xyz.appName.companyName" -v 1.0.0 \
-p "./YourApp.app" \
--channel "osx-channelName" \
--mainExe "Application Binary" \
--noPortable --packTitle "Application Title" --signEntitlements "$(pwd)/macos/Runner/Release.entitlements" \
--signAppIdentity "Developer ID Application: (Your Name)" \
--signInstallIdentity "Developer ID Installer: (Your Name)" \
--notaryProfile "notary-profile-name" \Your release package will be generated in the Releases directory.
For more information on packaging and distribution, refer to:
There is an issue (velopack/velopack#254) in the Velopack repo about adding full API support for GitHub releases. In the meantime you can still use GitHub releases with a few workarounds:
Run the download command before packing to include the latest information from your GitHub releases
vpk download github --repoUrl https://github.com/{orgOrUser}/{repoName}Then pack as normal.
vpk upload github --repoUrl https://github.com/{orgOrUser}/{repoName} --publish --releaseName YourDesiredReleaseName --tag v1.0.0 --token your_github_tokenVelopack expects all the files to be available at the given URL. One way to accomplish this with GitHub releases is
to specify ${repoUrl}releases/download/${tagName}/ as the URL passed to initializeVelopack.
This does require you to parse out the tag for the latest release manually yourself, e.g.:
final url = Uri.parse('${repoUrl}releases/latest/');
final response = await http.get(url);
if (response.statusCode == 200) {
final data = json.decode(response.body);
final tag_name = data['tag_name']
}- The Linux implementation is currently untested. Contributions and feedback from Linux users are welcome.
- The API may differ from Velopack implementations in other languages and is not feature-complete. In the long-term it would make sense to keep these consistent, however I didn't have time for this yet. Feel free to open a PR!
If you encounter issues, have suggestions, or want to contribute code, please open an issue or submit a pull request on this GitHub repository.