diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index caa143632..968ae34e8 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -15,6 +15,8 @@ import 'package:flutter_hbb/models/peer_model.dart'; import 'package:flutter_hbb/utils/multi_window_manager.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:uni_links/uni_links.dart'; +import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:window_manager/window_manager.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:window_size/window_size.dart' as window_size; @@ -1178,6 +1180,49 @@ Future restoreWindowPosition(WindowType type, {int? windowId}) async { return false; } +/// Initialize uni links for macos/windows +/// +/// [Availability] +/// initUniLinks should only be used on macos/windows. +/// we use dbus for linux currently. +Future initUniLinks() async { + if (!Platform.isWindows && !Platform.isMacOS) { + return; + } + if (Platform.isWindows) { + registerProtocol('rustdesk'); + } + // check cold boot + try { + final initialLink = await getInitialLink(); + if (initialLink == null) { + return; + } + parseRustdeskUri(initialLink); + } catch (err) { + debugPrint("$err"); + } +} + +StreamSubscription listenUniLinks() { + if (Platform.isWindows || Platform.isMacOS) { + final sub = uriLinkStream.listen((Uri? uri) { + if (uri != null) { + callUniLinksUriHandler(uri); + } else { + print("uni listen error: uri is empty."); + } + }, onError: (err) { + print("uni links error: $err"); + }); + return sub; + } else { + // return empty stream subscription for uniform logic + final stream = Stream.empty(); + return stream.listen((event) {/*ignore*/}); + } +} + void checkArguments() { // check connect args final connectIndex = bootArgs.indexOf("--connect"); @@ -1208,6 +1253,12 @@ void parseRustdeskUri(String uriPath) { print("uri is not valid: $uriPath"); return; } + callUniLinksUriHandler(uri); +} + +/// uri handler +void callUniLinksUriHandler(Uri uri) { + debugPrint("uni links called: $uri"); // new connection if (uri.authority == "connection" && uri.path.startsWith("/new/")) { final peerId = uri.path.substring("/new/".length); diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index a31a71802..d22f740cb 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -37,6 +37,7 @@ class _DesktopHomePageState extends State @override bool get wantKeepAlive => true; var updateUrl = ''; + StreamSubscription? _uniLinksSubscription; @override void onWindowClose() async { @@ -455,12 +456,14 @@ class _DesktopHomePageState extends State Future.delayed(Duration.zero, () { checkArguments(); }); + _uniLinksSubscription = listenUniLinks(); } @override void dispose() { trayManager.removeListener(this); windowManager.removeListener(this); + _uniLinksSubscription?.cancel(); super.dispose(); } } diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 5009e68a1..6f69a9c2b 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; @@ -13,6 +14,7 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:uni_links_desktop/uni_links_desktop.dart'; import 'package:window_manager/window_manager.dart'; // import 'package:window_manager/window_manager.dart'; @@ -89,6 +91,8 @@ Future initEnv(String appType) async { } void runMainApp(bool startService) async { + // register uni links + initUniLinks(); await initEnv(kAppTypeMain); // trigger connection status updater await bind.mainCheckConnectStatus(); diff --git a/flutter/macos/Runner/Info.plist b/flutter/macos/Runner/Info.plist index 4789daa6a..8245f21a0 100644 --- a/flutter/macos/Runner/Info.plist +++ b/flutter/macos/Runner/Info.plist @@ -28,5 +28,18 @@ MainMenu NSPrincipalClass NSApplication + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + + CFBundleURLSchemes + + rustdesk + + + diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 190a6ffa4..da086aab1 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -64,7 +64,7 @@ dependencies: desktop_multi_window: git: url: https://github.com/Kingtous/rustdesk_desktop_multi_window - ref: f25487b8aacfcc9d22b86a84e97eda1a5c07ccaf + ref: 318ebd0a70cc5868911591c04f84bf1541f1bf4e freezed_annotation: ^2.0.3 tray_manager: git: @@ -95,6 +95,8 @@ dependencies: # git: # url: https://github.com/Kingtous/flutter_improved_scrolling # ref: 62f09545149f320616467c306c8c5f71714a18e6 + uni_links: ^0.5.1 + uni_links_desktop: ^0.1.3 dev_dependencies: icons_launcher: ^2.0.4 diff --git a/flutter/windows/runner/main.cpp b/flutter/windows/runner/main.cpp index 3921e03dd..66194ed42 100644 --- a/flutter/windows/runner/main.cpp +++ b/flutter/windows/runner/main.cpp @@ -7,6 +7,8 @@ #include "utils.h" // #include +#include + typedef char** (*FUNC_RUSTDESK_CORE_MAIN)(int*); typedef void (*FUNC_RUSTDESK_FREE_ARGS)( char**, int); @@ -14,6 +16,15 @@ typedef void (*FUNC_RUSTDESK_FREE_ARGS)( char**, int); int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { + // uni links dispatch + HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"rustdesk"); + if (hwnd != NULL) { + DispatchToUniLinksDesktop(hwnd); + + ::ShowWindow(hwnd, SW_NORMAL); + ::SetForegroundWindow(hwnd); + return EXIT_FAILURE; + } HINSTANCE hInstance = LoadLibraryA("librustdesk.dll"); if (!hInstance) {