tauri icon indicating copy to clipboard operation
tauri copied to clipboard

Feature: Custom URI scheme support (deep linking)

Open rihardsgravis opened this issue 5 years ago • 58 comments

Custom URL schemes provide a way to reference resources inside an app. Users tapping a custom URL e.g. yourapp://foo?bar in an email, for example, launch the app in a specified context. Other apps can also trigger the app to launch with specific context data; for example, a photo library app might display a specified image.

Tauri could have a simplified API to register/unregister the custom URI scheme protocol a listener.

A Rust package https://github.com/maidsafe/system_uri exists that does System App URI registration for macOS, Linux and Windows. Unfortunately, this package does not support passing also the url params to the application - it only triggers the application launch. An example implementation together with Tauri -https://github.com/iotaledger/spark-wallet/blob/master/src-tauri/src/main.rs

rihardsgravis avatar Jan 15 '20 10:01 rihardsgravis

The same goes for the "redirect uri" when authenticating with some external provider that uses Oauth (Auth0 for example).

wiredmatt avatar Jan 04 '21 03:01 wiredmatt

It'd be nice if there could be something similar to Electron's protocol API which lets you:

  • Register your application to be launched on custom URI schemes, I wonder if there's existing rust packages that support this already.
  • Add "protocol handlers" to the webview so that custom protocol schemes could invoke a function which returns a stream for the HTTP response. I think most webviews have some concept of this
  • Set privileges for certain custom protocols (this is probably hardest to do with public OS WebView APIs)

Regarding the protocol handlers, this is something that would need to be done in the webview dependency.

RangerMauve avatar Mar 03 '21 23:03 RangerMauve

