llfbandit / app_links

Android App Links, Deep Links, iOs Universal Links and Custom URL schemes handler for Flutter.
https://pub.dev/packages/app_links
Apache License 2.0
176 stars 68 forks source link

Linux Support #20

Closed edeuss closed 6 months ago

edeuss commented 2 years ago

Would be great to have Linux support!

markvideon commented 1 year ago

@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 commented 1 year ago

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

LucasXu0 commented 10 months ago

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:

https://github.com/llfbandit/app_links/assets/11863087/bb29dc46-58aa-49ec-b23f-d299289e3731

It just needs a few steps to set up:

CaptainDario commented 10 months ago

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

LucasXu0 commented 10 months ago

@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 commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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

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

LucasXu0 commented 10 months ago

@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 commented 10 months ago

@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 commented 10 months ago

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 commented 10 months ago

@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 commented 10 months ago

@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 commented 10 months ago

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 commented 10 months ago

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 commented 9 months ago

@LucasXu0 any plans on opening an PR for this?

CaptainDario commented 9 months ago

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

LucasXu0 commented 9 months ago

@CaptainDario I have submitted the PR. https://github.com/llfbandit/app_links/pull/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 commented 9 months ago

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

llfbandit commented 7 months ago

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

llfbandit commented 7 months ago

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 commented 6 months ago

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

llfbandit commented 6 months ago

Released v3.5.0.

raghavnaphade commented 4 months ago

@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