Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux Support #20

Closed
edeuss opened this issue May 4, 2022 · 24 comments
Closed

Linux Support #20

edeuss opened this issue May 4, 2022 · 24 comments

Comments

@edeuss
Copy link

edeuss commented May 4, 2022

Would be great to have Linux support!

@markvideon
Copy link

markvideon commented Jan 2, 2023

@edeuss I recently published Desktop Entry that might be helpful. It includes an example project that uses Deep Links.

It uses the Desktop Entry Specification in conjunction with DBus to launch an app from a custom scheme URI or open it in an existing instance of the app if one is already open.

I think the primary reason this problem has not been handled by various packages is that the operations to register a custom scheme would be best performed by an installer / distributor. E.g. Flatpak, Steam etc.

One notable issue is that how other applications handle your custom URI is not within your control. E.g. Firefox might treat your URI as a Google Search query. You can use Desktop Entry to tell the OS that your app handles the scheme, but other apps (e.g. web browsers) may not necessarily honour that.

@CaptainDario
Copy link

@markvideon do you have an idea how one could handle it for a snap?

@LucasXu0
Copy link
Contributor

LucasXu0 commented Aug 24, 2023

I have implemented the deep linking feature on Linux.

Initially, I followed the suggestion from @markvideon and implemented it on Linux. However, it's too complicated for the setup step.

Later, my colleague hinted to me that there's a package named gtk.dart which might be helpful. So, I integrated it, and it works perfectly on my PC. Here's the video for reference:

showcase.mp4

It just needs a few steps to set up:

  • Modify the application.cc by following the documentation for gtk.dart.
  • Create a GtkApplicationNotifier variable and add the command line listener to it.
  • Add x-scheme-handler to your desktop file.
  • Done!

@CaptainDario
Copy link

@LucasXu0 wow! Really appreciate your work! If using your second approach, does it also work in Snap and Flatpak?

@LucasXu0
Copy link
Contributor

@CaptainDario Yes. The running application in the video was built by flatpak. I didn't verify it on snap, but I suppose that it should work too.

@CaptainDario
Copy link

CaptainDario commented Aug 24, 2023

Wow, then this is really awesome! Hopefully, it gets included in this package.
I am not sure when, but I will try it on Snap soonish.

@LucasXu0
Copy link
Contributor

LucasXu0 commented Aug 25, 2023

Would you mind trying it with commit? Because I've made several modifications to my forked repo, and cleaning up the test code will require some time.

Override these deps in the pubspec.yaml.

dependency_overrides:
  app_links:
    git:
      url: https://github.com/LucasXu0/app_links
      ref: c64ce17
  url_protocol:
    git:
      url: https://github.com/LucasXu0/flutter_url_protocol.git
      commit: 77a8420

Furthermore, please refer to this PR.

@CaptainDario
Copy link

CaptainDario commented Aug 25, 2023

Sure would love to give it a try!

So I have to

  1. override deps
dependency_overrides:
  app_links:
    git:
      url: https://github.com/LucasXu0/app_links
      ref: c64ce17
  url_protocol:
    git:
      url: https://github.com/LucasXu0/flutter_url_protocol.git
      commit: 77a8420
  1. my_application_activate(): activate an existing window if present
diff --git a/example/linux/my_application.cc b/example/linux/my_application.cc
index 5cd43c6..94e7215 100644
--- a/linux/my_application.cc
+++ b/linux/my_application.cc
@@ -20,6 +20,12 @@ static void my_application_activate(GApplication* application) {
   GtkWindow* window =
       GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
 
+  GList* windows = gtk_application_get_windows(GTK_APPLICATION(application));
+  if (windows) {
+    gtk_window_present(GTK_WINDOW(windows->data));
+    return;
+  }
+
   // 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).
  1. my_application_local_command_line(): return FALSE to allow the package to handle the command line
--- a/linux/my_application.cc
+++ b/linux/my_application.cc
@@ -81,7 +81,7 @@ static gboolean my_application_local_command_line(GApplication* application,
   g_application_activate(application);
   *exit_status = 0;
 
-  return TRUE;
+  return FALSE;
 }
 
 // Implements GObject::dispose.
  1. my_application_new(): replace G_APPLICATION_NON_UNIQUE with
--- a/linux/my_application.cc
+++ b/linux/my_application.cc
@@ -101,7 +101,8 @@ static void my_application_class_init(MyApplicationClass* klass) {
 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, "flags",
-                                     G_APPLICATION_NON_UNIQUE, nullptr));
+  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));
 }

