Skip to content

Commit

Permalink
Deeplink Support for Desktop (#1272)
Browse files Browse the repository at this point in the history
* implemented deeplink for macos

* Setup for windows.

* Setup for Linux.

* Fix compile issue and other changes.

* Update checksum.

* Remove entitlements from debug, added swift format in macos.
  • Loading branch information
jigar-f authored Dec 26, 2024
1 parent fcb1687 commit 839e481
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 90 deletions.
7 changes: 0 additions & 7 deletions .run/desktop.run.xml

This file was deleted.

3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ macos: macos-arm64
${DESKTOP_LIB_NAME}_amd64.dylib \
-output ${DARWIN_LIB_NAME}
install_name_tool -id "@rpath/${DARWIN_LIB_NAME}" ${DARWIN_LIB_NAME}
rm -Rf ${DESKTOP_LIB_NAME}_arm64.dylib ${DESKTOP_LIB_NAME}_amd64.dylib

$(INSTALLER_NAME).dmg: require-version require-appdmg require-retry require-magick
@echo "Generating distribution package for darwin/amd64..." && \
Expand Down Expand Up @@ -733,7 +734,7 @@ assert-go-version:

.PHONY: swift-format
swift-format:
swift-format --in-place --recursive DBModule ios/Runner ios/Tunnel ios/LanternTests
swift-format --in-place --recursive DBModule ios/Runner ios/Tunnel ios/LanternTests macos/Runner

clean:
rm -f liblantern*.aar && \
Expand Down
3 changes: 0 additions & 3 deletions lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,6 @@ class _LanternAppState extends State<LanternApp>
}

DeepLink navigateToDeepLink(PlatformDeepLink deepLink) {
if (!Platform.isAndroid) {
return DeepLink.defaultPath;
}
logger.d("DeepLink configuration: ${deepLink.configuration.toString()}");
if (deepLink.path.toLowerCase().startsWith('/report-issue')) {
logger.d("DeepLink uri: ${deepLink.uri.toString()}");
Expand Down
149 changes: 80 additions & 69 deletions linux/my_application.cc
Original file line number Diff line number Diff line change
@@ -1,102 +1,113 @@
#include "my_application.h"

#include <flutter_linux/flutter_linux.h>

#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif

#include "flutter/generated_plugin_registrant.h"

struct _MyApplication {
GtkApplication parent_instance;
char** dart_entrypoint_arguments;
GtkApplication parent_instance;
char **dart_entrypoint_arguments;
};

G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION
)

// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
MyApplication* self = MY_APPLICATION(application);
GtkWindow* window =
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));

// Use a header bar when running in GNOME as this is the common style used
// by applications and is the setup most users will be using (e.g. Ubuntu
// desktop).
// If running on X and not using GNOME then just use a traditional title bar
// in case the window manager does more exotic layout, e.g. tiling.
// If running on Wayland assume the header bar will work (may need changing
// if future cases occur).
gboolean use_header_bar = TRUE;
static void my_application_activate(GApplication *application) {
MyApplication * self = MY_APPLICATION(application);
GList *windows = gtk_application_get_windows(GTK_APPLICATION(application));
if (windows) {
gtk_window_present(GTK_WINDOW(windows->data));
return;
}
GtkWindow *window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));

// Use a header bar when running in GNOME as this is the common style used
// by applications and is the setup most users will be using (e.g. Ubuntu
// desktop).
// If running on X and not using GNOME then just use a traditional title bar
// in case the window manager does more exotic layout, e.g. tiling.
// If running on Wayland assume the header bar will work (may need changing
// if future cases occur).
gboolean use_header_bar = TRUE;
#ifdef GDK_WINDOWING_X11
GdkScreen* screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) {
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
GdkScreen* screen = gtk_window_get_screen(window);
if (GDK_IS_X11_SCREEN(screen)) {
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
use_header_bar = FALSE;
}
}
}
#endif
if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "Lantern");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
gtk_window_set_title(window, "Lantern");
}
if (use_header_bar) {
GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "Lantern");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
gtk_window_set_title(window, "Lantern");
}

gtk_window_set_default_size(window, 360, 712);
gtk_widget_show(GTK_WIDGET(window));
gtk_window_set_default_size(window, 360, 712);
gtk_widget_show(GTK_WIDGET(window));

g_autoptr(FlDartProject) project = fl_dart_project_new();
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
g_autoptr(FlDartProject)
project = fl_dart_project_new();
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);

FlView* view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
FlView *view = fl_view_new(project);
gtk_widget_show(GTK_WIDGET(view));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));

