├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── top │ │ │ │ └── wherewego │ │ │ │ └── vnt_app │ │ │ │ ├── MainActivity.java │ │ │ │ └── vpn │ │ │ │ ├── DeviceConfig.java │ │ │ │ ├── IpUtils.java │ │ │ │ └── MyVpnService.java │ │ ├── jniLibs │ │ │ ├── arm64-v8a │ │ │ │ └── librust_lib_vnt_app.so │ │ │ ├── armeabi-v7a │ │ │ │ └── librust_lib_vnt_app.so │ │ │ ├── x86 │ │ │ │ └── librust_lib_vnt_app.so │ │ │ └── x86_64 │ │ │ │ └── librust_lib_vnt_app.so │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-ldpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── app_icon.ico ├── app_icon.png └── log4rs.yaml ├── flutter_rust_bridge.yaml ├── integration_test └── simple_test.dart ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon-1024.png │ │ │ ├── icon-20@2x.png │ │ │ ├── icon-20@3x.png │ │ │ ├── icon-29@2x.png │ │ │ ├── icon-29@3x.png │ │ │ ├── icon-38@2x.png │ │ │ ├── icon-38@3x.png │ │ │ ├── icon-40@2x.png │ │ │ ├── icon-40@3x.png │ │ │ ├── icon-60@2x.png │ │ │ ├── icon-60@3x.png │ │ │ ├── icon-64@2x.png │ │ │ ├── icon-64@3x.png │ │ │ ├── icon-68@2x.png │ │ │ ├── icon-76@2x.png │ │ │ └── icon-83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h └── RunnerTests │ └── RunnerTests.swift ├── lib ├── about_page.dart ├── connect_log.dart ├── connected_page.dart ├── custom_app_bar.dart ├── data_persistence.dart ├── main.dart ├── network_config.dart ├── network_config_input_page.dart ├── settings_page.dart ├── src │ └── rust │ │ ├── api │ │ └── vnt_api.dart │ │ ├── frb_generated.dart │ │ ├── frb_generated.io.dart │ │ └── frb_generated.web.dart ├── utils │ └── ip_utils.dart ├── vnt │ └── vnt_manager.dart └── widgets │ ├── color_changing_button.dart │ ├── custom_tooltip_text_field.dart │ ├── dual_bar_chart.dart │ └── legend_widget.dart ├── linux ├── .gitignore ├── CMakeLists.txt ├── flutter │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake ├── main.cc ├── my_application.cc └── my_application.h ├── macos ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon-128.png │ │ │ ├── icon-128@2x.png │ │ │ ├── icon-16.png │ │ │ ├── icon-16@2x.png │ │ │ ├── icon-256.png │ │ │ ├── icon-256@2x.png │ │ │ ├── icon-32.png │ │ │ ├── icon-32@2x.png │ │ │ ├── icon-512.png │ │ │ └── icon-512@2x.png │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ ├── DebugProfile.entitlements │ ├── Info.plist │ ├── MainFlutterWindow.swift │ └── Release.entitlements └── RunnerTests │ └── RunnerTests.swift ├── pubspec.lock ├── pubspec.yaml ├── rust ├── .cargo │ └── config ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src │ ├── api │ ├── mod.rs │ └── vnt_api.rs │ ├── frb_generated.io.rs │ ├── frb_generated.rs │ ├── frb_generated.web.rs │ └── lib.rs ├── rust_builder ├── .gitignore ├── README.md ├── android │ ├── .gitignore │ ├── build.gradle │ ├── settings.gradle │ └── src │ │ └── main │ │ └── AndroidManifest.xml ├── cargokit │ ├── .gitignore │ ├── LICENSE │ ├── README │ ├── build_pod.sh │ ├── build_tool │ │ ├── README.md │ │ ├── analysis_options.yaml │ │ ├── bin │ │ │ └── build_tool.dart │ │ ├── lib │ │ │ ├── build_tool.dart │ │ │ └── src │ │ │ │ ├── android_environment.dart │ │ │ │ ├── artifacts_provider.dart │ │ │ │ ├── build_cmake.dart │ │ │ │ ├── build_gradle.dart │ │ │ │ ├── build_pod.dart │ │ │ │ ├── build_tool.dart │ │ │ │ ├── builder.dart │ │ │ │ ├── cargo.dart │ │ │ │ ├── crate_hash.dart │ │ │ │ ├── environment.dart │ │ │ │ ├── logging.dart │ │ │ │ ├── options.dart │ │ │ │ ├── precompile_binaries.dart │ │ │ │ ├── rustup.dart │ │ │ │ ├── target.dart │ │ │ │ ├── util.dart │ │ │ │ └── verify_binaries.dart │ │ ├── pubspec.lock │ │ └── pubspec.yaml │ ├── cmake │ │ ├── cargokit.cmake │ │ └── resolve_symlinks.ps1 │ ├── gradle │ │ └── plugin.gradle │ ├── run_build_tool.cmd │ └── run_build_tool.sh ├── ios │ ├── Classes │ │ └── dummy_file.c │ └── rust_lib_vnt_app.podspec ├── linux │ └── CMakeLists.txt ├── macos │ ├── Classes │ │ └── dummy_file.c │ └── rust_lib_vnt_app.podspec ├── pubspec.yaml └── windows │ ├── .gitignore │ └── CMakeLists.txt ├── test_driver └── integration_test.dart ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── index.html └── manifest.json └── windows ├── .gitignore ├── CMakeLists.txt ├── dlls ├── amd64 │ └── wintun.dll ├── arm │ └── wintun.dll ├── arm64 │ └── wintun.dll └── x86 │ └── wintun.dll ├── flutter ├── CMakeLists.txt ├── generated_plugin_registrant.cc ├── generated_plugin_registrant.h └── generated_plugins.cmake └── runner ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── resources └── app_icon.ico ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 17 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 18 | - platform: android 19 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 20 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 21 | - platform: ios 22 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 23 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 24 | - platform: linux 25 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 26 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 27 | - platform: macos 28 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 29 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 30 | - platform: web 31 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 32 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 33 | - platform: windows 34 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 35 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VNT GUI 2 | 3 | VNT GUI 4 | 5 | ## Build 6 | 7 | ### Install 8 | 9 | After [Flutter](https://docs.flutter.dev/get-started/install) and [Rust](https://www.rust-lang.org/tools/install) are installed, install `flutter_rust_bridge` 10 | 11 | ### Run 12 | ``` 13 | flutter run 14 | ``` 15 | 16 | 17 | ## Special 18 | 19 | Thanks to ChatGPT for helping with a lot of the work on this project. 20 | 21 | 22 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | rules: 24 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 25 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 26 | 27 | # Additional information about this file can be found at 28 | # https://dart.dev/guides/language/analysis-options 29 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | def localProperties = new Properties() 9 | def localPropertiesFile = rootProject.file("local.properties") 10 | if (localPropertiesFile.exists()) { 11 | localPropertiesFile.withReader("UTF-8") { reader -> 12 | localProperties.load(reader) 13 | } 14 | } 15 | 16 | def flutterVersionCode = localProperties.getProperty("flutter.versionCode") 17 | if (flutterVersionCode == null) { 18 | flutterVersionCode = "1" 19 | } 20 | 21 | def flutterVersionName = localProperties.getProperty("flutter.versionName") 22 | if (flutterVersionName == null) { 23 | flutterVersionName = "1.0" 24 | } 25 | 26 | android { 27 | namespace = "top.wherewego.vnt_app" 28 | compileSdk = flutter.compileSdkVersion 29 | ndkVersion = flutter.ndkVersion 30 | 31 | compileOptions { 32 | sourceCompatibility = JavaVersion.VERSION_1_8 33 | targetCompatibility = JavaVersion.VERSION_1_8 34 | } 35 | 36 | defaultConfig { 37 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 38 | applicationId = "top.wherewego.vnt_app" 39 | // You can update the following values to match your application needs. 40 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 41 | minSdk = flutter.minSdkVersion 42 | targetSdk = flutter.targetSdkVersion 43 | versionCode = flutterVersionCode.toInteger() 44 | versionName = flutterVersionName 45 | ndk { 46 | abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64" 47 | } 48 | versionName "1.2.11" 49 | } 50 | 51 | buildTypes { 52 | release { 53 | // TODO: Add your own signing config for the release build. 54 | // Signing with the debug keys for now, so `flutter run --release` works. 55 | signingConfig = signingConfigs.debug 56 | } 57 | } 58 | sourceSets { 59 | main { 60 | jniLibs.srcDirs = ['src/main/jniLibs'] 61 | } 62 | } 63 | } 64 | 65 | flutter { 66 | source = "../.." 67 | } 68 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 14 | 15 | 16 | 17 | 20 | 29 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /android/app/src/main/java/top/wherewego/vnt_app/MainActivity.java: -------------------------------------------------------------------------------- 1 | package top.wherewego.vnt_app; 2 | 3 | import android.content.Intent; 4 | import android.net.VpnService; 5 | import android.os.Bundle; 6 | 7 | import androidx.annotation.NonNull; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import io.flutter.embedding.android.FlutterActivity; 14 | import io.flutter.embedding.engine.FlutterEngine; 15 | import io.flutter.plugin.common.MethodChannel; 16 | import top.wherewego.vnt_app.vpn.DeviceConfig; 17 | import top.wherewego.vnt_app.vpn.IpUtils; 18 | import top.wherewego.vnt_app.vpn.MyVpnService; 19 | 20 | public class MainActivity extends FlutterActivity { 21 | private static final String CHANNEL = "top.wherewego.vnt/vpn"; 22 | private static final int VPN_REQUEST_CODE = 1; 23 | private static final String TAG = "MainActivity"; 24 | public static MethodChannel channel; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | } 30 | 31 | 32 | @Override 33 | public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { 34 | super.configureFlutterEngine(flutterEngine); 35 | channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL); 36 | channel.setMethodCallHandler((call, result) -> { 37 | if (call.method.equals("startVpn")) { 38 | try { 39 | Map arguments = call.arguments(); 40 | DeviceConfig config = parseDeviceConfig(arguments); 41 | startVpnService(config, result); 42 | } catch (Exception e) { 43 | result.error("VPN_ERROR", "Invalid DeviceConfig", e); 44 | } 45 | } else if (call.method.equals("stopVpn")) { 46 | try { 47 | MyVpnService.stopVpn(); 48 | } catch (Exception e) { 49 | result.error("VPN_ERROR", "stopVpn", e); 50 | } 51 | } else { 52 | result.notImplemented(); 53 | } 54 | } 55 | ); 56 | 57 | } 58 | 59 | private DeviceConfig parseDeviceConfig(Map arguments) { 60 | String virtualIp = (String) arguments.get("virtualIp"); 61 | String virtualNetmask = (String) arguments.get("virtualNetmask"); 62 | String virtualGateway = (String) arguments.get("virtualGateway"); 63 | Integer mtu = (Integer) arguments.get("mtu"); 64 | 65 | List> externalRouteList = (List>) arguments.get("externalRoute"); 66 | List externalRoute = new ArrayList<>(); 67 | if (externalRouteList != null) { 68 | for (Map route : externalRouteList) { 69 | String destination = route.get("destination"); 70 | String netmask = route.get("netmask"); 71 | externalRoute.add(new DeviceConfig.Route(IpUtils.ipToInt(destination), IpUtils.ipToInt(netmask))); 72 | } 73 | } 74 | return new DeviceConfig(IpUtils.ipToInt(virtualIp), IpUtils.ipToInt(virtualNetmask), IpUtils.ipToInt(virtualGateway), mtu, externalRoute); 75 | } 76 | 77 | private void startVpnService(DeviceConfig config, MethodChannel.Result result) { 78 | MyVpnService.pendingResult = result; 79 | MyVpnService.pendingConfig = config; 80 | Intent intent = VpnService.prepare(this); 81 | if (intent != null) { 82 | startActivityForResult(intent, VPN_REQUEST_CODE); 83 | } else { 84 | onActivityResult(VPN_REQUEST_CODE, RESULT_OK, null); 85 | } 86 | } 87 | 88 | @Override 89 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 90 | if (requestCode == VPN_REQUEST_CODE) { 91 | if (resultCode == RESULT_OK) { 92 | Intent serviceIntent = new Intent(this, MyVpnService.class); 93 | startService(serviceIntent); 94 | } else { 95 | // 用户拒绝授权,返回错误结果给 Flutter 96 | MyVpnService.callError("User denied VPN authorization", null); 97 | } 98 | } 99 | super.onActivityResult(requestCode, resultCode, data); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /android/app/src/main/java/top/wherewego/vnt_app/vpn/DeviceConfig.java: -------------------------------------------------------------------------------- 1 | package top.wherewego.vnt_app.vpn; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 启动VPN的配置 7 | * 8 | * @author https://github.com/lbl8603/vnt 9 | */ 10 | public class DeviceConfig { 11 | public int virtualIp; 12 | public int virtualNetmask; 13 | public int virtualGateway; 14 | public int mtu; 15 | public List externalRoute; 16 | 17 | public DeviceConfig(int virtualIp, int virtualNetmask, int virtualGateway, int mtu, List externalRoute) { 18 | this.virtualIp = virtualIp; 19 | this.virtualNetmask = virtualNetmask; 20 | this.virtualGateway = virtualGateway; 21 | this.mtu = mtu; 22 | this.externalRoute = externalRoute; 23 | } 24 | 25 | public static class Route { 26 | public int destination; 27 | public int netmask; 28 | 29 | public Route(int destination, int netmask) { 30 | this.destination = destination; 31 | this.netmask = netmask; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "Route{" + 37 | "destination=" + destination + 38 | ", netmask=" + netmask + 39 | '}'; 40 | } 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "DeviceConfig{" + 46 | "virtualIp=" + virtualIp + 47 | ", virtualNetmask=" + virtualNetmask + 48 | ", virtualGateway=" + virtualGateway + 49 | ", mtu=" + mtu + 50 | ", externalRoute=" + externalRoute + 51 | '}'; 52 | } 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /android/app/src/main/java/top/wherewego/vnt_app/vpn/IpUtils.java: -------------------------------------------------------------------------------- 1 | package top.wherewego.vnt_app.vpn; 2 | 3 | /** 4 | * ip转换 5 | * 6 | * @author https://github.com/lbl8603/vnt 7 | */ 8 | public class IpUtils { 9 | /** 10 | * 将整数的ip地址转成字符串,例如 0 转成 "0.0.0.0" 11 | * 12 | * @param ipAddress 13 | * @return 14 | */ 15 | public static String intToIpAddress(int ipAddress) { 16 | 17 | return ((ipAddress & 0xFF000000) >>> 24) + "." + 18 | ((ipAddress & 0x00FF0000) >>> 16) + "." + 19 | ((ipAddress & 0x0000FF00) >>> 8) + "." + 20 | (ipAddress & 0x000000FF); 21 | } 22 | public static int ipToInt(String ipAddress) { 23 | String[] parts = ipAddress.split("\\."); 24 | int ip = 0; 25 | for (int i = 0; i < 4; i++) { 26 | ip <<= 8; 27 | ip |= Integer.parseInt(parts[i]); 28 | } 29 | return ip; 30 | } 31 | 32 | /** 33 | * 返回掩码的长度 34 | * 35 | * @param subnetMask 36 | * @return 37 | */ 38 | public static int subnetMaskToPrefixLength(int subnetMask) { 39 | int prefixLength = 0; 40 | int bit = 1 << 31; 41 | 42 | while (subnetMask != 0) { 43 | if ((subnetMask & bit) != bit) { 44 | break; 45 | } 46 | prefixLength++; 47 | subnetMask <<= 1; 48 | } 49 | 50 | return prefixLength; 51 | } 52 | } -------------------------------------------------------------------------------- /android/app/src/main/java/top/wherewego/vnt_app/vpn/MyVpnService.java: -------------------------------------------------------------------------------- 1 | package top.wherewego.vnt_app.vpn; 2 | 3 | import android.content.Intent; 4 | import android.content.IntentFilter; 5 | import android.net.ConnectivityManager; 6 | import android.net.VpnService; 7 | import android.os.ParcelFileDescriptor; 8 | import android.system.OsConstants; 9 | import android.util.Log; 10 | 11 | import java.io.IOException; 12 | 13 | import io.flutter.plugin.common.MethodChannel; 14 | import top.wherewego.vnt_app.MainActivity; 15 | 16 | public class MyVpnService extends VpnService { 17 | private static final String TAG = "MyVpnService"; 18 | private static ParcelFileDescriptor vpnInterface; 19 | private volatile static MyVpnService vpnService; 20 | 21 | public static MethodChannel.Result pendingResult; 22 | public static DeviceConfig pendingConfig; 23 | 24 | public static synchronized void callSuccess(int fd) { 25 | if (pendingResult != null) { 26 | pendingResult.success(fd); 27 | } 28 | pendingResult = null; 29 | } 30 | 31 | public static synchronized void callError(String msg, Exception e) { 32 | if (pendingResult != null) { 33 | pendingResult.error("VPN_ERROR", msg, e); 34 | } 35 | pendingResult = null; 36 | } 37 | 38 | @Override 39 | public synchronized int onStartCommand(Intent intent, int flags, int startId) { 40 | vpnService = this; 41 | new Thread(() -> { 42 | try { 43 | int fd = startVpn(pendingConfig); 44 | callSuccess(fd); 45 | } catch (Exception e) { 46 | Log.e(TAG, "pendingConfig =" + pendingConfig.toString(), e); 47 | callError("Failed to start VPN", e); 48 | } 49 | }).start(); 50 | return START_STICKY; 51 | } 52 | 53 | @Override 54 | public void onCreate() { 55 | // Listen for connectivity updates 56 | IntentFilter ifConnectivity = new IntentFilter(); 57 | ifConnectivity.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 58 | super.onCreate(); 59 | } 60 | 61 | public static void stopVpn() { 62 | MainActivity.channel.invokeMethod("stopVnt", null); 63 | if (vpnService != null) { 64 | vpnService.stopSelf(); 65 | } 66 | if (vpnInterface != null) { 67 | try { 68 | vpnInterface.close(); 69 | } catch (IOException e) { 70 | Log.e(TAG, "Error closing existing VPN interface", e); 71 | } 72 | } 73 | } 74 | 75 | private int startVpn(DeviceConfig config) { 76 | Builder builder = new Builder(); 77 | String ip = IpUtils.intToIpAddress(config.virtualIp); 78 | int prefixLength = IpUtils.subnetMaskToPrefixLength(config.virtualNetmask); 79 | String ipRoute = IpUtils.intToIpAddress(config.virtualGateway & config.virtualNetmask); 80 | builder 81 | .allowFamily(OsConstants.AF_INET) 82 | .setBlocking(false) 83 | .setMtu(config.mtu) 84 | .addAddress(ip, prefixLength) 85 | .addRoute(ipRoute, prefixLength); 86 | if (config.externalRoute != null) { 87 | for (DeviceConfig.Route routeItem : config.externalRoute) { 88 | int routePrefixLength = IpUtils.subnetMaskToPrefixLength(routeItem.netmask); 89 | String routeDest = IpUtils.intToIpAddress(routeItem.destination); 90 | builder.addRoute(routeDest, routePrefixLength); 91 | } 92 | } 93 | try { 94 | vpnInterface = builder.setSession("VNT") 95 | .establish(); 96 | } catch (Exception e) { 97 | Log.e(TAG, "Error establishing VPN interface", e); 98 | } 99 | return vpnInterface.getFd(); 100 | } 101 | 102 | @Override 103 | public void onDestroy() { 104 | super.onDestroy(); 105 | stopVpn(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /android/app/src/main/jniLibs/arm64-v8a/librust_lib_vnt_app.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/jniLibs/arm64-v8a/librust_lib_vnt_app.so -------------------------------------------------------------------------------- /android/app/src/main/jniLibs/armeabi-v7a/librust_lib_vnt_app.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/jniLibs/armeabi-v7a/librust_lib_vnt_app.so -------------------------------------------------------------------------------- /android/app/src/main/jniLibs/x86/librust_lib_vnt_app.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/jniLibs/x86/librust_lib_vnt_app.so -------------------------------------------------------------------------------- /android/app/src/main/jniLibs/x86_64/librust_lib_vnt_app.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/jniLibs/x86_64/librust_lib_vnt_app.so -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/res/mipmap-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 21 | id "com.android.application" version "7.3.0" apply false 22 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 23 | } 24 | 25 | include ":app" 26 | -------------------------------------------------------------------------------- /assets/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/assets/app_icon.ico -------------------------------------------------------------------------------- /assets/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/assets/app_icon.png -------------------------------------------------------------------------------- /assets/log4rs.yaml: -------------------------------------------------------------------------------- 1 | refresh_rate: 30 seconds 2 | appenders: 3 | rolling_file: 4 | kind: rolling_file 5 | path: logs/vnt-core.log 6 | append: true 7 | encoder: 8 | pattern: "{d(%Y-%m-%d %H:%M:%S.%3f)} [{f}:{L}] {h({l})} {M}:{m}{n}{n}" 9 | policy: 10 | kind: compound 11 | trigger: 12 | kind: size 13 | limit: 10 mb # 每个日志文件最多10M 14 | roller: 15 | kind: fixed_window 16 | pattern: logs/vnt-core.{}.log 17 | base: 1 18 | count: 5 # 循环记录5个日志文件 19 | 20 | root: 21 | level: info # 日志级别,使用off表示不打日志 22 | appenders: 23 | - rolling_file -------------------------------------------------------------------------------- /flutter_rust_bridge.yaml: -------------------------------------------------------------------------------- 1 | rust_input: rust/src/api/*.rs 2 | dart_output: lib/src/rust -------------------------------------------------------------------------------- /integration_test/simple_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:vnt_app/main.dart'; 3 | import 'package:vnt_app/src/rust/frb_generated.dart'; 4 | import 'package:integration_test/integration_test.dart'; 5 | 6 | void main() { 7 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 8 | setUpAll(() async => await RustLib.init()); 9 | testWidgets('Can call rust function', (WidgetTester tester) async { 10 | await tester.pumpWidget(const VntApp()); 11 | expect(find.textContaining('Result: `Hello, Tom!`'), findsOneWidget); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "size": "20x20", 5 | "idiom": "universal", 6 | "filename": "icon-20@2x.png", 7 | "scale": "2x", 8 | "platform": "ios" 9 | }, 10 | { 11 | "size": "20x20", 12 | "idiom": "universal", 13 | "filename": "icon-20@3x.png", 14 | "scale": "3x", 15 | "platform": "ios" 16 | }, 17 | { 18 | "size": "29x29", 19 | "idiom": "universal", 20 | "filename": "icon-29@2x.png", 21 | "scale": "2x", 22 | "platform": "ios" 23 | }, 24 | { 25 | "size": "29x29", 26 | "idiom": "universal", 27 | "filename": "icon-29@3x.png", 28 | "scale": "3x", 29 | "platform": "ios" 30 | }, 31 | { 32 | "size": "38x38", 33 | "idiom": "universal", 34 | "filename": "icon-38@2x.png", 35 | "scale": "2x", 36 | "platform": "ios" 37 | }, 38 | { 39 | "size": "38x38", 40 | "idiom": "universal", 41 | "filename": "icon-38@3x.png", 42 | "scale": "3x", 43 | "platform": "ios" 44 | }, 45 | { 46 | "size": "40x40", 47 | "idiom": "universal", 48 | "filename": "icon-40@2x.png", 49 | "scale": "2x", 50 | "platform": "ios" 51 | }, 52 | { 53 | "size": "40x40", 54 | "idiom": "universal", 55 | "filename": "icon-40@3x.png", 56 | "scale": "3x", 57 | "platform": "ios" 58 | }, 59 | { 60 | "size": "60x60", 61 | "idiom": "universal", 62 | "filename": "icon-60@2x.png", 63 | "scale": "2x", 64 | "platform": "ios" 65 | }, 66 | { 67 | "size": "60x60", 68 | "idiom": "universal", 69 | "filename": "icon-60@3x.png", 70 | "scale": "3x", 71 | "platform": "ios" 72 | }, 73 | { 74 | "size": "64x64", 75 | "idiom": "universal", 76 | "filename": "icon-64@2x.png", 77 | "scale": "2x", 78 | "platform": "ios" 79 | }, 80 | { 81 | "size": "64x64", 82 | "idiom": "universal", 83 | "filename": "icon-64@3x.png", 84 | "scale": "3x", 85 | "platform": "ios" 86 | }, 87 | { 88 | "size": "68x68", 89 | "idiom": "universal", 90 | "filename": "icon-68@2x.png", 91 | "scale": "2x", 92 | "platform": "ios" 93 | }, 94 | { 95 | "size": "76x76", 96 | "idiom": "universal", 97 | "filename": "icon-76@2x.png", 98 | "scale": "2x", 99 | "platform": "ios" 100 | }, 101 | { 102 | "size": "83.5x83.5", 103 | "idiom": "universal", 104 | "filename": "icon-83.5@2x.png", 105 | "scale": "2x", 106 | "platform": "ios" 107 | }, 108 | { 109 | "size": "1024x1024", 110 | "idiom": "universal", 111 | "filename": "icon-1024.png", 112 | "scale": "1x", 113 | "platform": "ios" 114 | } 115 | ], 116 | "info": { 117 | "version": 1 118 | } 119 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-38@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-38@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-38@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-38@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-64@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-64@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-64@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-64@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-68@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-68@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Vnt App 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | vnt_app 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/about_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:url_launcher/url_launcher.dart'; 3 | 4 | class AboutPage extends StatelessWidget { 5 | const AboutPage({super.key}); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Scaffold( 10 | appBar: AppBar( 11 | title: const Text('关于我们'), 12 | ), 13 | body: Padding( 14 | padding: const EdgeInsets.all(16.0), 15 | child: Center( 16 | child: Column( 17 | mainAxisAlignment: MainAxisAlignment.center, 18 | children: [ 19 | const Text( 20 | '应用说明', 21 | style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), 22 | ), 23 | const SizedBox(height: 20), 24 | const Text( 25 | '这是一个简单高效的组网工具,可以非常方便的进行组网、点对点、点对网通信。', 26 | style: TextStyle(fontSize: 16), 27 | textAlign: TextAlign.center, 28 | ), 29 | const SizedBox(height: 20), 30 | Row( 31 | mainAxisAlignment: MainAxisAlignment.center, 32 | children: [ 33 | const Flexible( 34 | child: SelectableText( 35 | "开放所有源代码 https://github.com/lbl8603/vnt", 36 | style: TextStyle(fontSize: 16), 37 | textAlign: TextAlign.center, 38 | ), 39 | ), 40 | TextButton( 41 | onPressed: () { 42 | launchUrl(Uri.parse('https://github.com/lbl8603/vnt')); 43 | }, 44 | child: const Text('点击跳转'), 45 | ), 46 | ], 47 | ), 48 | const SizedBox(height: 20), 49 | const Text( 50 | '版本号: 1.2.11-预发布版', 51 | style: TextStyle(fontSize: 16), 52 | textAlign: TextAlign.center, 53 | ), 54 | ], 55 | ), 56 | ), 57 | ), 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/connect_log.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'dart:io'; 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | class LogPage extends StatefulWidget { 8 | @override 9 | _LogPageState createState() => _LogPageState(); 10 | } 11 | 12 | class _LogPageState extends State { 13 | final LogReader _logReader = LogReader(File('logs/vnt-core.log')); 14 | final ScrollController _scrollController = ScrollController(); 15 | final List _logLines = []; 16 | bool _isLoading = false; 17 | 18 | @override 19 | void initState() { 20 | super.initState(); 21 | _loadMoreLogs(); 22 | _scrollController.addListener(_onScroll); 23 | } 24 | 25 | Future _loadMoreLogs() async { 26 | if (_isLoading) return; 27 | setState(() => _isLoading = true); 28 | 29 | final newLines = await _logReader.readNextBatch(); 30 | setState(() { 31 | _logLines.addAll(newLines); 32 | _isLoading = false; 33 | }); 34 | } 35 | 36 | void _onScroll() { 37 | if (_scrollController.position.pixels >= 38 | _scrollController.position.maxScrollExtent && 39 | !_isLoading) { 40 | _loadMoreLogs(); 41 | } 42 | } 43 | 44 | @override 45 | void dispose() { 46 | _scrollController.dispose(); 47 | super.dispose(); 48 | } 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | return Scaffold( 53 | appBar: AppBar( 54 | title: const Text('日志'), 55 | // actions: [ 56 | // IconButton( 57 | // icon: const Icon(Icons.download), 58 | // onPressed: _exportLogs, 59 | // ), 60 | // ], 61 | ), 62 | body: Padding( 63 | padding: const EdgeInsets.all(8.0), 64 | child: _buildLogView(), 65 | ), 66 | ); 67 | } 68 | 69 | Widget _buildLogView() { 70 | return ListView.builder( 71 | controller: _scrollController, 72 | itemCount: _logLines.length + (_isLoading ? 1 : 0), 73 | itemBuilder: (context, index) { 74 | if (index >= _logLines.length) { 75 | return const Center(child: CircularProgressIndicator()); 76 | } 77 | 78 | final line = _logLines[index]; 79 | return SelectableText( 80 | line, 81 | style: TextStyle( 82 | color: line.contains('ERROR') ? Colors.red : Colors.black, 83 | ), 84 | ); 85 | }, 86 | ); 87 | } 88 | 89 | void _exportLogs() { 90 | // 实现日志导出功能 91 | } 92 | } 93 | 94 | class LogReader { 95 | final File logFile; 96 | final int batchSize; 97 | int _currentOffset = 0; 98 | 99 | LogReader(this.logFile, {this.batchSize = 100}); 100 | 101 | Future> readNextBatch() async { 102 | final lines = []; 103 | var fileLength = await logFile.length(); 104 | if (_currentOffset >= fileLength) { 105 | // 如果偏移量超过文件长度,说明已经读取完毕 106 | return lines; 107 | } 108 | int bytesRead = 0; 109 | 110 | try { 111 | final fileStream = logFile.openRead(_currentOffset); 112 | await for (var line in fileStream 113 | .transform(const Utf8Decoder(allowMalformed: true)) 114 | .transform(const LineSplitter())) { 115 | lines.add(line); 116 | 117 | bytesRead += utf8.encode(line).length + 1; // 是为了换行符 118 | if (lines.length >= batchSize) { 119 | break; 120 | } 121 | } 122 | } catch (e) { 123 | debugPrint('dart catch e: $fileLength $_currentOffset $e'); 124 | } 125 | 126 | _currentOffset += bytesRead; // 更新偏移量 127 | return lines; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lib/custom_app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { 4 | final Widget title; 5 | final Color backgroundColor; 6 | final List actions; 7 | 8 | const CustomAppBar({super.key, 9 | required this.title, 10 | this.backgroundColor = Colors.blue, 11 | this.actions = const [], 12 | }); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return AppBar( 17 | title: title, 18 | backgroundColor: backgroundColor, 19 | actions: actions, 20 | ); 21 | } 22 | 23 | @override 24 | Size get preferredSize => Size.fromHeight(kToolbarHeight); 25 | } 26 | -------------------------------------------------------------------------------- /lib/data_persistence.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:shared_preferences/shared_preferences.dart'; 3 | import 'network_config.dart'; 4 | import 'dart:convert'; 5 | import 'package:uuid/uuid.dart'; 6 | 7 | class DataPersistence { 8 | static const String dataKey = 'data-key'; 9 | static const String vntUniqueIdKey = 'vnt-unique-id-key'; 10 | 11 | Future saveData(List configs) async { 12 | final prefs = await SharedPreferences.getInstance(); 13 | List jsonDataList = 14 | configs.map((config) => jsonEncode(config.toJson())).toList(); 15 | await prefs.setStringList(dataKey, jsonDataList); 16 | } 17 | 18 | Future> loadData() async { 19 | final prefs = await SharedPreferences.getInstance(); 20 | List? jsonDataList = prefs.getStringList(dataKey); 21 | 22 | if (jsonDataList != null) { 23 | return jsonDataList 24 | .map((jsonData) => NetworkConfig.fromJson(jsonDecode(jsonData))) 25 | .toList(); 26 | } else { 27 | return []; 28 | } 29 | } 30 | 31 | Future loadUniqueId() async { 32 | final prefs = await SharedPreferences.getInstance(); 33 | String? uniqueId = prefs.getString(vntUniqueIdKey); 34 | if (uniqueId == null || uniqueId.isEmpty) { 35 | uniqueId = const Uuid().v4().toString(); 36 | prefs.setString(vntUniqueIdKey, uniqueId); 37 | } 38 | return uniqueId; 39 | } 40 | 41 | Future loadWindowSize() async { 42 | final prefs = await SharedPreferences.getInstance(); 43 | final width = prefs.getDouble('window-width'); 44 | final height = prefs.getDouble('window-height'); 45 | if (width != null && height != null) { 46 | return Size(width, height); 47 | } 48 | return const Size(600, 700); 49 | } 50 | 51 | Future saveWindowSize(Size size) async { 52 | if (size.width == 600 && size.height == 700) { 53 | return; 54 | } 55 | final prefs = await SharedPreferences.getInstance(); 56 | await prefs.setDouble('window-width', size.width); 57 | await prefs.setDouble('window-height', size.height); 58 | } 59 | 60 | Future loadCloseApp() async { 61 | final prefs = await SharedPreferences.getInstance(); 62 | return prefs.getBool('is-close-app'); 63 | } 64 | 65 | Future saveCloseApp(bool isClose) async { 66 | final prefs = await SharedPreferences.getInstance(); 67 | prefs.setBool('is-close-app', isClose); 68 | } 69 | 70 | Future loadAutoStart() async { 71 | final prefs = await SharedPreferences.getInstance(); 72 | return prefs.getBool('is-auto-start'); 73 | } 74 | 75 | Future saveAutoStart(bool autoStart) async { 76 | final prefs = await SharedPreferences.getInstance(); 77 | prefs.setBool('is-auto-start', autoStart); 78 | } 79 | 80 | Future loadAutoConnect() async { 81 | final prefs = await SharedPreferences.getInstance(); 82 | return prefs.getString('auto-connect-key'); 83 | } 84 | 85 | Future saveAutoConnect(String autoConnect) async { 86 | final prefs = await SharedPreferences.getInstance(); 87 | prefs.setString('auto-connect-key', autoConnect); 88 | } 89 | 90 | Future clear() async { 91 | final prefs = await SharedPreferences.getInstance(); 92 | prefs.clear(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/utils/ip_utils.dart: -------------------------------------------------------------------------------- 1 | class Ipv4Addr { 2 | final String address; 3 | 4 | Ipv4Addr(this.address); 5 | 6 | static Ipv4Addr? tryParse(String input) { 7 | final regex = RegExp( 8 | r'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'); 9 | if (regex.hasMatch(input)) { 10 | return Ipv4Addr(input); 11 | } else { 12 | return null; 13 | } 14 | } 15 | 16 | List octets() { 17 | return address.split('.').map((e) => int.parse(e)).toList(); 18 | } 19 | 20 | int toInt() { 21 | final octets = this.octets(); 22 | return (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]; 23 | } 24 | 25 | static String fromInt(int ip) { 26 | final octet1 = (ip >> 24) & 0xFF; 27 | final octet2 = (ip >> 16) & 0xFF; 28 | final octet3 = (ip >> 8) & 0xFF; 29 | final octet4 = ip & 0xFF; 30 | return '$octet1.$octet2.$octet3.$octet4'; 31 | } 32 | 33 | @override 34 | String toString() { 35 | return address; 36 | } 37 | } 38 | 39 | class IpUtils { 40 | static String toInIpString(int dest, int mask, String ip) { 41 | return '${Ipv4Addr.fromInt(dest).toString()}/${_countBits(mask)},${ip}'; 42 | } 43 | 44 | static (int, int, String) parseInIpString(String input) { 45 | final parts = input.split(","); 46 | if (parts.length != 2) { 47 | throw Exception("格式错误: $input"); 48 | } 49 | 50 | final netPart = parts[0]; 51 | final ipPart = parts[1]; 52 | 53 | final ip = Ipv4Addr.tryParse(ipPart); 54 | if (ip == null) { 55 | throw Exception("无效的 IP 地址: $ipPart"); 56 | } 57 | 58 | final netParts = netPart.split("/"); 59 | if (netParts.length != 2) { 60 | throw Exception("无效的网络格式: $netPart"); 61 | } 62 | 63 | final destPart = netParts[0]; 64 | final maskPart = netParts[1]; 65 | 66 | final dest = Ipv4Addr.tryParse(destPart); 67 | if (dest == null) { 68 | throw Exception("无效的目的Ipv4: $destPart"); 69 | } 70 | 71 | final mask = toIp(maskPart); 72 | 73 | return (_toU32(dest.octets()), mask, ip.toString()); 74 | } 75 | 76 | static String toOutIpString(int dest, int mask) { 77 | return '${Ipv4Addr.fromInt(dest).toString()}/${_countBits(mask)}'; 78 | } 79 | 80 | static (int, int) parseOutIpString(String netPart) { 81 | final netParts = netPart.split("/"); 82 | if (netParts.length != 2) { 83 | throw Exception("无效的网络格式: $netPart"); 84 | } 85 | 86 | final destPart = netParts[0]; 87 | final maskPart = netParts[1]; 88 | 89 | final dest = Ipv4Addr.tryParse(destPart); 90 | if (dest == null) { 91 | throw Exception("无效的目的Ipv4: $destPart"); 92 | } 93 | 94 | final mask = toIp(maskPart); 95 | 96 | return (_toU32(dest.octets()), mask); 97 | } 98 | 99 | static int toIp(String mask) { 100 | try { 101 | int maskInt = int.parse(mask); 102 | return (0xFFFFFFFF << (32 - maskInt)) & 0xFFFFFFFF; 103 | } catch (e) { 104 | throw Exception("无效掩码: $mask"); 105 | } 106 | } 107 | 108 | static int _toU32(List octets) { 109 | if (octets.length != 4) { 110 | throw Exception("无效的 IPv4 地址"); 111 | } 112 | return (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3]; 113 | } 114 | 115 | static int _countBits(int octet) { 116 | int count = 0; 117 | while (octet > 0) { 118 | count += octet & 1; 119 | octet >>= 1; 120 | } 121 | return count; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /lib/widgets/color_changing_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:async'; 3 | 4 | class ColorChangingButton extends StatefulWidget { 5 | final IconData icon; 6 | final List colors; 7 | final VoidCallback onPressed; 8 | 9 | const ColorChangingButton({super.key, 10 | required this.icon, 11 | required this.colors, 12 | required this.onPressed, 13 | }); 14 | 15 | @override 16 | _ColorChangingButtonState createState() => _ColorChangingButtonState(); 17 | } 18 | 19 | class _ColorChangingButtonState extends State { 20 | late Timer _timer; 21 | late Color _currentColor; 22 | int _currentIndex = 0; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | _currentColor = widget.colors[_currentIndex]; 28 | _startColorChange(); 29 | } 30 | 31 | void _startColorChange() { 32 | _timer = Timer.periodic(const Duration(seconds: 1), (timer) { 33 | setState(() { 34 | _currentIndex = (_currentIndex + 1) % widget.colors.length; 35 | _currentColor = widget.colors[_currentIndex]; 36 | }); 37 | }); 38 | } 39 | 40 | @override 41 | void dispose() { 42 | _timer.cancel(); 43 | super.dispose(); 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | return IconButton( 49 | icon: Icon(widget.icon, color: _currentColor), 50 | onPressed: widget.onPressed, 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/widgets/custom_tooltip_text_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomTooltipTextField extends StatefulWidget { 4 | final TextEditingController controller; 5 | final String labelText; 6 | final String tooltipMessage; 7 | final int maxLength; 8 | final String? Function(String?)? validator; 9 | 10 | const CustomTooltipTextField({ 11 | super.key, 12 | required this.controller, 13 | required this.labelText, 14 | required this.tooltipMessage, 15 | this.maxLength = 32, 16 | this.validator, 17 | }); 18 | 19 | @override 20 | _CustomTooltipTextFieldState createState() => _CustomTooltipTextFieldState(); 21 | } 22 | 23 | class _CustomTooltipTextFieldState extends State { 24 | final FocusNode _focusNode = FocusNode(); 25 | bool _showTooltip = false; 26 | String? _errorText; 27 | 28 | @override 29 | void initState() { 30 | super.initState(); 31 | _focusNode.addListener(() { 32 | setState(() { 33 | _showTooltip = _focusNode.hasFocus; 34 | if (!_focusNode.hasFocus && widget.validator != null) { 35 | setState(() { 36 | _errorText = widget.validator!(widget.controller.text); 37 | }); 38 | } 39 | }); 40 | }); 41 | } 42 | 43 | @override 44 | void dispose() { 45 | _focusNode.dispose(); 46 | super.dispose(); 47 | } 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | return Column( 52 | crossAxisAlignment: CrossAxisAlignment.start, 53 | children: [ 54 | if (_showTooltip) 55 | Text( 56 | '${widget.labelText} ${widget.tooltipMessage}', 57 | style: const TextStyle(color: Colors.black, fontSize: 13), 58 | ), 59 | TextFormField( 60 | controller: widget.controller, 61 | validator: widget.validator, 62 | focusNode: _focusNode, 63 | decoration: InputDecoration( 64 | labelText: !_showTooltip ? widget.labelText : null, 65 | errorText: _errorText, 66 | ), 67 | maxLength: widget.maxLength, 68 | ), 69 | ], 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/widgets/legend_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class LegendWidget extends StatelessWidget { 4 | const LegendWidget({ 5 | super.key, 6 | required this.name, 7 | required this.color, 8 | }); 9 | final String name; 10 | final Color color; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Row( 15 | mainAxisSize: MainAxisSize.min, 16 | children: [ 17 | Container( 18 | width: 10, 19 | height: 10, 20 | decoration: BoxDecoration( 21 | shape: BoxShape.circle, 22 | color: color, 23 | ), 24 | ), 25 | const SizedBox(width: 6), 26 | Text( 27 | name, 28 | style: const TextStyle( 29 | color: Color(0xff757391), 30 | fontSize: 12, 31 | ), 32 | ), 33 | ], 34 | ); 35 | } 36 | } 37 | 38 | class LegendsListWidget extends StatelessWidget { 39 | const LegendsListWidget({ 40 | super.key, 41 | required this.legends, 42 | }); 43 | final List legends; 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return Wrap( 48 | spacing: 16, 49 | children: legends 50 | .map( 51 | (e) => LegendWidget( 52 | name: e.name, 53 | color: e.color, 54 | ), 55 | ) 56 | .toList(), 57 | ); 58 | } 59 | } 60 | 61 | class Legend { 62 | Legend(this.name, this.color); 63 | final String name; 64 | final Color color; 65 | } -------------------------------------------------------------------------------- /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | 12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 13 | # which isn't available in 3.10. 14 | function(list_prepend LIST_NAME PREFIX) 15 | set(NEW_LIST "") 16 | foreach(element ${${LIST_NAME}}) 17 | list(APPEND NEW_LIST "${PREFIX}${element}") 18 | endforeach(element) 19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 20 | endfunction() 21 | 22 | # === Flutter Library === 23 | # System-level dependencies. 24 | find_package(PkgConfig REQUIRED) 25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 28 | 29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 30 | 31 | # Published to parent scope for install step. 32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 36 | 37 | list(APPEND FLUTTER_LIBRARY_HEADERS 38 | "fl_basic_message_channel.h" 39 | "fl_binary_codec.h" 40 | "fl_binary_messenger.h" 41 | "fl_dart_project.h" 42 | "fl_engine.h" 43 | "fl_json_message_codec.h" 44 | "fl_json_method_codec.h" 45 | "fl_message_codec.h" 46 | "fl_method_call.h" 47 | "fl_method_channel.h" 48 | "fl_method_codec.h" 49 | "fl_method_response.h" 50 | "fl_plugin_registrar.h" 51 | "fl_plugin_registry.h" 52 | "fl_standard_message_codec.h" 53 | "fl_standard_method_codec.h" 54 | "fl_string_codec.h" 55 | "fl_value.h" 56 | "fl_view.h" 57 | "flutter_linux.h" 58 | ) 59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 60 | add_library(flutter INTERFACE) 61 | target_include_directories(flutter INTERFACE 62 | "${EPHEMERAL_DIR}" 63 | ) 64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 65 | target_link_libraries(flutter INTERFACE 66 | PkgConfig::GTK 67 | PkgConfig::GLIB 68 | PkgConfig::GIO 69 | ) 70 | add_dependencies(flutter flutter_assemble) 71 | 72 | # === Flutter tool backend === 73 | # _phony_ is a non-existent file to force this command to run every time, 74 | # since currently there's no way to get a full input/output list from the 75 | # flutter tool. 76 | add_custom_command( 77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 79 | COMMAND ${CMAKE_COMMAND} -E env 80 | ${FLUTTER_TOOL_ENVIRONMENT} 81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} 83 | VERBATIM 84 | ) 85 | add_custom_target(flutter_assemble DEPENDS 86 | "${FLUTTER_LIBRARY}" 87 | ${FLUTTER_LIBRARY_HEADERS} 88 | ) 89 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void fl_register_plugins(FlPluginRegistry* registry) { 16 | g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar = 17 | fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin"); 18 | bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar); 19 | g_autoptr(FlPluginRegistrar) screen_retriever_registrar = 20 | fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); 21 | screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); 22 | g_autoptr(FlPluginRegistrar) system_tray_registrar = 23 | fl_plugin_registry_get_registrar_for_plugin(registry, "SystemTrayPlugin"); 24 | system_tray_plugin_register_with_registrar(system_tray_registrar); 25 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 26 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 27 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 28 | g_autoptr(FlPluginRegistrar) window_manager_registrar = 29 | fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); 30 | window_manager_plugin_register_with_registrar(window_manager_registrar); 31 | } 32 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | bitsdojo_window_linux 7 | screen_retriever 8 | system_tray 9 | url_launcher_linux 10 | window_manager 11 | ) 12 | 13 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 14 | rust_lib_vnt_app 15 | ) 16 | 17 | set(PLUGIN_BUNDLED_LIBRARIES) 18 | 19 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 20 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 21 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 24 | endforeach(plugin) 25 | 26 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 27 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 28 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 29 | endforeach(ffi_plugin) 30 | -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen* screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "vnt_app"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } else { 47 | gtk_window_set_title(window, "vnt_app"); 48 | } 49 | 50 | gtk_window_set_default_size(window, 1280, 720); 51 | gtk_widget_show(GTK_WIDGET(window)); 52 | 53 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 55 | 56 | FlView* view = fl_view_new(project); 57 | gtk_widget_show(GTK_WIDGET(view)); 58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 59 | 60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 61 | 62 | gtk_widget_grab_focus(GTK_WIDGET(view)); 63 | } 64 | 65 | // Implements GApplication::local_command_line. 66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { 67 | MyApplication* self = MY_APPLICATION(application); 68 | // Strip out the first argument as it is the binary name. 69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 70 | 71 | g_autoptr(GError) error = nullptr; 72 | if (!g_application_register(application, nullptr, &error)) { 73 | g_warning("Failed to register: %s", error->message); 74 | *exit_status = 1; 75 | return TRUE; 76 | } 77 | 78 | g_application_activate(application); 79 | *exit_status = 0; 80 | 81 | return TRUE; 82 | } 83 | 84 | // Implements GApplication::startup. 85 | static void my_application_startup(GApplication* application) { 86 | //MyApplication* self = MY_APPLICATION(object); 87 | 88 | // Perform any actions required at application startup. 89 | 90 | G_APPLICATION_CLASS(my_application_parent_class)->startup(application); 91 | } 92 | 93 | // Implements GApplication::shutdown. 94 | static void my_application_shutdown(GApplication* application) { 95 | //MyApplication* self = MY_APPLICATION(object); 96 | 97 | // Perform any actions required at application shutdown. 98 | 99 | G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); 100 | } 101 | 102 | // Implements GObject::dispose. 103 | static void my_application_dispose(GObject* object) { 104 | MyApplication* self = MY_APPLICATION(object); 105 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 106 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 107 | } 108 | 109 | static void my_application_class_init(MyApplicationClass* klass) { 110 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 111 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 112 | G_APPLICATION_CLASS(klass)->startup = my_application_startup; 113 | G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; 114 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 115 | } 116 | 117 | static void my_application_init(MyApplication* self) {} 118 | 119 | MyApplication* my_application_new() { 120 | return MY_APPLICATION(g_object_new(my_application_get_type(), 121 | "application-id", APPLICATION_ID, 122 | "flags", G_APPLICATION_NON_UNIQUE, 123 | nullptr)); 124 | } 125 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import bitsdojo_window_macos 9 | import device_info_plus 10 | import path_provider_foundation 11 | import screen_retriever 12 | import shared_preferences_foundation 13 | import system_tray 14 | import url_launcher_macos 15 | import window_manager 16 | 17 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 18 | BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin")) 19 | DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) 20 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 21 | ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) 22 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 23 | SystemTrayPlugin.register(with: registry.registrar(forPlugin: "SystemTrayPlugin")) 24 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 25 | WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) 26 | } 27 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "size": "16x16", 5 | "idiom": "mac", 6 | "filename": "icon-16.png", 7 | "scale": "1x" 8 | }, 9 | { 10 | "size": "16x16", 11 | "idiom": "mac", 12 | "filename": "icon-16@2x.png", 13 | "scale": "2x" 14 | }, 15 | { 16 | "size": "32x32", 17 | "idiom": "mac", 18 | "filename": "icon-32.png", 19 | "scale": "1x" 20 | }, 21 | { 22 | "size": "32x32", 23 | "idiom": "mac", 24 | "filename": "icon-32@2x.png", 25 | "scale": "2x" 26 | }, 27 | { 28 | "size": "128x128", 29 | "idiom": "mac", 30 | "filename": "icon-128.png", 31 | "scale": "1x" 32 | }, 33 | { 34 | "size": "128x128", 35 | "idiom": "mac", 36 | "filename": "icon-128@2x.png", 37 | "scale": "2x" 38 | }, 39 | { 40 | "size": "256x256", 41 | "idiom": "mac", 42 | "filename": "icon-256.png", 43 | "scale": "1x" 44 | }, 45 | { 46 | "size": "256x256", 47 | "idiom": "mac", 48 | "filename": "icon-256@2x.png", 49 | "scale": "2x" 50 | }, 51 | { 52 | "size": "512x512", 53 | "idiom": "mac", 54 | "filename": "icon-512.png", 55 | "scale": "1x" 56 | }, 57 | { 58 | "size": "512x512", 59 | "idiom": "mac", 60 | "filename": "icon-512@2x.png", 61 | "scale": "2x" 62 | } 63 | ], 64 | "info": { 65 | "version": 1 66 | } 67 | } -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-128@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-16@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-256@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-32@2x.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-512.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/macos/Runner/Assets.xcassets/AppIcon.appiconset/icon-512@2x.png -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = vnt_app 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = top.wherewego.vntApp 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2024 top.wherewego. All rights reserved. 15 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | com.apple.security.network.client 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: vnt_app 2 | description: "A new Flutter project." 3 | # The following line prevents the package from being accidentally published to 4 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 5 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 6 | 7 | # The following defines the version and build number for your application. 8 | # A version number is three numbers separated by dots, like 1.2.43 9 | # followed by an optional build number separated by a +. 10 | # Both the version and the builder number may be overridden in flutter 11 | # build by specifying --build-name and --build-number, respectively. 12 | # In Android, build-name is used as versionName while build-number used as versionCode. 13 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 14 | # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. 15 | # Read more about iOS versioning at 16 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 17 | # In Windows, build-name is used as the major, minor, and patch parts 18 | # of the product and file versions while build-number is used as the build suffix. 19 | version: 1.0.0+1 20 | 21 | environment: 22 | sdk: '>=3.4.0 <4.0.0' 23 | 24 | # Dependencies specify other packages that your package needs in order to work. 25 | # To automatically upgrade your package dependencies to the latest versions 26 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 27 | # dependencies can be manually updated by changing the version numbers below to 28 | # the latest version available on pub.dev. To see which dependencies have newer 29 | # versions available, run `flutter pub outdated`. 30 | dependencies: 31 | flutter: 32 | sdk: flutter 33 | 34 | 35 | # The following adds the Cupertino Icons font to your application. 36 | # Use with the CupertinoIcons class for iOS style icons. 37 | cupertino_icons: ^1.0.6 38 | device_info_plus: ^10.0.0 39 | shared_preferences: ^2.0.0 40 | rust_lib_vnt_app: 41 | path: rust_builder 42 | flutter_rust_bridge: 2.0.0-dev.37 43 | path_provider: ^2.1.3 44 | yaml: ^3.1.0 45 | json2yaml: ^3.0.1 46 | url_launcher: ^6.2.6 47 | system_tray: ^2.0.3 48 | bitsdojo_window: ^0.1.6 49 | window_manager: ^0.3.9 50 | synchronized: ^3.0.0 51 | fl_chart: ^0.68.0 52 | dev_dependencies: 53 | flutter_test: 54 | sdk: flutter 55 | 56 | # The "flutter_lints" package below contains a set of recommended lints to 57 | # encourage good coding practices. The lint set provided by the package is 58 | # activated in the `analysis_options.yaml` file located at the root of your 59 | # package. See that file for information about deactivating specific lint 60 | # rules and activating additional ones. 61 | flutter_lints: ^3.0.0 62 | integration_test: 63 | sdk: flutter 64 | 65 | # For information on the generic Dart part of this file, see the 66 | # following page: https://dart.dev/tools/pub/pubspec 67 | 68 | # The following section is specific to Flutter packages. 69 | flutter: 70 | 71 | # The following line ensures that the Material Icons font is 72 | # included with your application, so that you can use the icons in 73 | # the material Icons class. 74 | uses-material-design: true 75 | 76 | # To add assets to your application, add an assets section, like this: 77 | # assets: 78 | # - images/a_dot_burr.jpeg 79 | # - images/a_dot_ham.jpeg 80 | 81 | # An image asset can refer to one or more resolution-specific "variants", see 82 | # https://flutter.dev/assets-and-images/#resolution-aware 83 | 84 | # For details regarding adding assets from package dependencies, see 85 | # https://flutter.dev/assets-and-images/#from-packages 86 | 87 | # To add custom fonts to your application, add a fonts section here, 88 | # in this "flutter" section. Each entry in this list should have a 89 | # "family" key with the font family name, and a "fonts" key with a 90 | # list giving the asset and other descriptors for the font. For 91 | # example: 92 | # fonts: 93 | # - family: Schyler 94 | # fonts: 95 | # - asset: fonts/Schyler-Regular.ttf 96 | # - asset: fonts/Schyler-Italic.ttf 97 | # style: italic 98 | # - family: Trajan Pro 99 | # fonts: 100 | # - asset: fonts/TrajanPro.ttf 101 | # - asset: fonts/TrajanPro_Bold.ttf 102 | # weight: 700 103 | # 104 | # For details regarding fonts from package dependencies, 105 | # see https://flutter.dev/custom-fonts/#from-packages 106 | 107 | assets: 108 | - assets/app_icon.ico 109 | - assets/app_icon.png 110 | - assets/log4rs.yaml -------------------------------------------------------------------------------- /rust/.cargo/config: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-musl] 2 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 3 | [target.aarch64-unknown-linux-musl] 4 | linker = "aarch64-linux-musl-gcc" 5 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 6 | [target.armv7-unknown-linux-musleabihf] 7 | linker = "armv7l-linux-musleabihf-gcc" 8 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 9 | [target.armv7-unknown-linux-musleabi] 10 | linker = "armv7m-linux-musleabi-gcc" 11 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 12 | [target.arm-unknown-linux-musleabihf] 13 | linker = "arm-linux-musleabihf-gcc" 14 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 15 | [target.arm-unknown-linux-musleabi] 16 | linker = "arm-linux-musleabi-gcc" 17 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 18 | [target.mipsel-unknown-linux-musl] 19 | linker = "mipsel-linux-musl-gcc" 20 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 21 | [target.mips-unknown-linux-musl] 22 | linker = "mips-linux-musl-gcc" 23 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 24 | [target.x86_64-pc-windows-msvc] 25 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 26 | [target.i686-pc-windows-msvc] 27 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 28 | [target.x86_64-apple-darwin] 29 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 30 | [target.aarch64-apple-darwin] 31 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 32 | [target.i686-unknown-linux-musl] 33 | rustflags = ["-C", "target-feature=+crt-static", "-C", "strip=symbols"] 34 | 35 | 36 | [target.armv7-linux-androideabi] 37 | ar = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/arm-linux-androideabi-ar" 38 | linker = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/armv7a-linux-androideabi21-clang" 39 | 40 | [target.aarch64-linux-android] 41 | ar = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android-ar" 42 | linker = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang" 43 | 44 | [target.i686-linux-android] 45 | ar = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/i686-linux-android-ar" 46 | linker = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/i686-linux-android21-clang" 47 | 48 | [target.x86_64-linux-android] 49 | ar = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/x86_64-linux-android-ar" 50 | linker = "D:/android/android-ndk-r26d-windows/android-ndk-r26d/toolchains/llvm/prebuilt/windows-x86_64/bin/x86_64-linux-android21-clang" 51 | -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust_lib_vnt_app" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | crate-type = ["staticlib", "cdylib"] 8 | 9 | [dependencies] 10 | 11 | serde = { version = "1.0", features = ["derive"] } 12 | flutter_rust_bridge = "=2.0.0-dev.37" 13 | vnt = { git = "https://github.com/lbl8603/vnt.git", branch = "1.2.x", features = ["ring-cipher", "wss"] } 14 | anyhow = "1.0.82" 15 | tokio = { version = "1.37.0", features = ["full"] } 16 | 17 | log = "0.4.17" 18 | log4rs = "1.2.0" 19 | 20 | 21 | [target.'cfg(target_os = "android")'.dependencies] 22 | android_logger = "0.13" 23 | -------------------------------------------------------------------------------- /rust/src/api/mod.rs: -------------------------------------------------------------------------------- 1 | // 2 | // Do not put code in `mod.rs`, but put in e.g. `simple.rs`. 3 | // 4 | 5 | pub mod vnt_api; 6 | -------------------------------------------------------------------------------- /rust/src/frb_generated.io.rs: -------------------------------------------------------------------------------- 1 | // This file is automatically generated, so please do not edit it. 2 | // Generated by `flutter_rust_bridge`@ 2.0.0-dev.37. 3 | 4 | // Section: imports 5 | 6 | use super::*; 7 | use crate::api::vnt_api::*; 8 | use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; 9 | use flutter_rust_bridge::for_generated::transform_result_dco; 10 | use flutter_rust_bridge::{Handler, IntoIntoDart}; 11 | 12 | // Section: boilerplate 13 | 14 | flutter_rust_bridge::frb_generated_boilerplate_io!(); 15 | 16 | #[no_mangle] 17 | pub extern "C" fn frbgen_vnt_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApi( 18 | ptr: *const std::ffi::c_void, 19 | ) { 20 | MoiArc::>::increment_strong_count(ptr as _); 21 | } 22 | 23 | #[no_mangle] 24 | pub extern "C" fn frbgen_vnt_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApi( 25 | ptr: *const std::ffi::c_void, 26 | ) { 27 | MoiArc::>::decrement_strong_count(ptr as _); 28 | } 29 | 30 | #[no_mangle] 31 | pub extern "C" fn frbgen_vnt_app_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApiCallback( 32 | ptr: *const std::ffi::c_void, 33 | ) { 34 | MoiArc::>::increment_strong_count(ptr as _); 35 | } 36 | 37 | #[no_mangle] 38 | pub extern "C" fn frbgen_vnt_app_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApiCallback( 39 | ptr: *const std::ffi::c_void, 40 | ) { 41 | MoiArc::>::decrement_strong_count(ptr as _); 42 | } 43 | -------------------------------------------------------------------------------- /rust/src/frb_generated.web.rs: -------------------------------------------------------------------------------- 1 | // This file is automatically generated, so please do not edit it. 2 | // Generated by `flutter_rust_bridge`@ 2.0.0-dev.37. 3 | 4 | // Section: imports 5 | 6 | use super::*; 7 | use crate::api::vnt_api::*; 8 | use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; 9 | use flutter_rust_bridge::for_generated::transform_result_dco; 10 | use flutter_rust_bridge::for_generated::wasm_bindgen; 11 | use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; 12 | use flutter_rust_bridge::{Handler, IntoIntoDart}; 13 | 14 | // Section: boilerplate 15 | 16 | flutter_rust_bridge::frb_generated_boilerplate_web!(); 17 | 18 | #[wasm_bindgen] 19 | pub fn rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApi( 20 | ptr: *const std::ffi::c_void, 21 | ) { 22 | MoiArc::>::increment_strong_count(ptr as _); 23 | } 24 | 25 | #[wasm_bindgen] 26 | pub fn rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApi( 27 | ptr: *const std::ffi::c_void, 28 | ) { 29 | MoiArc::>::decrement_strong_count(ptr as _); 30 | } 31 | 32 | #[wasm_bindgen] 33 | pub fn rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApiCallback( 34 | ptr: *const std::ffi::c_void, 35 | ) { 36 | MoiArc::>::increment_strong_count(ptr as _); 37 | } 38 | 39 | #[wasm_bindgen] 40 | pub fn rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerVntApiCallback( 41 | ptr: *const std::ffi::c_void, 42 | ) { 43 | MoiArc::>::decrement_strong_count(ptr as _); 44 | } 45 | -------------------------------------------------------------------------------- /rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod api; 2 | mod frb_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */ 3 | -------------------------------------------------------------------------------- /rust_builder/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | build/ 30 | -------------------------------------------------------------------------------- /rust_builder/README.md: -------------------------------------------------------------------------------- 1 | Please ignore this folder, which is just glue to build Rust with Flutter. -------------------------------------------------------------------------------- /rust_builder/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .cxx 10 | -------------------------------------------------------------------------------- /rust_builder/android/build.gradle: -------------------------------------------------------------------------------- 1 | // The Android Gradle Plugin builds the native code with the Android NDK. 2 | 3 | group 'com.flutter_rust_bridge.rust_lib_vnt_app' 4 | version '1.0' 5 | 6 | buildscript { 7 | repositories { 8 | google() 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | // The Android Gradle Plugin knows how to build native code with the NDK. 14 | classpath 'com.android.tools.build:gradle:7.3.0' 15 | } 16 | } 17 | 18 | rootProject.allprojects { 19 | repositories { 20 | google() 21 | mavenCentral() 22 | } 23 | } 24 | 25 | apply plugin: 'com.android.library' 26 | 27 | android { 28 | if (project.android.hasProperty("namespace")) { 29 | namespace 'com.flutter_rust_bridge.rust_lib_vnt_app' 30 | } 31 | 32 | // Bumping the plugin compileSdkVersion requires all clients of this plugin 33 | // to bump the version in their app. 34 | compileSdkVersion 33 35 | 36 | // Use the NDK version 37 | // declared in /android/app/build.gradle file of the Flutter project. 38 | // Replace it with a version number if this plugin requires a specfic NDK version. 39 | // (e.g. ndkVersion "23.1.7779620") 40 | ndkVersion android.ndkVersion 41 | 42 | compileOptions { 43 | sourceCompatibility JavaVersion.VERSION_1_8 44 | targetCompatibility JavaVersion.VERSION_1_8 45 | } 46 | 47 | defaultConfig { 48 | minSdkVersion 19 49 | } 50 | } 51 | 52 | apply from: "../cargokit/gradle/plugin.gradle" 53 | cargokit { 54 | manifestDir = "../../rust" 55 | libname = "rust_lib_vnt_app" 56 | } 57 | -------------------------------------------------------------------------------- /rust_builder/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'rust_lib_vnt_app' 2 | -------------------------------------------------------------------------------- /rust_builder/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /rust_builder/cargokit/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .dart_tool 3 | *.iml 4 | !pubspec.lock 5 | -------------------------------------------------------------------------------- /rust_builder/cargokit/LICENSE: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | Copyright 2022 Matej Knopp 5 | 6 | ================================================================================ 7 | 8 | MIT LICENSE 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14 | of the Software, and to permit persons to whom the Software is furnished to do 15 | so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 22 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 23 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | ================================================================================ 28 | 29 | APACHE LICENSE, VERSION 2.0 30 | 31 | Licensed under the Apache License, Version 2.0 (the "License"); 32 | you may not use this file except in compliance with the License. 33 | You may obtain a copy of the License at 34 | 35 | http://www.apache.org/licenses/LICENSE-2.0 36 | 37 | Unless required by applicable law or agreed to in writing, software 38 | distributed under the License is distributed on an "AS IS" BASIS, 39 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 40 | See the License for the specific language governing permissions and 41 | limitations under the License. 42 | 43 | -------------------------------------------------------------------------------- /rust_builder/cargokit/README: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | Experimental repository to provide glue for seamlessly integrating cargo build 5 | with flutter plugins and packages. 6 | 7 | See https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/ 8 | for a tutorial on how to use Cargokit. 9 | 10 | Example plugin available at https://github.com/irondash/hello_rust_ffi_plugin. 11 | 12 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_pod.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | BASEDIR=$(dirname "$0") 5 | 6 | # Workaround for https://github.com/dart-lang/pub/issues/4010 7 | BASEDIR=$(cd "$BASEDIR" ; pwd -P) 8 | 9 | # Remove XCode SDK from path. Otherwise this breaks tool compilation when building iOS project 10 | NEW_PATH=`echo $PATH | tr ":" "\n" | grep -v "Contents/Developer/" | tr "\n" ":"` 11 | 12 | export PATH=${NEW_PATH%?} # remove trailing : 13 | 14 | env 15 | 16 | # Platform name (macosx, iphoneos, iphonesimulator) 17 | export CARGOKIT_DARWIN_PLATFORM_NAME=$PLATFORM_NAME 18 | 19 | # Arctive architectures (arm64, armv7, x86_64), space separated. 20 | export CARGOKIT_DARWIN_ARCHS=$ARCHS 21 | 22 | # Current build configuration (Debug, Release) 23 | export CARGOKIT_CONFIGURATION=$CONFIGURATION 24 | 25 | # Path to directory containing Cargo.toml. 26 | export CARGOKIT_MANIFEST_DIR=$PODS_TARGET_SRCROOT/$1 27 | 28 | # Temporary directory for build artifacts. 29 | export CARGOKIT_TARGET_TEMP_DIR=$TARGET_TEMP_DIR 30 | 31 | # Output directory for final artifacts. 32 | export CARGOKIT_OUTPUT_DIR=$PODS_CONFIGURATION_BUILD_DIR/$PRODUCT_NAME 33 | 34 | # Directory to store built tool artifacts. 35 | export CARGOKIT_TOOL_TEMP_DIR=$TARGET_TEMP_DIR/build_tool 36 | 37 | # Directory inside root project. Not necessarily the top level directory of root project. 38 | export CARGOKIT_ROOT_PROJECT_DIR=$SRCROOT 39 | 40 | FLUTTER_EXPORT_BUILD_ENVIRONMENT=( 41 | "$PODS_ROOT/../Flutter/ephemeral/flutter_export_environment.sh" # macOS 42 | "$PODS_ROOT/../Flutter/flutter_export_environment.sh" # iOS 43 | ) 44 | 45 | for path in "${FLUTTER_EXPORT_BUILD_ENVIRONMENT[@]}" 46 | do 47 | if [[ -f "$path" ]]; then 48 | source "$path" 49 | fi 50 | done 51 | 52 | sh "$BASEDIR/run_build_tool.sh" build-pod "$@" 53 | 54 | # Make a symlink from built framework to phony file, which will be used as input to 55 | # build script. This should force rebuild (podspec currently doesn't support alwaysOutOfDate 56 | # attribute on custom build phase) 57 | ln -fs "$OBJROOT/XCBuildData/build.db" "${BUILT_PRODUCTS_DIR}/cargokit_phony" 58 | ln -fs "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/cargokit_phony_out" 59 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/README.md: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | A sample command-line application with an entrypoint in `bin/`, library code 5 | in `lib/`, and example unit test in `test/`. 6 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This is copied from Cargokit (which is the official way to use it currently) 2 | # Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | # This file configures the static analysis results for your project (errors, 5 | # warnings, and lints). 6 | # 7 | # This enables the 'recommended' set of lints from `package:lints`. 8 | # This set helps identify many issues that may lead to problems when running 9 | # or consuming Dart code, and enforces writing Dart using a single, idiomatic 10 | # style and format. 11 | # 12 | # If you want a smaller set of lints you can change this to specify 13 | # 'package:lints/core.yaml'. These are just the most critical lints 14 | # (the recommended set includes the core lints). 15 | # The core lints are also what is used by pub.dev for scoring packages. 16 | 17 | include: package:lints/recommended.yaml 18 | 19 | # Uncomment the following section to specify additional rules. 20 | 21 | linter: 22 | rules: 23 | - prefer_relative_imports 24 | - directives_ordering 25 | 26 | # analyzer: 27 | # exclude: 28 | # - path/to/excluded/files/** 29 | 30 | # For more information about the core and recommended set of lints, see 31 | # https://dart.dev/go/core-lints 32 | 33 | # For additional information about configuring this file, see 34 | # https://dart.dev/guides/language/analysis-options 35 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/bin/build_tool.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'package:build_tool/build_tool.dart' as build_tool; 5 | 6 | void main(List arguments) { 7 | build_tool.runMain(arguments); 8 | } 9 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/build_tool.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'src/build_tool.dart' as build_tool; 5 | 6 | Future runMain(List args) async { 7 | return build_tool.runMain(args); 8 | } 9 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/build_cmake.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:path/path.dart' as path; 7 | 8 | import 'artifacts_provider.dart'; 9 | import 'builder.dart'; 10 | import 'environment.dart'; 11 | import 'options.dart'; 12 | import 'target.dart'; 13 | 14 | class BuildCMake { 15 | final CargokitUserOptions userOptions; 16 | 17 | BuildCMake({required this.userOptions}); 18 | 19 | Future build() async { 20 | final targetPlatform = Environment.targetPlatform; 21 | final target = Target.forFlutterName(Environment.targetPlatform); 22 | if (target == null) { 23 | throw Exception("Unknown target platform: $targetPlatform"); 24 | } 25 | 26 | final environment = BuildEnvironment.fromEnvironment(isAndroid: false); 27 | final provider = 28 | ArtifactProvider(environment: environment, userOptions: userOptions); 29 | final artifacts = await provider.getArtifacts([target]); 30 | 31 | final libs = artifacts[target]!; 32 | 33 | for (final lib in libs) { 34 | if (lib.type == AritifactType.dylib) { 35 | File(lib.path) 36 | .copySync(path.join(Environment.outputDir, lib.finalFileName)); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/build_gradle.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:logging/logging.dart'; 7 | import 'package:path/path.dart' as path; 8 | 9 | import 'artifacts_provider.dart'; 10 | import 'builder.dart'; 11 | import 'environment.dart'; 12 | import 'options.dart'; 13 | import 'target.dart'; 14 | 15 | final log = Logger('build_gradle'); 16 | 17 | class BuildGradle { 18 | BuildGradle({required this.userOptions}); 19 | 20 | final CargokitUserOptions userOptions; 21 | 22 | Future build() async { 23 | final targets = Environment.targetPlatforms.map((arch) { 24 | final target = Target.forFlutterName(arch); 25 | if (target == null) { 26 | throw Exception( 27 | "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); 28 | } 29 | return target; 30 | }).toList(); 31 | 32 | final environment = BuildEnvironment.fromEnvironment(isAndroid: true); 33 | final provider = 34 | ArtifactProvider(environment: environment, userOptions: userOptions); 35 | final artifacts = await provider.getArtifacts(targets); 36 | 37 | for (final target in targets) { 38 | final libs = artifacts[target]!; 39 | final outputDir = path.join(Environment.outputDir, target.android!); 40 | Directory(outputDir).createSync(recursive: true); 41 | 42 | for (final lib in libs) { 43 | if (lib.type == AritifactType.dylib) { 44 | File(lib.path).copySync(path.join(outputDir, lib.finalFileName)); 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/build_pod.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:path/path.dart' as path; 7 | 8 | import 'artifacts_provider.dart'; 9 | import 'builder.dart'; 10 | import 'environment.dart'; 11 | import 'options.dart'; 12 | import 'target.dart'; 13 | import 'util.dart'; 14 | 15 | class BuildPod { 16 | BuildPod({required this.userOptions}); 17 | 18 | final CargokitUserOptions userOptions; 19 | 20 | Future build() async { 21 | final targets = Environment.darwinArchs.map((arch) { 22 | final target = Target.forDarwin( 23 | platformName: Environment.darwinPlatformName, darwinAarch: arch); 24 | if (target == null) { 25 | throw Exception( 26 | "Unknown darwin target or platform: $arch, ${Environment.darwinPlatformName}"); 27 | } 28 | return target; 29 | }).toList(); 30 | 31 | final environment = BuildEnvironment.fromEnvironment(isAndroid: false); 32 | final provider = 33 | ArtifactProvider(environment: environment, userOptions: userOptions); 34 | final artifacts = await provider.getArtifacts(targets); 35 | 36 | void performLipo(String targetFile, Iterable sourceFiles) { 37 | runCommand("lipo", [ 38 | '-create', 39 | ...sourceFiles, 40 | '-output', 41 | targetFile, 42 | ]); 43 | } 44 | 45 | final outputDir = Environment.outputDir; 46 | 47 | Directory(outputDir).createSync(recursive: true); 48 | 49 | final staticLibs = artifacts.values 50 | .expand((element) => element) 51 | .where((element) => element.type == AritifactType.staticlib) 52 | .toList(); 53 | final dynamicLibs = artifacts.values 54 | .expand((element) => element) 55 | .where((element) => element.type == AritifactType.dylib) 56 | .toList(); 57 | 58 | final libName = environment.crateInfo.packageName; 59 | 60 | // If there is static lib, use it and link it with pod 61 | if (staticLibs.isNotEmpty) { 62 | final finalTargetFile = path.join(outputDir, "lib$libName.a"); 63 | performLipo(finalTargetFile, staticLibs.map((e) => e.path)); 64 | } else { 65 | // Otherwise try to replace bundle dylib with our dylib 66 | final bundlePaths = [ 67 | '$libName.framework/Versions/A/$libName', 68 | '$libName.framework/$libName', 69 | ]; 70 | 71 | for (final bundlePath in bundlePaths) { 72 | final targetFile = path.join(outputDir, bundlePath); 73 | if (File(targetFile).existsSync()) { 74 | performLipo(targetFile, dynamicLibs.map((e) => e.path)); 75 | 76 | // Replace absolute id with @rpath one so that it works properly 77 | // when moved to Frameworks. 78 | runCommand("install_name_tool", [ 79 | '-id', 80 | '@rpath/$bundlePath', 81 | targetFile, 82 | ]); 83 | return; 84 | } 85 | } 86 | throw Exception('Unable to find bundle for dynamic library'); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/cargo.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:path/path.dart' as path; 7 | import 'package:toml/toml.dart'; 8 | 9 | class ManifestException { 10 | ManifestException(this.message, {required this.fileName}); 11 | 12 | final String? fileName; 13 | final String message; 14 | 15 | @override 16 | String toString() { 17 | if (fileName != null) { 18 | return 'Failed to parse package manifest at $fileName: $message'; 19 | } else { 20 | return 'Failed to parse package manifest: $message'; 21 | } 22 | } 23 | } 24 | 25 | class CrateInfo { 26 | CrateInfo({required this.packageName}); 27 | 28 | final String packageName; 29 | 30 | static CrateInfo parseManifest(String manifest, {final String? fileName}) { 31 | final toml = TomlDocument.parse(manifest); 32 | final package = toml.toMap()['package']; 33 | if (package == null) { 34 | throw ManifestException('Missing package section', fileName: fileName); 35 | } 36 | final name = package['name']; 37 | if (name == null) { 38 | throw ManifestException('Missing package name', fileName: fileName); 39 | } 40 | return CrateInfo(packageName: name); 41 | } 42 | 43 | static CrateInfo load(String manifestDir) { 44 | final manifestFile = File(path.join(manifestDir, 'Cargo.toml')); 45 | final manifest = manifestFile.readAsStringSync(); 46 | return parseManifest(manifest, fileName: manifestFile.path); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/crate_hash.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:convert'; 5 | import 'dart:io'; 6 | import 'dart:typed_data'; 7 | 8 | import 'package:collection/collection.dart'; 9 | import 'package:convert/convert.dart'; 10 | import 'package:crypto/crypto.dart'; 11 | import 'package:path/path.dart' as path; 12 | 13 | class CrateHash { 14 | /// Computes a hash uniquely identifying crate content. This takes into account 15 | /// content all all .rs files inside the src directory, as well as Cargo.toml, 16 | /// Cargo.lock, build.rs and cargokit.yaml. 17 | /// 18 | /// If [tempStorage] is provided, computed hash is stored in a file in that directory 19 | /// and reused on subsequent calls if the crate content hasn't changed. 20 | static String compute(String manifestDir, {String? tempStorage}) { 21 | return CrateHash._( 22 | manifestDir: manifestDir, 23 | tempStorage: tempStorage, 24 | )._compute(); 25 | } 26 | 27 | CrateHash._({ 28 | required this.manifestDir, 29 | required this.tempStorage, 30 | }); 31 | 32 | String _compute() { 33 | final files = getFiles(); 34 | final tempStorage = this.tempStorage; 35 | if (tempStorage != null) { 36 | final quickHash = _computeQuickHash(files); 37 | final quickHashFolder = Directory(path.join(tempStorage, 'crate_hash')); 38 | quickHashFolder.createSync(recursive: true); 39 | final quickHashFile = File(path.join(quickHashFolder.path, quickHash)); 40 | if (quickHashFile.existsSync()) { 41 | return quickHashFile.readAsStringSync(); 42 | } 43 | final hash = _computeHash(files); 44 | quickHashFile.writeAsStringSync(hash); 45 | return hash; 46 | } else { 47 | return _computeHash(files); 48 | } 49 | } 50 | 51 | /// Computes a quick hash based on files stat (without reading contents). This 52 | /// is used to cache the real hash, which is slower to compute since it involves 53 | /// reading every single file. 54 | String _computeQuickHash(List files) { 55 | final output = AccumulatorSink(); 56 | final input = sha256.startChunkedConversion(output); 57 | 58 | final data = ByteData(8); 59 | for (final file in files) { 60 | input.add(utf8.encode(file.path)); 61 | final stat = file.statSync(); 62 | data.setUint64(0, stat.size); 63 | input.add(data.buffer.asUint8List()); 64 | data.setUint64(0, stat.modified.millisecondsSinceEpoch); 65 | input.add(data.buffer.asUint8List()); 66 | } 67 | 68 | input.close(); 69 | return base64Url.encode(output.events.single.bytes); 70 | } 71 | 72 | String _computeHash(List files) { 73 | final output = AccumulatorSink(); 74 | final input = sha256.startChunkedConversion(output); 75 | 76 | void addTextFile(File file) { 77 | // text Files are hashed by lines in case we're dealing with github checkout 78 | // that auto-converts line endings. 79 | final splitter = LineSplitter(); 80 | if (file.existsSync()) { 81 | final data = file.readAsStringSync(); 82 | final lines = splitter.convert(data); 83 | for (final line in lines) { 84 | input.add(utf8.encode(line)); 85 | } 86 | } 87 | } 88 | 89 | for (final file in files) { 90 | addTextFile(file); 91 | } 92 | 93 | input.close(); 94 | final res = output.events.single; 95 | 96 | // Truncate to 128bits. 97 | final hash = res.bytes.sublist(0, 16); 98 | return hex.encode(hash); 99 | } 100 | 101 | List getFiles() { 102 | final src = Directory(path.join(manifestDir, 'src')); 103 | final files = src 104 | .listSync(recursive: true, followLinks: false) 105 | .whereType() 106 | .toList(); 107 | files.sortBy((element) => element.path); 108 | void addFile(String relative) { 109 | final file = File(path.join(manifestDir, relative)); 110 | if (file.existsSync()) { 111 | files.add(file); 112 | } 113 | } 114 | 115 | addFile('Cargo.toml'); 116 | addFile('Cargo.lock'); 117 | addFile('build.rs'); 118 | addFile('cargokit.yaml'); 119 | return files; 120 | } 121 | 122 | final String manifestDir; 123 | final String? tempStorage; 124 | } 125 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/environment.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | extension on String { 7 | String resolveSymlink() => File(this).resolveSymbolicLinksSync(); 8 | } 9 | 10 | class Environment { 11 | /// Current build configuration (debug or release). 12 | static String get configuration => 13 | _getEnv("CARGOKIT_CONFIGURATION").toLowerCase(); 14 | 15 | static bool get isDebug => configuration == 'debug'; 16 | static bool get isRelease => configuration == 'release'; 17 | 18 | /// Temporary directory where Rust build artifacts are placed. 19 | static String get targetTempDir => _getEnv("CARGOKIT_TARGET_TEMP_DIR"); 20 | 21 | /// Final output directory where the build artifacts are placed. 22 | static String get outputDir => _getEnvPath('CARGOKIT_OUTPUT_DIR'); 23 | 24 | /// Path to the crate manifest (containing Cargo.toml). 25 | static String get manifestDir => _getEnvPath('CARGOKIT_MANIFEST_DIR'); 26 | 27 | /// Directory inside root project. Not necessarily root folder. Symlinks are 28 | /// not resolved on purpose. 29 | static String get rootProjectDir => _getEnv('CARGOKIT_ROOT_PROJECT_DIR'); 30 | 31 | // Pod 32 | 33 | /// Platform name (macosx, iphoneos, iphonesimulator). 34 | static String get darwinPlatformName => 35 | _getEnv("CARGOKIT_DARWIN_PLATFORM_NAME"); 36 | 37 | /// List of architectures to build for (arm64, armv7, x86_64). 38 | static List get darwinArchs => 39 | _getEnv("CARGOKIT_DARWIN_ARCHS").split(' '); 40 | 41 | // Gradle 42 | static String get minSdkVersion => _getEnv("CARGOKIT_MIN_SDK_VERSION"); 43 | static String get ndkVersion => _getEnv("CARGOKIT_NDK_VERSION"); 44 | static String get sdkPath => _getEnvPath("CARGOKIT_SDK_DIR"); 45 | static String get javaHome => _getEnvPath("CARGOKIT_JAVA_HOME"); 46 | static List get targetPlatforms => 47 | _getEnv("CARGOKIT_TARGET_PLATFORMS").split(','); 48 | 49 | // CMAKE 50 | static String get targetPlatform => _getEnv("CARGOKIT_TARGET_PLATFORM"); 51 | 52 | static String _getEnv(String key) { 53 | final res = Platform.environment[key]; 54 | if (res == null) { 55 | throw Exception("Missing environment variable $key"); 56 | } 57 | return res; 58 | } 59 | 60 | static String _getEnvPath(String key) { 61 | final res = _getEnv(key); 62 | if (Directory(res).existsSync()) { 63 | return res.resolveSymlink(); 64 | } else { 65 | return res; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/logging.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:logging/logging.dart'; 7 | 8 | const String kSeparator = "--"; 9 | const String kDoubleSeparator = "=="; 10 | 11 | bool _lastMessageWasSeparator = false; 12 | 13 | void _log(LogRecord rec) { 14 | final prefix = '${rec.level.name}: '; 15 | final out = rec.level == Level.SEVERE ? stderr : stdout; 16 | if (rec.message == kSeparator) { 17 | if (!_lastMessageWasSeparator) { 18 | out.write(prefix); 19 | out.writeln('-' * 80); 20 | _lastMessageWasSeparator = true; 21 | } 22 | return; 23 | } else if (rec.message == kDoubleSeparator) { 24 | out.write(prefix); 25 | out.writeln('=' * 80); 26 | _lastMessageWasSeparator = true; 27 | return; 28 | } 29 | out.write(prefix); 30 | out.writeln(rec.message); 31 | _lastMessageWasSeparator = false; 32 | } 33 | 34 | void initLogging() { 35 | Logger.root.level = Level.INFO; 36 | Logger.root.onRecord.listen((LogRecord rec) { 37 | final lines = rec.message.split('\n'); 38 | for (final line in lines) { 39 | if (line.isNotEmpty || lines.length == 1 || line != lines.last) { 40 | _log(LogRecord( 41 | rec.level, 42 | line, 43 | rec.loggerName, 44 | )); 45 | } 46 | } 47 | }); 48 | } 49 | 50 | void enableVerboseLogging() { 51 | Logger.root.level = Level.ALL; 52 | } 53 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/rustup.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:collection/collection.dart'; 7 | import 'package:path/path.dart' as path; 8 | 9 | import 'util.dart'; 10 | 11 | class _Toolchain { 12 | _Toolchain( 13 | this.name, 14 | this.targets, 15 | ); 16 | 17 | final String name; 18 | final List targets; 19 | } 20 | 21 | class Rustup { 22 | List? installedTargets(String toolchain) { 23 | final targets = _installedTargets(toolchain); 24 | return targets != null ? List.unmodifiable(targets) : null; 25 | } 26 | 27 | void installToolchain(String toolchain) { 28 | log.info("Installing Rust toolchain: $toolchain"); 29 | runCommand("rustup", ['toolchain', 'install', toolchain]); 30 | _installedToolchains 31 | .add(_Toolchain(toolchain, _getInstalledTargets(toolchain))); 32 | } 33 | 34 | void installTarget( 35 | String target, { 36 | required String toolchain, 37 | }) { 38 | log.info("Installing Rust target: $target"); 39 | runCommand("rustup", [ 40 | 'target', 41 | 'add', 42 | '--toolchain', 43 | toolchain, 44 | target, 45 | ]); 46 | _installedTargets(toolchain)?.add(target); 47 | } 48 | 49 | final List<_Toolchain> _installedToolchains; 50 | 51 | Rustup() : _installedToolchains = _getInstalledToolchains(); 52 | 53 | List? _installedTargets(String toolchain) => _installedToolchains 54 | .firstWhereOrNull( 55 | (e) => e.name == toolchain || e.name.startsWith('$toolchain-')) 56 | ?.targets; 57 | 58 | static List<_Toolchain> _getInstalledToolchains() { 59 | String extractToolchainName(String line) { 60 | // ignore (default) after toolchain name 61 | final parts = line.split(' '); 62 | return parts[0]; 63 | } 64 | 65 | final res = runCommand("rustup", ['toolchain', 'list']); 66 | 67 | // To list all non-custom toolchains, we need to filter out lines that 68 | // don't start with "stable", "beta", or "nightly". 69 | Pattern nonCustom = RegExp(r"^(stable|beta|nightly)"); 70 | final lines = res.stdout 71 | .toString() 72 | .split('\n') 73 | .where((e) => e.isNotEmpty && e.startsWith(nonCustom)) 74 | .map(extractToolchainName) 75 | .toList(growable: true); 76 | 77 | return lines 78 | .map( 79 | (name) => _Toolchain( 80 | name, 81 | _getInstalledTargets(name), 82 | ), 83 | ) 84 | .toList(growable: true); 85 | } 86 | 87 | static List _getInstalledTargets(String toolchain) { 88 | final res = runCommand("rustup", [ 89 | 'target', 90 | 'list', 91 | '--toolchain', 92 | toolchain, 93 | '--installed', 94 | ]); 95 | final lines = res.stdout 96 | .toString() 97 | .split('\n') 98 | .where((e) => e.isNotEmpty) 99 | .toList(growable: true); 100 | return lines; 101 | } 102 | 103 | bool _didInstallRustSrcForNightly = false; 104 | 105 | void installRustSrcForNightly() { 106 | if (_didInstallRustSrcForNightly) { 107 | return; 108 | } 109 | // Useful for -Z build-std 110 | runCommand( 111 | "rustup", 112 | ['component', 'add', 'rust-src', '--toolchain', 'nightly'], 113 | ); 114 | _didInstallRustSrcForNightly = true; 115 | } 116 | 117 | static String? executablePath() { 118 | final envPath = Platform.environment['PATH']; 119 | final envPathSeparator = Platform.isWindows ? ';' : ':'; 120 | final home = Platform.isWindows 121 | ? Platform.environment['USERPROFILE'] 122 | : Platform.environment['HOME']; 123 | final paths = [ 124 | if (home != null) path.join(home, '.cargo', 'bin'), 125 | if (envPath != null) ...envPath.split(envPathSeparator), 126 | ]; 127 | for (final p in paths) { 128 | final rustup = Platform.isWindows ? 'rustup.exe' : 'rustup'; 129 | final rustupPath = path.join(p, rustup); 130 | if (File(rustupPath).existsSync()) { 131 | return rustupPath; 132 | } 133 | } 134 | return null; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/target.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:collection/collection.dart'; 7 | 8 | import 'util.dart'; 9 | 10 | class Target { 11 | Target({ 12 | required this.rust, 13 | this.flutter, 14 | this.android, 15 | this.androidMinSdkVersion, 16 | this.darwinPlatform, 17 | this.darwinArch, 18 | }); 19 | 20 | static final all = [ 21 | Target( 22 | rust: 'armv7-linux-androideabi', 23 | flutter: 'android-arm', 24 | android: 'armeabi-v7a', 25 | androidMinSdkVersion: 16, 26 | ), 27 | Target( 28 | rust: 'aarch64-linux-android', 29 | flutter: 'android-arm64', 30 | android: 'arm64-v8a', 31 | androidMinSdkVersion: 21, 32 | ), 33 | Target( 34 | rust: 'i686-linux-android', 35 | flutter: 'android-x86', 36 | android: 'x86', 37 | androidMinSdkVersion: 16, 38 | ), 39 | Target( 40 | rust: 'x86_64-linux-android', 41 | flutter: 'android-x64', 42 | android: 'x86_64', 43 | androidMinSdkVersion: 21, 44 | ), 45 | Target( 46 | rust: 'x86_64-pc-windows-msvc', 47 | flutter: 'windows-x64', 48 | ), 49 | Target( 50 | rust: 'x86_64-unknown-linux-gnu', 51 | flutter: 'linux-x64', 52 | ), 53 | Target( 54 | rust: 'aarch64-unknown-linux-gnu', 55 | flutter: 'linux-arm64', 56 | ), 57 | Target( 58 | rust: 'x86_64-apple-darwin', 59 | darwinPlatform: 'macosx', 60 | darwinArch: 'x86_64', 61 | ), 62 | Target( 63 | rust: 'aarch64-apple-darwin', 64 | darwinPlatform: 'macosx', 65 | darwinArch: 'arm64', 66 | ), 67 | Target( 68 | rust: 'aarch64-apple-ios', 69 | darwinPlatform: 'iphoneos', 70 | darwinArch: 'arm64', 71 | ), 72 | Target( 73 | rust: 'aarch64-apple-ios-sim', 74 | darwinPlatform: 'iphonesimulator', 75 | darwinArch: 'arm64', 76 | ), 77 | Target( 78 | rust: 'x86_64-apple-ios', 79 | darwinPlatform: 'iphonesimulator', 80 | darwinArch: 'x86_64', 81 | ), 82 | ]; 83 | 84 | static Target? forFlutterName(String flutterName) { 85 | return all.firstWhereOrNull((element) => element.flutter == flutterName); 86 | } 87 | 88 | static Target? forDarwin({ 89 | required String platformName, 90 | required String darwinAarch, 91 | }) { 92 | return all.firstWhereOrNull((element) => // 93 | element.darwinPlatform == platformName && 94 | element.darwinArch == darwinAarch); 95 | } 96 | 97 | static Target? forRustTriple(String triple) { 98 | return all.firstWhereOrNull((element) => element.rust == triple); 99 | } 100 | 101 | static List androidTargets() { 102 | return all 103 | .where((element) => element.android != null) 104 | .toList(growable: false); 105 | } 106 | 107 | /// Returns buildable targets on current host platform ignoring Android targets. 108 | static List buildableTargets() { 109 | if (Platform.isLinux) { 110 | // Right now we don't support cross-compiling on Linux. So we just return 111 | // the host target. 112 | final arch = runCommand('arch', []).stdout as String; 113 | if (arch.trim() == 'aarch64') { 114 | return [Target.forRustTriple('aarch64-unknown-linux-gnu')!]; 115 | } else { 116 | return [Target.forRustTriple('x86_64-unknown-linux-gnu')!]; 117 | } 118 | } 119 | return all.where((target) { 120 | if (Platform.isWindows) { 121 | return target.rust.contains('-windows-'); 122 | } else if (Platform.isMacOS) { 123 | return target.darwinPlatform != null; 124 | } 125 | return false; 126 | }).toList(growable: false); 127 | } 128 | 129 | @override 130 | String toString() { 131 | return rust; 132 | } 133 | 134 | final String? flutter; 135 | final String rust; 136 | final String? android; 137 | final int? androidMinSdkVersion; 138 | final String? darwinPlatform; 139 | final String? darwinArch; 140 | } 141 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/lib/src/verify_binaries.dart: -------------------------------------------------------------------------------- 1 | /// This is copied from Cargokit (which is the official way to use it currently) 2 | /// Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | import 'dart:io'; 5 | 6 | import 'package:ed25519_edwards/ed25519_edwards.dart'; 7 | import 'package:http/http.dart'; 8 | 9 | import 'artifacts_provider.dart'; 10 | import 'cargo.dart'; 11 | import 'crate_hash.dart'; 12 | import 'options.dart'; 13 | import 'precompile_binaries.dart'; 14 | import 'target.dart'; 15 | 16 | class VerifyBinaries { 17 | VerifyBinaries({ 18 | required this.manifestDir, 19 | }); 20 | 21 | final String manifestDir; 22 | 23 | Future run() async { 24 | final crateInfo = CrateInfo.load(manifestDir); 25 | 26 | final config = CargokitCrateOptions.load(manifestDir: manifestDir); 27 | final precompiledBinaries = config.precompiledBinaries; 28 | if (precompiledBinaries == null) { 29 | stdout.writeln('Crate does not support precompiled binaries.'); 30 | } else { 31 | final crateHash = CrateHash.compute(manifestDir); 32 | stdout.writeln('Crate hash: $crateHash'); 33 | 34 | for (final target in Target.all) { 35 | final message = 'Checking ${target.rust}...'; 36 | stdout.write(message.padRight(40)); 37 | stdout.flush(); 38 | 39 | final artifacts = getArtifactNames( 40 | target: target, 41 | libraryName: crateInfo.packageName, 42 | remote: true, 43 | ); 44 | 45 | final prefix = precompiledBinaries.uriPrefix; 46 | 47 | bool ok = true; 48 | 49 | for (final artifact in artifacts) { 50 | final fileName = PrecompileBinaries.fileName(target, artifact); 51 | final signatureFileName = 52 | PrecompileBinaries.signatureFileName(target, artifact); 53 | 54 | final url = Uri.parse('$prefix$crateHash/$fileName'); 55 | final signatureUrl = 56 | Uri.parse('$prefix$crateHash/$signatureFileName'); 57 | 58 | final signature = await get(signatureUrl); 59 | if (signature.statusCode != 200) { 60 | stdout.writeln('MISSING'); 61 | ok = false; 62 | break; 63 | } 64 | final asset = await get(url); 65 | if (asset.statusCode != 200) { 66 | stdout.writeln('MISSING'); 67 | ok = false; 68 | break; 69 | } 70 | 71 | if (!verify(precompiledBinaries.publicKey, asset.bodyBytes, 72 | signature.bodyBytes)) { 73 | stdout.writeln('INVALID SIGNATURE'); 74 | ok = false; 75 | } 76 | } 77 | 78 | if (ok) { 79 | stdout.writeln('OK'); 80 | } 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /rust_builder/cargokit/build_tool/pubspec.yaml: -------------------------------------------------------------------------------- 1 | # This is copied from Cargokit (which is the official way to use it currently) 2 | # Details: https://fzyzcjy.github.io/flutter_rust_bridge/manual/integrate/builtin 3 | 4 | name: build_tool 5 | description: Cargokit build_tool. Facilitates the build of Rust crate during Flutter application build. 6 | publish_to: none 7 | version: 1.0.0 8 | 9 | environment: 10 | sdk: ">=3.0.0 <4.0.0" 11 | 12 | # Add regular dependencies here. 13 | dependencies: 14 | # these are pinned on purpose because the bundle_tool_runner doesn't have 15 | # pubspec.lock. See run_build_tool.sh 16 | logging: 1.2.0 17 | path: 1.8.0 18 | version: 3.0.0 19 | collection: 1.18.0 20 | ed25519_edwards: 0.3.1 21 | hex: 0.2.0 22 | yaml: 3.1.2 23 | source_span: 1.10.0 24 | github: 9.17.0 25 | args: 2.4.2 26 | crypto: 3.0.3 27 | convert: 3.1.1 28 | http: 1.1.0 29 | toml: 0.14.0 30 | 31 | dev_dependencies: 32 | lints: ^2.1.0 33 | test: ^1.24.0 34 | -------------------------------------------------------------------------------- /rust_builder/cargokit/cmake/cargokit.cmake: -------------------------------------------------------------------------------- 1 | SET(cargokit_cmake_root "${CMAKE_CURRENT_LIST_DIR}/..") 2 | 3 | # Workaround for https://github.com/dart-lang/pub/issues/4010 4 | get_filename_component(cargokit_cmake_root "${cargokit_cmake_root}" REALPATH) 5 | 6 | if(WIN32) 7 | # REALPATH does not properly resolve symlinks on windows :-/ 8 | execute_process(COMMAND powershell -ExecutionPolicy Bypass -File "${CMAKE_CURRENT_LIST_DIR}/resolve_symlinks.ps1" "${cargokit_cmake_root}" OUTPUT_VARIABLE cargokit_cmake_root OUTPUT_STRIP_TRAILING_WHITESPACE) 9 | endif() 10 | 11 | # Arguments 12 | # - target: CMAKE target to which rust library is linked 13 | # - manifest_dir: relative path from current folder to directory containing cargo manifest 14 | # - lib_name: cargo package name 15 | # - any_symbol_name: name of any exported symbol from the library. 16 | # used on windows to force linking with library. 17 | function(apply_cargokit target manifest_dir lib_name any_symbol_name) 18 | 19 | set(CARGOKIT_LIB_NAME "${lib_name}") 20 | set(CARGOKIT_LIB_FULL_NAME "${CMAKE_SHARED_MODULE_PREFIX}${CARGOKIT_LIB_NAME}${CMAKE_SHARED_MODULE_SUFFIX}") 21 | if (CMAKE_CONFIGURATION_TYPES) 22 | set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/$") 23 | set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/$/${CARGOKIT_LIB_FULL_NAME}") 24 | else() 25 | set(CARGOKIT_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") 26 | set(OUTPUT_LIB "${CMAKE_CURRENT_BINARY_DIR}/${CARGOKIT_LIB_FULL_NAME}") 27 | endif() 28 | set(CARGOKIT_TEMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/cargokit_build") 29 | 30 | if (FLUTTER_TARGET_PLATFORM) 31 | set(CARGOKIT_TARGET_PLATFORM "${FLUTTER_TARGET_PLATFORM}") 32 | else() 33 | set(CARGOKIT_TARGET_PLATFORM "windows-x64") 34 | endif() 35 | 36 | set(CARGOKIT_ENV 37 | "CARGOKIT_CMAKE=${CMAKE_COMMAND}" 38 | "CARGOKIT_CONFIGURATION=$" 39 | "CARGOKIT_MANIFEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${manifest_dir}" 40 | "CARGOKIT_TARGET_TEMP_DIR=${CARGOKIT_TEMP_DIR}" 41 | "CARGOKIT_OUTPUT_DIR=${CARGOKIT_OUTPUT_DIR}" 42 | "CARGOKIT_TARGET_PLATFORM=${CARGOKIT_TARGET_PLATFORM}" 43 | "CARGOKIT_TOOL_TEMP_DIR=${CARGOKIT_TEMP_DIR}/tool" 44 | "CARGOKIT_ROOT_PROJECT_DIR=${CMAKE_SOURCE_DIR}" 45 | ) 46 | 47 | if (WIN32) 48 | set(SCRIPT_EXTENSION ".cmd") 49 | set(IMPORT_LIB_EXTENSION ".lib") 50 | else() 51 | set(SCRIPT_EXTENSION ".sh") 52 | set(IMPORT_LIB_EXTENSION "") 53 | execute_process(COMMAND chmod +x "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}") 54 | endif() 55 | 56 | # Using generators in custom command is only supported in CMake 3.20+ 57 | if (CMAKE_CONFIGURATION_TYPES AND ${CMAKE_VERSION} VERSION_LESS "3.20.0") 58 | foreach(CONFIG IN LISTS CMAKE_CONFIGURATION_TYPES) 59 | add_custom_command( 60 | OUTPUT 61 | "${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/${CARGOKIT_LIB_FULL_NAME}" 62 | "${CMAKE_CURRENT_BINARY_DIR}/_phony_" 63 | COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} 64 | "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake 65 | VERBATIM 66 | ) 67 | endforeach() 68 | else() 69 | add_custom_command( 70 | OUTPUT 71 | ${OUTPUT_LIB} 72 | "${CMAKE_CURRENT_BINARY_DIR}/_phony_" 73 | COMMAND ${CMAKE_COMMAND} -E env ${CARGOKIT_ENV} 74 | "${cargokit_cmake_root}/run_build_tool${SCRIPT_EXTENSION}" build-cmake 75 | VERBATIM 76 | ) 77 | endif() 78 | 79 | 80 | set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/_phony_" PROPERTIES SYMBOLIC TRUE) 81 | 82 | if (TARGET ${target}) 83 | # If we have actual cmake target provided create target and make existing 84 | # target depend on it 85 | add_custom_target("${target}_cargokit" DEPENDS ${OUTPUT_LIB}) 86 | add_dependencies("${target}" "${target}_cargokit") 87 | target_link_libraries("${target}" PRIVATE "${OUTPUT_LIB}${IMPORT_LIB_EXTENSION}") 88 | if(WIN32) 89 | target_link_options(${target} PRIVATE "/INCLUDE:${any_symbol_name}") 90 | endif() 91 | else() 92 | # Otherwise (FFI) just use ALL to force building always 93 | add_custom_target("${target}_cargokit" ALL DEPENDS ${OUTPUT_LIB}) 94 | endif() 95 | 96 | # Allow adding the output library to plugin bundled libraries 97 | set("${target}_cargokit_lib" ${OUTPUT_LIB} PARENT_SCOPE) 98 | 99 | endfunction() 100 | -------------------------------------------------------------------------------- /rust_builder/cargokit/cmake/resolve_symlinks.ps1: -------------------------------------------------------------------------------- 1 | function Resolve-Symlinks { 2 | [CmdletBinding()] 3 | [OutputType([string])] 4 | param( 5 | [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] 6 | [string] $Path 7 | ) 8 | 9 | [string] $separator = '/' 10 | [string[]] $parts = $Path.Split($separator) 11 | 12 | [string] $realPath = '' 13 | foreach ($part in $parts) { 14 | if ($realPath -and !$realPath.EndsWith($separator)) { 15 | $realPath += $separator 16 | } 17 | $realPath += $part 18 | $item = Get-Item $realPath 19 | if ($item.Target) { 20 | $realPath = $item.Target.Replace('\', '/') 21 | } 22 | } 23 | $realPath 24 | } 25 | 26 | $path=Resolve-Symlinks -Path $args[0] 27 | Write-Host $path 28 | -------------------------------------------------------------------------------- /rust_builder/cargokit/run_build_tool.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | setlocal ENABLEDELAYEDEXPANSION 5 | 6 | SET BASEDIR=%~dp0 7 | 8 | if not exist "%CARGOKIT_TOOL_TEMP_DIR%" ( 9 | mkdir "%CARGOKIT_TOOL_TEMP_DIR%" 10 | ) 11 | cd /D "%CARGOKIT_TOOL_TEMP_DIR%" 12 | 13 | SET BUILD_TOOL_PKG_DIR=%BASEDIR%build_tool 14 | SET DART=%FLUTTER_ROOT%\bin\cache\dart-sdk\bin\dart 15 | 16 | set BUILD_TOOL_PKG_DIR_POSIX=%BUILD_TOOL_PKG_DIR:\=/% 17 | 18 | ( 19 | echo name: build_tool_runner 20 | echo version: 1.0.0 21 | echo publish_to: none 22 | echo. 23 | echo environment: 24 | echo sdk: '^>=3.0.0 ^<4.0.0' 25 | echo. 26 | echo dependencies: 27 | echo build_tool: 28 | echo path: %BUILD_TOOL_PKG_DIR_POSIX% 29 | ) >pubspec.yaml 30 | 31 | if not exist bin ( 32 | mkdir bin 33 | ) 34 | 35 | ( 36 | echo import 'package:build_tool/build_tool.dart' as build_tool; 37 | echo void main^(List^ args^) ^{ 38 | echo build_tool.runMain^(args^); 39 | echo ^} 40 | ) >bin\build_tool_runner.dart 41 | 42 | SET PRECOMPILED=bin\build_tool_runner.dill 43 | 44 | REM To detect changes in package we compare output of DIR /s (recursive) 45 | set PREV_PACKAGE_INFO=.dart_tool\package_info.prev 46 | set CUR_PACKAGE_INFO=.dart_tool\package_info.cur 47 | 48 | DIR "%BUILD_TOOL_PKG_DIR%" /s > "%CUR_PACKAGE_INFO%_orig" 49 | 50 | REM Last line in dir output is free space on harddrive. That is bound to 51 | REM change between invocation so we need to remove it 52 | ( 53 | Set "Line=" 54 | For /F "UseBackQ Delims=" %%A In ("%CUR_PACKAGE_INFO%_orig") Do ( 55 | SetLocal EnableDelayedExpansion 56 | If Defined Line Echo !Line! 57 | EndLocal 58 | Set "Line=%%A") 59 | ) >"%CUR_PACKAGE_INFO%" 60 | DEL "%CUR_PACKAGE_INFO%_orig" 61 | 62 | REM Compare current directory listing with previous 63 | FC /B "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" > nul 2>&1 64 | 65 | If %ERRORLEVEL% neq 0 ( 66 | REM Changed - copy current to previous and remove precompiled kernel 67 | if exist "%PREV_PACKAGE_INFO%" ( 68 | DEL "%PREV_PACKAGE_INFO%" 69 | ) 70 | MOVE /Y "%CUR_PACKAGE_INFO%" "%PREV_PACKAGE_INFO%" 71 | if exist "%PRECOMPILED%" ( 72 | DEL "%PRECOMPILED%" 73 | ) 74 | ) 75 | 76 | REM There is no CUR_PACKAGE_INFO it was renamed in previous step to %PREV_PACKAGE_INFO% 77 | REM which means we need to do pub get and precompile 78 | if not exist "%PRECOMPILED%" ( 79 | echo Running pub get in "%cd%" 80 | "%DART%" pub get --no-precompile 81 | "%DART%" compile kernel bin/build_tool_runner.dart 82 | ) 83 | 84 | "%DART%" "%PRECOMPILED%" %* 85 | 86 | REM 253 means invalid snapshot version. 87 | If %ERRORLEVEL% equ 253 ( 88 | "%DART%" pub get --no-precompile 89 | "%DART%" compile kernel bin/build_tool_runner.dart 90 | "%DART%" "%PRECOMPILED%" %* 91 | ) 92 | -------------------------------------------------------------------------------- /rust_builder/cargokit/run_build_tool.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | BASEDIR=$(dirname "$0") 6 | 7 | mkdir -p "$CARGOKIT_TOOL_TEMP_DIR" 8 | 9 | cd "$CARGOKIT_TOOL_TEMP_DIR" 10 | 11 | # Write a very simple bin package in temp folder that depends on build_tool package 12 | # from Cargokit. This is done to ensure that we don't pollute Cargokit folder 13 | # with .dart_tool contents. 14 | 15 | BUILD_TOOL_PKG_DIR="$BASEDIR/build_tool" 16 | 17 | if [[ -z $FLUTTER_ROOT ]]; then # not defined 18 | DART=dart 19 | else 20 | DART="$FLUTTER_ROOT/bin/cache/dart-sdk/bin/dart" 21 | fi 22 | 23 | cat << EOF > "pubspec.yaml" 24 | name: build_tool_runner 25 | version: 1.0.0 26 | publish_to: none 27 | 28 | environment: 29 | sdk: '>=3.0.0 <4.0.0' 30 | 31 | dependencies: 32 | build_tool: 33 | path: "$BUILD_TOOL_PKG_DIR" 34 | EOF 35 | 36 | mkdir -p "bin" 37 | 38 | cat << EOF > "bin/build_tool_runner.dart" 39 | import 'package:build_tool/build_tool.dart' as build_tool; 40 | void main(List args) { 41 | build_tool.runMain(args); 42 | } 43 | EOF 44 | 45 | # Create alias for `shasum` if it does not exist and `sha1sum` exists 46 | if ! [ -x "$(command -v shasum)" ] && [ -x "$(command -v sha1sum)" ]; then 47 | shopt -s expand_aliases 48 | alias shasum="sha1sum" 49 | fi 50 | 51 | # Dart run will not cache any package that has a path dependency, which 52 | # is the case for our build_tool_runner. So instead we precompile the package 53 | # ourselves. 54 | # To invalidate the cached kernel we use the hash of ls -LR of the build_tool 55 | # package directory. This should be good enough, as the build_tool package 56 | # itself is not meant to have any path dependencies. 57 | 58 | if [[ "$OSTYPE" == "darwin"* ]]; then 59 | PACKAGE_HASH=$(ls -lTR "$BUILD_TOOL_PKG_DIR" | shasum) 60 | else 61 | PACKAGE_HASH=$(ls -lR --full-time "$BUILD_TOOL_PKG_DIR" | shasum) 62 | fi 63 | 64 | PACKAGE_HASH_FILE=".package_hash" 65 | 66 | if [ -f "$PACKAGE_HASH_FILE" ]; then 67 | EXISTING_HASH=$(cat "$PACKAGE_HASH_FILE") 68 | if [ "$PACKAGE_HASH" != "$EXISTING_HASH" ]; then 69 | rm "$PACKAGE_HASH_FILE" 70 | fi 71 | fi 72 | 73 | # Run pub get if needed. 74 | if [ ! -f "$PACKAGE_HASH_FILE" ]; then 75 | "$DART" pub get --no-precompile 76 | "$DART" compile kernel bin/build_tool_runner.dart 77 | echo "$PACKAGE_HASH" > "$PACKAGE_HASH_FILE" 78 | fi 79 | 80 | set +e 81 | 82 | "$DART" bin/build_tool_runner.dill "$@" 83 | 84 | exit_code=$? 85 | 86 | # 253 means invalid snapshot version. 87 | if [ $exit_code == 253 ]; then 88 | "$DART" pub get --no-precompile 89 | "$DART" compile kernel bin/build_tool_runner.dart 90 | "$DART" bin/build_tool_runner.dill "$@" 91 | exit_code=$? 92 | fi 93 | 94 | exit $exit_code 95 | -------------------------------------------------------------------------------- /rust_builder/ios/Classes/dummy_file.c: -------------------------------------------------------------------------------- 1 | // This is an empty file to force CocoaPods to create a framework. 2 | -------------------------------------------------------------------------------- /rust_builder/ios/rust_lib_vnt_app.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint rust_lib_vnt_app.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'rust_lib_vnt_app' 7 | s.version = '0.0.1' 8 | s.summary = 'A new Flutter FFI plugin project.' 9 | s.description = <<-DESC 10 | A new Flutter FFI plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | 16 | # This will ensure the source files in Classes/ are included in the native 17 | # builds of apps using this FFI plugin. Podspec does not support relative 18 | # paths, so Classes contains a forwarder C file that relatively imports 19 | # `../src/*` so that the C sources can be shared among all target platforms. 20 | s.source = { :path => '.' } 21 | s.source_files = 'Classes/**/*' 22 | s.dependency 'Flutter' 23 | s.platform = :ios, '11.0' 24 | 25 | # Flutter.framework does not contain a i386 slice. 26 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 27 | s.swift_version = '5.0' 28 | 29 | s.script_phase = { 30 | :name => 'Build Rust library', 31 | # First argument is relative path to the `rust` folder, second is name of rust library 32 | :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_vnt_app', 33 | :execution_position => :before_compile, 34 | :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], 35 | # Let XCode know that the static library referenced in -force_load below is 36 | # created by this build step. 37 | :output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_vnt_app.a"], 38 | } 39 | s.pod_target_xcconfig = { 40 | 'DEFINES_MODULE' => 'YES', 41 | # Flutter.framework does not contain a i386 slice. 42 | 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', 43 | 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_vnt_app.a', 44 | } 45 | end -------------------------------------------------------------------------------- /rust_builder/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have CMake 3.10 or later 2 | # installed. You should not increase this version, as doing so will cause 3 | # the plugin to fail to compile for some customers of the plugin. 4 | cmake_minimum_required(VERSION 3.10) 5 | 6 | # Project-level configuration. 7 | set(PROJECT_NAME "rust_lib_vnt_app") 8 | project(${PROJECT_NAME} LANGUAGES CXX) 9 | 10 | include("../cargokit/cmake/cargokit.cmake") 11 | apply_cargokit(${PROJECT_NAME} ../../rust rust_lib_vnt_app "") 12 | 13 | # List of absolute paths to libraries that should be bundled with the plugin. 14 | # This list could contain prebuilt libraries, or libraries created by an 15 | # external build triggered from this build file. 16 | set(rust_lib_vnt_app_bundled_libraries 17 | "${${PROJECT_NAME}_cargokit_lib}" 18 | PARENT_SCOPE 19 | ) 20 | -------------------------------------------------------------------------------- /rust_builder/macos/Classes/dummy_file.c: -------------------------------------------------------------------------------- 1 | // This is an empty file to force CocoaPods to create a framework. 2 | -------------------------------------------------------------------------------- /rust_builder/macos/rust_lib_vnt_app.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint rust_lib_vnt_app.podspec` to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'rust_lib_vnt_app' 7 | s.version = '0.0.1' 8 | s.summary = 'A new Flutter FFI plugin project.' 9 | s.description = <<-DESC 10 | A new Flutter FFI plugin project. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | 16 | # This will ensure the source files in Classes/ are included in the native 17 | # builds of apps using this FFI plugin. Podspec does not support relative 18 | # paths, so Classes contains a forwarder C file that relatively imports 19 | # `../src/*` so that the C sources can be shared among all target platforms. 20 | s.source = { :path => '.' } 21 | s.source_files = 'Classes/**/*' 22 | s.dependency 'FlutterMacOS' 23 | 24 | s.platform = :osx, '10.11' 25 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } 26 | s.swift_version = '5.0' 27 | 28 | s.script_phase = { 29 | :name => 'Build Rust library', 30 | # First argument is relative path to the `rust` folder, second is name of rust library 31 | :script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib_vnt_app', 32 | :execution_position => :before_compile, 33 | :input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'], 34 | # Let XCode know that the static library referenced in -force_load below is 35 | # created by this build step. 36 | :output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib_vnt_app.a"], 37 | } 38 | s.pod_target_xcconfig = { 39 | 'DEFINES_MODULE' => 'YES', 40 | # Flutter.framework does not contain a i386 slice. 41 | 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', 42 | 'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib_vnt_app.a', 43 | } 44 | end -------------------------------------------------------------------------------- /rust_builder/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: rust_lib_vnt_app 2 | description: "Utility to build Rust code" 3 | version: 0.0.1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: '>=3.3.0 <4.0.0' 8 | flutter: '>=3.3.0' 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | plugin_platform_interface: ^2.0.2 14 | 15 | dev_dependencies: 16 | ffi: ^2.0.2 17 | ffigen: ^11.0.0 18 | flutter_test: 19 | sdk: flutter 20 | flutter_lints: ^2.0.0 21 | 22 | flutter: 23 | plugin: 24 | platforms: 25 | android: 26 | ffiPlugin: true 27 | ios: 28 | ffiPlugin: true 29 | linux: 30 | ffiPlugin: true 31 | macos: 32 | ffiPlugin: true 33 | windows: 34 | ffiPlugin: true 35 | -------------------------------------------------------------------------------- /rust_builder/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /rust_builder/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The Flutter tooling requires that developers have a version of Visual Studio 2 | # installed that includes CMake 3.14 or later. You should not increase this 3 | # version, as doing so will cause the plugin to fail to compile for some 4 | # customers of the plugin. 5 | cmake_minimum_required(VERSION 3.14) 6 | 7 | # Project-level configuration. 8 | set(PROJECT_NAME "rust_lib_vnt_app") 9 | project(${PROJECT_NAME} LANGUAGES CXX) 10 | 11 | include("../cargokit/cmake/cargokit.cmake") 12 | apply_cargokit(${PROJECT_NAME} ../../../../../../rust rust_lib_vnt_app "") 13 | 14 | # List of absolute paths to libraries that should be bundled with the plugin. 15 | # This list could contain prebuilt libraries, or libraries created by an 16 | # external build triggered from this build file. 17 | set(rust_lib_vnt_app_bundled_libraries 18 | "${${PROJECT_NAME}_cargokit_lib}" 19 | PARENT_SCOPE 20 | ) 21 | -------------------------------------------------------------------------------- /test_driver/integration_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:integration_test/integration_test_driver.dart'; 2 | 3 | Future main() => integrationDriver(); 4 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | vnt_app 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vnt_app", 3 | "short_name": "vnt_app", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.14) 3 | project(vnt_app LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "vnt_app") 8 | 9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 10 | # versions of CMake. 11 | cmake_policy(VERSION 3.14...3.25) 12 | 13 | # Define build configuration option. 14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 15 | if(IS_MULTICONFIG) 16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 17 | CACHE STRING "" FORCE) 18 | else() 19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 20 | set(CMAKE_BUILD_TYPE "Debug" CACHE 21 | STRING "Flutter build mode" FORCE) 22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 23 | "Debug" "Profile" "Release") 24 | endif() 25 | endif() 26 | # Define settings for the Profile build mode. 27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 31 | 32 | # Use Unicode for all projects. 33 | add_definitions(-DUNICODE -D_UNICODE) 34 | 35 | # Compilation settings that should be applied to most targets. 36 | # 37 | # Be cautious about adding new options here, as plugins use this function by 38 | # default. In most cases, you should add new options to specific targets instead 39 | # of modifying this function. 40 | function(APPLY_STANDARD_SETTINGS TARGET) 41 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 43 | target_compile_options(${TARGET} PRIVATE /EHsc) 44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 46 | endfunction() 47 | 48 | # Flutter library and tool build rules. 49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 50 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 51 | 52 | # Application build; see runner/CMakeLists.txt. 53 | add_subdirectory("runner") 54 | 55 | 56 | # Generated plugin build rules, which manage building the plugins and adding 57 | # them to the application. 58 | include(flutter/generated_plugins.cmake) 59 | 60 | 61 | # === Installation === 62 | # Support files are copied into place next to the executable, so that it can 63 | # run in place. This is done instead of making a separate bundle (as on Linux) 64 | # so that building and running from within Visual Studio will work. 65 | set(BUILD_BUNDLE_DIR "$") 66 | # Make the "install" step default, as it's required to run. 67 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 68 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 69 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 70 | endif() 71 | 72 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 73 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 74 | 75 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 76 | COMPONENT Runtime) 77 | 78 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 79 | COMPONENT Runtime) 80 | 81 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 82 | COMPONENT Runtime) 83 | 84 | if(PLUGIN_BUNDLED_LIBRARIES) 85 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 86 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 87 | COMPONENT Runtime) 88 | endif() 89 | 90 | # Copy the native assets provided by the build.dart from all packages. 91 | set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") 92 | install(DIRECTORY "${NATIVE_ASSETS_DIR}" 93 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 94 | COMPONENT Runtime) 95 | 96 | # Fully re-copy the assets directory on each build to avoid having stale files 97 | # from a previous install. 98 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 99 | install(CODE " 100 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 101 | " COMPONENT Runtime) 102 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 103 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 104 | 105 | # Install the AOT library on non-Debug builds only. 106 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 107 | CONFIGURATIONS Profile;Release 108 | COMPONENT Runtime) 109 | -------------------------------------------------------------------------------- /windows/dlls/amd64/wintun.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/windows/dlls/amd64/wintun.dll -------------------------------------------------------------------------------- /windows/dlls/arm/wintun.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/windows/dlls/arm/wintun.dll -------------------------------------------------------------------------------- /windows/dlls/arm64/wintun.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/windows/dlls/arm64/wintun.dll -------------------------------------------------------------------------------- /windows/dlls/x86/wintun.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/windows/dlls/x86/wintun.dll -------------------------------------------------------------------------------- /windows/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.14) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 12 | 13 | # Set fallback configurations for older versions of the flutter tool. 14 | if (NOT DEFINED FLUTTER_TARGET_PLATFORM) 15 | set(FLUTTER_TARGET_PLATFORM "windows-x64") 16 | endif() 17 | 18 | # === Flutter Library === 19 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") 20 | 21 | # Published to parent scope for install step. 22 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 23 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 24 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 25 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) 26 | 27 | list(APPEND FLUTTER_LIBRARY_HEADERS 28 | "flutter_export.h" 29 | "flutter_windows.h" 30 | "flutter_messenger.h" 31 | "flutter_plugin_registrar.h" 32 | "flutter_texture_registrar.h" 33 | ) 34 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 35 | add_library(flutter INTERFACE) 36 | target_include_directories(flutter INTERFACE 37 | "${EPHEMERAL_DIR}" 38 | ) 39 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 40 | add_dependencies(flutter flutter_assemble) 41 | 42 | # === Wrapper === 43 | list(APPEND CPP_WRAPPER_SOURCES_CORE 44 | "core_implementations.cc" 45 | "standard_codec.cc" 46 | ) 47 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 48 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 49 | "plugin_registrar.cc" 50 | ) 51 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 52 | list(APPEND CPP_WRAPPER_SOURCES_APP 53 | "flutter_engine.cc" 54 | "flutter_view_controller.cc" 55 | ) 56 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 57 | 58 | # Wrapper sources needed for a plugin. 59 | add_library(flutter_wrapper_plugin STATIC 60 | ${CPP_WRAPPER_SOURCES_CORE} 61 | ${CPP_WRAPPER_SOURCES_PLUGIN} 62 | ) 63 | apply_standard_settings(flutter_wrapper_plugin) 64 | set_target_properties(flutter_wrapper_plugin PROPERTIES 65 | POSITION_INDEPENDENT_CODE ON) 66 | set_target_properties(flutter_wrapper_plugin PROPERTIES 67 | CXX_VISIBILITY_PRESET hidden) 68 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 69 | target_include_directories(flutter_wrapper_plugin PUBLIC 70 | "${WRAPPER_ROOT}/include" 71 | ) 72 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 73 | 74 | # Wrapper sources needed for the runner. 75 | add_library(flutter_wrapper_app STATIC 76 | ${CPP_WRAPPER_SOURCES_CORE} 77 | ${CPP_WRAPPER_SOURCES_APP} 78 | ) 79 | apply_standard_settings(flutter_wrapper_app) 80 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 81 | target_include_directories(flutter_wrapper_app PUBLIC 82 | "${WRAPPER_ROOT}/include" 83 | ) 84 | add_dependencies(flutter_wrapper_app flutter_assemble) 85 | 86 | # === Flutter tool backend === 87 | # _phony_ is a non-existent file to force this command to run every time, 88 | # since currently there's no way to get a full input/output list from the 89 | # flutter tool. 90 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") 91 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) 92 | add_custom_command( 93 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 94 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} 95 | ${CPP_WRAPPER_SOURCES_APP} 96 | ${PHONY_OUTPUT} 97 | COMMAND ${CMAKE_COMMAND} -E env 98 | ${FLUTTER_TOOL_ENVIRONMENT} 99 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" 100 | ${FLUTTER_TARGET_PLATFORM} $ 101 | VERBATIM 102 | ) 103 | add_custom_target(flutter_assemble DEPENDS 104 | "${FLUTTER_LIBRARY}" 105 | ${FLUTTER_LIBRARY_HEADERS} 106 | ${CPP_WRAPPER_SOURCES_CORE} 107 | ${CPP_WRAPPER_SOURCES_PLUGIN} 108 | ${CPP_WRAPPER_SOURCES_APP} 109 | ) 110 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void RegisterPlugins(flutter::PluginRegistry* registry) { 16 | BitsdojoWindowPluginRegisterWithRegistrar( 17 | registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); 18 | ScreenRetrieverPluginRegisterWithRegistrar( 19 | registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); 20 | SystemTrayPluginRegisterWithRegistrar( 21 | registry->GetRegistrarForPlugin("SystemTrayPlugin")); 22 | UrlLauncherWindowsRegisterWithRegistrar( 23 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 24 | WindowManagerPluginRegisterWithRegistrar( 25 | registry->GetRegistrarForPlugin("WindowManagerPlugin")); 26 | } 27 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | bitsdojo_window_windows 7 | screen_retriever 8 | system_tray 9 | url_launcher_windows 10 | window_manager 11 | ) 12 | 13 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 14 | rust_lib_vnt_app 15 | ) 16 | 17 | set(PLUGIN_BUNDLED_LIBRARIES) 18 | 19 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 20 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 21 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 24 | endforeach(plugin) 25 | 26 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 27 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 28 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 29 | endforeach(ffi_plugin) 30 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | set(CMAKE_SYSTEM_VERSION 6.1) 4 | add_definitions(-D_WIN32_WINNT=0x0601) 5 | 6 | # Define the application target. To change its name, change BINARY_NAME in the 7 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 8 | # work. 9 | # 10 | # Any new source files that you add to the application should be added here. 11 | add_executable(${BINARY_NAME} WIN32 12 | "flutter_window.cpp" 13 | "main.cpp" 14 | "utils.cpp" 15 | "win32_window.cpp" 16 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 17 | "Runner.rc" 18 | "runner.exe.manifest" 19 | ) 20 | 21 | # Apply the standard set of build settings. This can be removed for applications 22 | # that need different build settings. 23 | apply_standard_settings(${BINARY_NAME}) 24 | 25 | # Add preprocessor definitions for the build version. 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 29 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 30 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 31 | 32 | # Disable Windows macros that collide with C++ standard library functions. 33 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 34 | 35 | # Add dependency libraries and include directories. Add any application-specific 36 | # dependencies here. 37 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 38 | target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") 39 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 40 | 41 | # Run the Flutter tool portions of the build. This must not be removed. 42 | add_dependencies(${BINARY_NAME} flutter_assemble) 43 | 44 | SET_TARGET_PROPERTIES(${BINARY_NAME} PROPERTIES LINK_FLAGS "/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\" /SUBSYSTEM:WINDOWS") 45 | 46 | 47 | set(DLLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../dlls") 48 | 49 | # Copy the entire DLLs directory to the output directory 50 | add_custom_command(TARGET ${BINARY_NAME} POST_BUILD 51 | COMMAND ${CMAKE_COMMAND} -E copy_directory 52 | ${DLLS_DIR} 53 | $/dlls) -------------------------------------------------------------------------------- /windows/runner/Runner.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | #include "resource.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "winres.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (United States) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_APP_ICON ICON "resources\\app_icon.ico" 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) 64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0,0 67 | #endif 68 | 69 | #if defined(FLUTTER_VERSION) 70 | #define VERSION_AS_STRING FLUTTER_VERSION 71 | #else 72 | #define VERSION_AS_STRING "1.0.0" 73 | #endif 74 | 75 | VS_VERSION_INFO VERSIONINFO 76 | FILEVERSION VERSION_AS_NUMBER 77 | PRODUCTVERSION VERSION_AS_NUMBER 78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 79 | #ifdef _DEBUG 80 | FILEFLAGS VS_FF_DEBUG 81 | #else 82 | FILEFLAGS 0x0L 83 | #endif 84 | FILEOS VOS__WINDOWS32 85 | FILETYPE VFT_APP 86 | FILESUBTYPE 0x0L 87 | BEGIN 88 | BLOCK "StringFileInfo" 89 | BEGIN 90 | BLOCK "040904e4" 91 | BEGIN 92 | VALUE "CompanyName", "com.example" "\0" 93 | VALUE "FileDescription", "vnt_app" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "vnt_app" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "vnt_app.exe" "\0" 98 | VALUE "ProductName", "vnt_app" "\0" 99 | VALUE "ProductVersion", VERSION_AS_STRING "\0" 100 | END 101 | END 102 | BLOCK "VarFileInfo" 103 | BEGIN 104 | VALUE "Translation", 0x409, 1252 105 | END 106 | END 107 | 108 | #endif // English (United States) resources 109 | ///////////////////////////////////////////////////////////////////////////// 110 | 111 | 112 | 113 | #ifndef APSTUDIO_INVOKED 114 | ///////////////////////////////////////////////////////////////////////////// 115 | // 116 | // Generated from the TEXTINCLUDE 3 resource. 117 | // 118 | 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | 30 | flutter_controller_->engine()->SetNextFrameCallback([&]() { 31 | this->Show(); 32 | }); 33 | 34 | // Flutter can complete the first frame before the "show window" callback is 35 | // registered. The following call ensures a frame is pending to ensure the 36 | // window is shown. It is a no-op if the first frame hasn't completed yet. 37 | flutter_controller_->ForceRedraw(); 38 | 39 | return true; 40 | } 41 | 42 | void FlutterWindow::OnDestroy() { 43 | if (flutter_controller_) { 44 | flutter_controller_ = nullptr; 45 | } 46 | 47 | Win32Window::OnDestroy(); 48 | } 49 | 50 | LRESULT 51 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 52 | WPARAM const wparam, 53 | LPARAM const lparam) noexcept { 54 | // Give Flutter, including plugins, an opportunity to handle window messages. 55 | if (flutter_controller_) { 56 | std::optional result = 57 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 58 | lparam); 59 | if (result) { 60 | return *result; 61 | } 62 | } 63 | 64 | switch (message) { 65 | case WM_FONTCHANGE: 66 | flutter_controller_->engine()->ReloadSystemFonts(); 67 | break; 68 | } 69 | 70 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 71 | } 72 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.Create(L"vnt_app", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/VntApp/a74d60b67e3fcd67990bdd953bfe03e74f13656e/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | unsigned int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr) 51 | -1; // remove the trailing null character 52 | int input_length = (int)wcslen(utf16_string); 53 | std::string utf8_string; 54 | if (target_length == 0 || target_length > utf8_string.max_size()) { 55 | return utf8_string; 56 | } 57 | utf8_string.resize(target_length); 58 | int converted_length = ::WideCharToMultiByte( 59 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 60 | input_length, utf8_string.data(), target_length, nullptr, nullptr); 61 | if (converted_length == 0) { 62 | return std::string(); 63 | } 64 | return utf8_string; 65 | } 66 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /windows/runner/win32_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_WIN32_WINDOW_H_ 2 | #define RUNNER_WIN32_WINDOW_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be 11 | // inherited from by classes that wish to specialize with custom 12 | // rendering and input handling 13 | class Win32Window { 14 | public: 15 | struct Point { 16 | unsigned int x; 17 | unsigned int y; 18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {} 19 | }; 20 | 21 | struct Size { 22 | unsigned int width; 23 | unsigned int height; 24 | Size(unsigned int width, unsigned int height) 25 | : width(width), height(height) {} 26 | }; 27 | 28 | Win32Window(); 29 | virtual ~Win32Window(); 30 | 31 | // Creates a win32 window with |title| that is positioned and sized using 32 | // |origin| and |size|. New windows are created on the default monitor. Window 33 | // sizes are specified to the OS in physical pixels, hence to ensure a 34 | // consistent size this function will scale the inputted width and height as 35 | // as appropriate for the default monitor. The window is invisible until 36 | // |Show| is called. Returns true if the window was created successfully. 37 | bool Create(const std::wstring& title, const Point& origin, const Size& size); 38 | 39 | // Show the current window. Returns true if the window was successfully shown. 40 | bool Show(); 41 | 42 | // Release OS resources associated with window. 43 | void Destroy(); 44 | 45 | // Inserts |content| into the window tree. 46 | void SetChildContent(HWND content); 47 | 48 | // Returns the backing Window handle to enable clients to set icon and other 49 | // window properties. Returns nullptr if the window has been destroyed. 50 | HWND GetHandle(); 51 | 52 | // If true, closing this window will quit the application. 53 | void SetQuitOnClose(bool quit_on_close); 54 | 55 | // Return a RECT representing the bounds of the current client area. 56 | RECT GetClientArea(); 57 | 58 | protected: 59 | // Processes and route salient window messages for mouse handling, 60 | // size change and DPI. Delegates handling of these to member overloads that 61 | // inheriting classes can handle. 62 | virtual LRESULT MessageHandler(HWND window, 63 | UINT const message, 64 | WPARAM const wparam, 65 | LPARAM const lparam) noexcept; 66 | 67 | // Called when CreateAndShow is called, allowing subclass window-related 68 | // setup. Subclasses should return false if setup fails. 69 | virtual bool OnCreate(); 70 | 71 | // Called when Destroy is called. 72 | virtual void OnDestroy(); 73 | 74 | private: 75 | friend class WindowClassRegistrar; 76 | 77 | // OS callback called by message pump. Handles the WM_NCCREATE message which 78 | // is passed when the non-client area is being created and enables automatic 79 | // non-client DPI scaling so that the non-client area automatically 80 | // responds to changes in DPI. All other messages are handled by 81 | // MessageHandler. 82 | static LRESULT CALLBACK WndProc(HWND const window, 83 | UINT const message, 84 | WPARAM const wparam, 85 | LPARAM const lparam) noexcept; 86 | 87 | // Retrieves a class instance pointer for |window| 88 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 89 | 90 | // Update the window frame's theme to match the system theme. 91 | static void UpdateTheme(HWND const window); 92 | 93 | bool quit_on_close_ = false; 94 | 95 | // window handle for top level window. 96 | HWND window_handle_ = nullptr; 97 | 98 | // window handle for hosted content. 99 | HWND child_content_ = nullptr; 100 | }; 101 | 102 | #endif // RUNNER_WIN32_WINDOW_H_ 103 | --------------------------------------------------------------------------------