In the dev branch of Tauri, we already use custom protocols to load web assets (See https://github.com/tauri-apps/wry/pull/65). However, you can't create your own, is this a feature that would be useful?

nklayman avatar Mar 04 '21 00:03 nklayman

@nklayman It'd be super useful for me! I'm working on a p2p web browser called Agregore which uses Electron's protocol handlers to support loading content from p2p protocols like IPFS and Hyprcore-protcol as well as indie protocols like Gemini.

I like electron, but it'd be nice to be able to go closer to the metal and ditch all the JavaScript that's on the backend and use Rust. 😁

RangerMauve avatar Mar 04 '21 00:03 RangerMauve

The other thing which I think is missing in a lot of webview libraries is the registerScemesAsPriviledged API that Electron provides.

This is what lets custom protocol handlers to access APIs which are normally only available via HTTPs as well as make the URL parser treat them as "proper" URLs so that they can get a correct hostname set rather than everything going into the pathname. Not sure if this is possible with Tauri, though.

RangerMauve avatar Apr 06 '21 21:04 RangerMauve

As a matter of fact, this is what wry is actually doing with its custom scheme @RangerMauve see:

https://github.com/tauri-apps/wry/blob/c49846cfc41bb548a685edeac5f8036501f7dcec/src/webview/mimetype.rs#L115

nothingismagick avatar Apr 08 '21 07:04 nothingismagick

Oh wow! That's really cool to see @nothingismagick

It'd be super handy if wry provided APIs to register different protocol schemes like that. I'd love to ditch all the extra bloat from Electron + Node!

RangerMauve avatar Apr 08 '21 19:04 RangerMauve

@RangerMauve https://github.com/tauri-apps/wry/pull/151/files

nothingismagick avatar Apr 10 '21 07:04 nothingismagick

#1553 is related to some of what has been discussed here (although that's not related to the original issue, which is just about deeplink support).

lucasfernog avatar Apr 21 '21 03:04 lucasfernog

Hello, I want to know how this function is progressing. I am using the dev branch of tauri and wry, but the registered protocol is still unavailable. Failed to launch'tes://az' because the scheme does not have a registered handler. For some applications that use oauth, this is a very convenient feature.

juzi5201314 avatar Jul 06 '21 14:07 juzi5201314

+1 or could someone show an example on how to use it?

tststs avatar Aug 07 '21 12:08 tststs

The work on this feature is frozen because we're focusing on bug fixes ahead of a stable release and our audit.

lucasfernog avatar Aug 08 '21 23:08 lucasfernog

@lucasfernog Thanks for the update! Is this something you'll be able to continue on after the release/audit?

RangerMauve avatar Aug 09 '21 16:08 RangerMauve

@lucasfernog Thanks for the update! Is this something you'll be able to continue on after the release/audit?

Yeah hopefully I can get back to it after the release.

lucasfernog avatar Aug 09 '21 16:08 lucasfernog

Sweet, I'm excited to see how it progresses. 😁 This functionality can enable a lot of interesting use cases (especially for people making experimental browsers like myself).

RangerMauve avatar Aug 09 '21 16:08 RangerMauve

@lucasfernog Sorry to push you on this but its a feature we need it ASAP for us to use with oath. Also please consider how to communicate the change in deeplink to sidecar

cloudsolace avatar Sep 06 '21 11:09 cloudsolace

@hellomocks - we are currently in a feature freeze while the audit is ongoing and have some important revision work to do, so as Lucas said, this is not something that the core team will be getting to before the end of September.

nothingismagick avatar Sep 06 '21 11:09 nothingismagick

@hellomocks - we are currently in a feature freeze while the audit is ongoing and have some important revision work to do, so as Lucas said, this is not something that the core team will be getting to before the end of September.

I would add, the custom URI support is handled by the registry keys on Windows and on macOS it's handled by a custom PLIST;

something like this may work;

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>CustomID</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>tauriapp</string>
    </array>
  </dict>
</array>

Tauri supports custom plist on macOS, for Windows registry key they can probably be done through a custom WIX template or you can do it in rust when the app launch for the first time. Linux with some research it can be done easily, but it depends how you package your app.

lemarier avatar Sep 06 '21 11:09 lemarier

or you can do it in rust when the app launch for the first time. Linux with some research it can be done easily, but it depends how you package your app.

The initial poster mentioned implementing this via the system_uri package and @Shot on Discord implemented a forked version of that crate. I tested it out as well using the mentioned library but with just the registry keys the default command will just keep opening new instances of the application instead of reusing the existing instance.

Are you aware of a way to intercept the triggers or to redirect the invocation to an existing window instead of opening a second instance?

ioneyed avatar Sep 15 '21 02:09 ioneyed

This can be achieved with WIX but currently don't understand how to get the context replacement working with fragments. However, the wix settings allow you to override the default template which can be modified to achieve this effort.

<Component Id="ApplicationURI" Guid="*">
                <RegistryKey Root="HKCR" Key="acme">
                    <RegistryValue Type="string" Value="acme" />
                    <RegistryValue Name="URL Protocol" Type="string" Value=""/>
                    <RegistryKey Key="shell">
                        <RegistryKey Key="open">
                            <RegistryKey Key="command">
                                <RegistryValue Type="string" Value='{{{app_exe_source}}} "%1"'/>
                            </RegistryKey>
                        </RegistryKey>
                    </RegistryKey>
                </RegistryKey>
            </Component>

I placed this component in the

 <DirectoryRef Id="INSTALLDIR">

section of the default WIX template (https://github.com/tauri-apps/tauri/blob/b0a8c38a736544cdd70fd10155e5ad3a25c81535/tooling/bundler/src/bundle/windows/templates/main.wxs)

Then I updated my tauri.conf.json bundle section to look the following:

"windows": {
        "certificateThumbprint": null,
        "digestAlgorithm": "sha256",
        "timestampUrl": "",
        "wix":{
          "template":"wixFragments/template.wxs" // <-- wixFragments is a folder in my src-tauri parent directory
        }
      }

This will create the registry keys under Computer\HKEY_CLASSES_ROOT\acme\shell\open\command which is where the file associates/commands live to be found for invocation. This will allow acme:// to open the application. I will caveat that this approach will launch a new instance every time it encounters the scheme. It will not re-use an existing instance and pass that information into the instance. I am still digging into that bit of work as well as how to make this part of a fragment instead of a custom template.

My list of items to continue investigating:

  • How to make it re-use an instance
  • How to invoke a command when a scheme is invoked with parameters
  • File associations (which is registry driven like custom uris)

ioneyed avatar Sep 16 '21 14:09 ioneyed

has there been any updates on this and if there are, is there an example?

RiChrisMurphy avatar Nov 15 '21 15:11 RiChrisMurphy

@RiChrisMurphy No, otherwise it would be listed or linked here...

FabianLars avatar Nov 15 '21 19:11 FabianLars

This seems like it would be useful for redirect uri for some OAuth2 flows as @system32uwu mentioned. Currently is there anyway to handle 3rd party OAuth authentication from a Tauri APP ?

vikigenius avatar Dec 10 '21 21:12 vikigenius

Hello @nothingismagick, any update on this ?

cloudsolace avatar Jan 17 '22 05:01 cloudsolace

This is all that's left for me before I make the switch from Electron. Woohoo! Can't wait for someone much smarter and capable than myself to PR this.

alectrocute avatar Jan 20 '22 22:01 alectrocute

Please, can people stop posting messages like "are there any updates" or comments in the "+1" spirit? FabianLars already said:

No, otherwise it would be listed or linked here...

A lot of people are subscribed to this issue since it is a well wanted feature. And everytime those people get a notification about these comments. It's just annoying :) With that being said, can these kind of comments be marked as off-topic, please? Including mine.

Thank you.

mainrs avatar Jan 20 '22 22:01 mainrs

This seems like it would be useful for redirect uri for some OAuth2 flows as system32uwu mentioned. Currently is there anyway to handle 3rd party OAuth authentication from a Tauri APP ?

@vikigenius I know it's been a long time since this was posted but I thought maybe my old, undocumented, probably suboptimal code might be of use to people trying to implement authentication using 3rd party providers in tauri: https://github.com/ohmree/stfu-old I don't remember exactly what I did there off the top of my head but I do remember having a functioning prototype, and there isn't that much code to read through so I believe anyone should be able to borrow the method I came up with (unless some major update somehow broke it while I was on a break from fiddling with tauri). Anyways I think I could help adapt this to other codebases if anyone's interested and can't figure it out on their own just from reading through the code, or maybe even contribute an example (but I might need some help with that).

ohmree avatar Feb 06 '22 01:02 ohmree

Hey everyone,

as I'm also waiting for updates for this, I kind of managed to come up with a workaround (more like a hackaround) for now to handle OAuth.

  1. Create a new window to handle OAuth.
  2. Create a Tauri command which checks whether the OAuth redirect was successful. If it is, redirect to the local app path to handle the success(e.g. tauri.localhost/oauth/success). I've done this with evaluating Javascript inside of Rust.
  3. In the source window, set an interval to invoke this command after the OAuth flow is initiated.

Hope this helps! 🥳

elvinaspredkelis avatar Apr 11 '22 06:04 elvinaspredkelis

@elvinaspredkelis that's certainly useful, I have finished my project half a year ago, but if you could provide a working example I'd be happy to port it from Qt to Tauri.

Something similar to what you propose I did with electron in another project, here. I just waited for the second window to redirect to the approved url and to contain "#access_token=", then split the string, grab the token and store it in a local config file, but I could've also replied to the event with the token which I think would've been better.

This would require Tauri to add events to the core library for windows to communicate between themselves (not sure if this is already implemented or not).

wiredmatt avatar Apr 11 '22 19:04 wiredmatt

@loicortola - thanks for bringing this up again, indeed we forgot about it. I spoke with @lucasfernog briefly this afternoon, and while it should be ok to make work, the devil (and the security auditing needed) will be in the details.

nothingismagick avatar Aug 22 '22 17:08 nothingismagick