fl_register_plugins(FL_PLUGIN_REGISTRY(view));
fl_register_plugins(FL_PLUGIN_REGISTRY(view));

gtk_widget_grab_focus(GTK_WIDGET(view));
gtk_widget_grab_focus(GTK_WIDGET(view));
}

// Implements GApplication::local_command_line.
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
MyApplication* self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);

g_autoptr(GError) error = nullptr;
if (!g_application_register(application, nullptr, &error)) {
g_warning("Failed to register: %s", error->message);
*exit_status = 1;
return TRUE;
}

g_application_activate(application);
*exit_status = 0;

return TRUE;
static gboolean
my_application_local_command_line(GApplication *application, gchar ***arguments, int *exit_status) {
MyApplication * self = MY_APPLICATION(application);
// Strip out the first argument as it is the binary name.
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);

g_autoptr(GError)
error = nullptr;
if (!g_application_register(application, nullptr, &error)) {
g_warning("Failed to register: %s", error->message);
*exit_status = 1;
return TRUE;
}

g_application_activate(application);
*exit_status = 0;

return FALSE;
}

// Implements GObject::dispose.
static void my_application_dispose(GObject* object) {
MyApplication* self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
static void my_application_dispose(GObject *object) {
MyApplication * self = MY_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
}

static void my_application_class_init(MyApplicationClass* klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
static void my_application_class_init(MyApplicationClass *klass) {
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
}

static void my_application_init(MyApplication* self) {}
static void my_application_init(MyApplication * self) {}

MyApplication* my_application_new() {
return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID,
nullptr)); }
MyApplication *my_application_new() {
return MY_APPLICATION(g_object_new(my_application_get_type(),
"application-id", APPLICATION_ID,
"flags", G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN,
nullptr));
}
8 changes: 4 additions & 4 deletions macos/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,10 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = ACZRKC3LQ9;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Lantern;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down Expand Up @@ -724,10 +724,10 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = ACZRKC3LQ9;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Lantern;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down
18 changes: 18 additions & 0 deletions macos/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
import Cocoa
import FlutterMacOS
import app_links

@main
class AppDelegate: FlutterAppDelegate {

public override func application(
_ application: NSApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([any NSUserActivityRestoring]) -> Void
) -> Bool {

guard let url = AppLinks.shared.getUniversalLink(userActivity) else {
return false
}

AppLinks.shared.handleLink(link: url.absoluteString)

return false
}

override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return false
}

}
8 changes: 6 additions & 2 deletions macos/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FlutterDeepLinkingEnabled</key>
<false/>
<key>LSApplicationCategoryType</key>
<string></string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
Expand All @@ -28,7 +32,7 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
5 changes: 5 additions & 0 deletions macos/Runner/Release.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>webcredentials:lantern.io</string>
<string>applinks:lantern.io</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
</dict>
Expand Down
44 changes: 42 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
archive:
dependency: transitive
description:
name: archive
sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
args:
dependency: transitive
description:
Expand Down Expand Up @@ -350,6 +358,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.1"
console:
dependency: transitive
description:
name: console
sha256: e04e7824384c5b39389acdd6dc7d33f3efe6b232f6f16d7626f194f6a01ad69a
url: "https://pub.dev"
source: hosted
version: "4.1.0"
convert:
dependency: transitive
description:
Expand Down Expand Up @@ -880,10 +896,10 @@ packages:
dependency: "direct main"
description:
name: get_it
sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103
sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
url: "https://pub.dev"
source: hosted
version: "8.0.3"
version: "7.7.0"
gettext_parser:
dependency: transitive
description:
Expand Down Expand Up @@ -988,6 +1004,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.0.6"
image:
dependency: transitive
description:
name: image
sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6"
url: "https://pub.dev"
source: hosted
version: "4.5.2"
in_app_purchase:
dependency: "direct main"
description:
Expand Down Expand Up @@ -1193,6 +1217,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.4.4"
msix:
dependency: "direct dev"
description:
name: msix
sha256: c50d6bd1aafe0d071a3c1e5a5ccb056404502935cb0a549e3178c4aae16caf33
url: "https://pub.dev"
source: hosted
version: "3.16.8"
nested:
dependency: transitive
description:
Expand Down Expand Up @@ -1401,6 +1433,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
posix:
dependency: transitive
description:
name: posix
sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
url: "https://pub.dev"
source: hosted
version: "6.0.1"
process:
dependency: transitive
description:
Expand Down
Loading

0 comments on commit 839e481

Please sign in to comment.