And I should be good to go, right? Or am I missing something?
Do I also need the gtk package?

@LucasXu0
Copy link
Contributor

LucasXu0 commented Aug 28, 2023

@CaptainDario Yes, That's all. You don't need to import the gtk package.

Does it work?

One more thing, please note that your application ID (APPLICATION_ID) should match the ID in your snap/flathub yaml file.

@cocorax
Copy link

cocorax commented Aug 28, 2023

@LucasXu0 Hi, I tested it on friday and once registered via xdg-mime it works flawlessly. I did not test it with snap/flathub however, just plain build.

The only change I had to make is regarding the GTK setup, placing the gtk_application_get_windows call above the window creation, contrary to the documentation. Otherwise I would end up with an empty window.

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)));

I'm not familiar with GTK, but it makes sense to me since querying the window after creating one would find it and immediately return without finishing the setup.

@LucasXu0
Copy link
Contributor

Hi, @cocorax. Yes. You don't need to set up the other steps if you just intend to open your app via the scheme without processing the content received from the scheme.

@CaptainDario
Copy link

@LucasXu0 yes, works great! I tried it as a snap and everything is registered perfectly. My .desktop file

[Desktop Entry]
version=1.5
Name=DaKanji
Comment=You are learning Japanese? Then you need to try DaKanji!
Exec=dakanji %u
Icon=${SNAP}/data/flutter_assets/assets/images/dakanji/icon.png
Terminal=false
Type=Application
Categories=Education;Languages;
MimeType=x-scheme-handler/dakanji;

However, I also encountered the empty widow mentioned by @cocorax . Didn't try his work around yet.

@LucasXu0
Copy link
Contributor

@CaptainDario How did you change the my_application_activate function? My change is

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;
  }

@CaptainDario
Copy link

mine looks like this

// 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)));

  // app links support - start
  GList* windows = gtk_application_get_windows(GTK_APPLICATION(application));
  if (windows) {
    gtk_window_present(GTK_WINDOW(windows->data));
    return;
  }
  //  app links support - end

I am gonna try @cocorax 's work around

@CaptainDario
Copy link

Seems to be working like this

// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
  MyApplication* self = MY_APPLICATION(application);

  // app links support - start
  GList* windows = gtk_application_get_windows(GTK_APPLICATION(application));
  if (windows) {
    gtk_window_present(GTK_WINDOW(windows->data));
    return;
  }
  //  app links support - end

  GtkWindow* window =
      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));

Did not try as a snap yet but will do so later today

@CaptainDario
Copy link

@LucasXu0 any plans on opening an PR for this?

@CaptainDario
Copy link

@LucasXu0 how would one go about supporting universal links like on iOS? Something like https://my.cool.app/app/ . Is this possible?

@LucasXu0
Copy link
Contributor

@CaptainDario I have submitted the PR. #76

how would one go about supporting universal links like on iOS? Something like https://my.cool.app/app/ . Is this possible?

It seems NO. Your URL format may only work on iOS or macOS.

@CaptainDario
Copy link

@LucasXu0 thank you for the info and also the PR!

@llfbandit
Copy link
Owner

Linux support is available in app_links 3.5.0-beta.1. Please have a look to the README file.
Feedback appreciated!

@llfbandit
Copy link
Owner

Can someone confirm it's working fine?

I've received an new issue about linux #84 but I don't have Linux OS to reproduce.

@cocorax
Copy link

cocorax commented Dec 13, 2023

I updated our project to 3.5.0-beta.3 this morning, so far it seems to work fine.

@llfbandit
Copy link
Owner

Released v3.5.0.

@raghavnaphade
Copy link

@LucasXu0 yes, works great! I tried it as a snap and everything is registered perfectly. My .desktop file

[Desktop Entry]
version=1.5
Name=DaKanji
Comment=You are learning Japanese? Then you need to try DaKanji!
Exec=dakanji %u
Icon=${SNAP}/data/flutter_assets/assets/images/dakanji/icon.png
Terminal=false
Type=Application
Categories=Education;Languages;
MimeType=x-scheme-handler/dakanji;

However, I also encountered the empty widow mentioned by @cocorax . Didn't try his work around yet.

Hi
I am new to linux flutter.
Do we have to manually create .desktop file?

and can you give me code in main.dart file.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants