Search code examples
electronelectron-builder

Does electron's registerHttpProtocol work in development?


I'm trying to register a custom protocol with electron. I want it to be a redirect location that a website can use to provide an api key (like myprotocol://example/payload=api-key). I have been using electron's registerHttpProtocol and also tried electron's interceptHttpProtocol.

But, when the website tries to redirect to my protocol my electron app doesn't do anything. The website goes to myprotocol://example/payload=api-key, and registers a "page doesn't exist error"--while nothing happens in my app.

This is in a development environment. I've seen some discussion about custom protocols that assume a production environment.

Can you register a custom protocol with electron in development?

Why am I not able to intercept the website's going to the protocol I've set out?

Here's my code:

main.js:

app.whenReady().then(() => {
  protocol.registerHttpProtocol('examplep', (request, callback) => {
     console.log("examplep", request);
     callback('it-worked');
  }, (error) => {
        if (error) console.error('Failed to register protocol = ' + error)
  })

  protocol.interceptHttpProtocol("examplep", function (request, callback) {  //I've tried both registerHttp... and interceptHttp... methods, so including both here; though I think in practice only one should be required
    console.log('intercepted!' + request)
    callback(request);
  });
})

redirect url provided to website:

'http://examplep'

And I've whitelisted this url on the website itself.

I've also tried related methods registerStringProtocol, interceptStringProtocol, registerFileProtocol, and interceptFileProtocol, without success.


What am I missing?


Solution

  • Sounds like you need to support deep linking for a desktop app, which is done via a Custom URI Scheme and is registered with setAsDefaultProtocolClient. When your Electron app starts up write this code to register the scheme, on the main side of your app:

    const customScheme = 'x-mycompany-myapp';
    app.setAsDefaultProtocolClient(customScheme);
    

    The custom scheme can be tested from the command line like this, eg on macOS or Windows:

    open  x-mycompany-myapp:/some/location
    start x-mycompany-myapp:/some/location
    

    The notification will be received within the main side of your app and on Windows will attempt to create a new instance of the app, in which case you need to detect this condition, process the notification then cancel the new app instance. On macOS it will be received within the open-url event, so you register it like this:

    app.on('open-url', myCallback);
    

    Once the main side of the Electron app has the notification, it needs to get the URL information and forward it to the renderer process. You can use ipcMain events for this.

    EXAMPLE APP

    Since the code is a little tricky, here is some example code that may be useful, to give you something to compare against. If it helps you can also run the app by following the instructions in the blog post:

    My use case is around receiving OAuth responses after signing in from the system browser. Hopefully you can borrow some ideas from it related to deep linking though.

    INFO.PLIST

    My understand is that in a development environment (on macOS) deep links work when the app is running, but if you stop the app and attempt a deep link it will not start the app.

    You can only resolve this for a packaged app, which requires an info.plist. In my code sample the info.plist is generated from build protocol entries in the package.json file.

    My code sample is packaged in a basic way by the Electron Packager, so when I run npm run pack, the app is built to a dist folder. I can then run the packaged version of the app and it gets registered with the system.