Reputation: 6144
We have an electron crypto app that signs transactions (among other things).
We want other websites to have the ability to have a button that opens that electron app, pre-filled with some params (the transaction information).
flow is:
This could be done at runtime, or install time.
calling app.setAsDefaultProtocolClient
with the code of this gist, which is basically:
app.setAsDefaultProtocolClient("my-app")
But after I put my-app://foo?bar=baz
in chrome browser, I get the following popup, and pressing open-xdg does nothing (other than dismissing the popup)
Maybe there's a way to do so at install time through electron builder?
Thanks in advance for the help, I have no idea how to proceed here!
Upvotes: 42
Views: 31135
Reputation: 4290
All little bit different from above.
open-url fires before the ready event so you can store it in a variable and use within the widow did-finish-load.
let link;
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1280,
height: 720,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
mainWindow.openDevTools();
mainWindow.setContentProtection(true);
mainWindow.loadFile('index.html');
mainWindow.webContents.on("did-finish-load", function() {
mainWindow.webContents.send('link', link);
});
}
app.on('ready', createWindow);
// This will catch clicks on links such as <a href="protocols://abc=1">open in foobar</a>
app.on('open-url', function(event, url) {
link = url;
if (mainWindow?.webContents) {
mainWindow.webContents.send('link', link);
}
});
app.setAsDefaultProtocolClient('protocols');
You can then use the value in your render html like this.
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
const ipc = require("electron").ipcRenderer;
ipc.on("link", function (event, url) {
console.log(url);
console.log(parseQuery(decodeURI(url)));
});
function parseQuery(queryString) {
queryString = queryString.substring(queryString.indexOf("://") + 3);
var query = {};
var pairs = (queryString[0] === "?" ? queryString.substr(1) : queryString).split("&");
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split("=");
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
}
return query;
}
</script>
</body>
</html>
Upvotes: 1
Reputation: 18901
Since this may be relevant to what I’m doing at work, I decided to give it a go. I’ve only tested this on OSX though!
I looked at the documentation for app.setAsDefaultProtocolClient and it says this:
Note: On macOS, you can only register protocols that have been added to your app's info.plist, which can not be modified at runtime. You can however change the file with a simple text editor or script during build time. Please refer to Apple's documentation for details.
These protocols can be defined when packaging your app with electron-builder
. See build
:
{
"name": "foobar",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"dist": "electron-builder"
},
"devDependencies": {
"electron": "^3.0.7",
"electron-builder": "^20.38.2"
},
"dependencies": {},
"build": {
"appId": "foobar.id",
"mac": {
"category": "foo.bar.category"
},
"protocols": {
"name": "foobar-protocol",
"schemes": [
"foobar"
]
}
}
}
In your main thread:
const {app, BrowserWindow} = require('electron');
let mainWindow;
function createWindow () {
mainWindow = new BrowserWindow({width: 800, height: 600})
mainWindow.loadFile('index.html');
}
app.on('ready', createWindow);
var link;
// This will catch clicks on links such as <a href="foobar://abc=1">open in foobar</a>
app.on('open-url', function (event, data) {
event.preventDefault();
link = data;
});
app.setAsDefaultProtocolClient('foobar');
// Export so you can access it from the renderer thread
module.exports.getLink = () => link;
In your renderer thread:
Notice the use of the remote API to access the getLink
function exported in the main thread
<!DOCTYPE html>
<html>
<body>
<p>Received this data <input id="data"/></p>
<script>
const {getLink} = require('electron').remote.require('./main.js');
document.querySelector('#data').value = getLink();
</script>
</body>
</html>
Example
<a href="foobar://abc=1">open in foobar</a>
This also allows you to launch from the command line:
open "foobar://xyz=1"
How do you get back to the original caller?
I suppose that when you launch the app you could include the caller url:
<a href="foobar://abc=1&caller=example.com”>open in foobar</a>
When your electron app finishes processing data, it would simply ping back that url
Credits
Most of my findings are based on:
Upvotes: 66