diff --git a/ElectronNET.API/AutoUpdater.cs b/ElectronNET.API/AutoUpdater.cs
new file mode 100644
index 0000000..7a44162
--- /dev/null
+++ b/ElectronNET.API/AutoUpdater.cs
@@ -0,0 +1,96 @@
+using ElectronNET.API.Entities;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ElectronNET.API
+{
+ ///
+ /// Enable apps to automatically update themselves. Based on electron-updater.
+ ///
+ public sealed class AutoUpdater
+ {
+ private static AutoUpdater _autoUpdater;
+ private static object _syncRoot = new object();
+
+ internal AutoUpdater() { }
+
+ internal static AutoUpdater Instance
+ {
+ get
+ {
+ if (_autoUpdater == null)
+ {
+ lock (_syncRoot)
+ {
+ if (_autoUpdater == null)
+ {
+ _autoUpdater = new AutoUpdater();
+ }
+ }
+ }
+
+ return _autoUpdater;
+ }
+ }
+
+ ///
+ /// Asks the server whether there is an update.
+ ///
+ ///
+ public Task CheckForUpdatesAsync()
+ {
+ var taskCompletionSource = new TaskCompletionSource();
+ string guid = Guid.NewGuid().ToString();
+
+ BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesComplete" + guid, (updateCheckResult) =>
+ {
+ BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesComplete" + guid);
+ taskCompletionSource.SetResult(JObject.Parse(updateCheckResult.ToString()).ToObject());
+ });
+
+ BridgeConnector.Socket.Emit("autoUpdaterCheckForUpdates", guid);
+
+ return taskCompletionSource.Task;
+ }
+
+ ///
+ /// Asks the server whether there is an update.
+ ///
+ /// This will immediately download an update, then install when the app quits.
+ ///
+ ///
+ public Task CheckForUpdatesAndNotifyAsync()
+ {
+ var taskCompletionSource = new TaskCompletionSource();
+ string guid = Guid.NewGuid().ToString();
+
+ BridgeConnector.Socket.On("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid, (updateCheckResult) =>
+ {
+ BridgeConnector.Socket.Off("autoUpdaterCheckForUpdatesAndNotifyComplete" + guid);
+ taskCompletionSource.SetResult(JObject.Parse(updateCheckResult.ToString()).ToObject());
+ });
+
+ BridgeConnector.Socket.Emit("autoUpdaterCheckForUpdatesAndNotify", guid);
+
+ return taskCompletionSource.Task;
+ }
+
+ ///
+ /// Restarts the app and installs the update after it has been downloaded.
+ /// It should only be called after `update-downloaded` has been emitted.
+ ///
+ /// Note: QuitAndInstall() will close all application windows first and only emit `before-quit` event on `app` after that.
+ /// This is different from the normal quit event sequence.
+ ///
+ /// *windows-only* Runs the installer in silent mode. Defaults to `false`.
+ /// Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`.
+ public void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false)
+ {
+ BridgeConnector.Socket.Emit("autoUpdaterQuitAndInstall", isSilent, isForceRunAfter);
+ }
+ }
+}
diff --git a/ElectronNET.API/Electron.cs b/ElectronNET.API/Electron.cs
index 1f739d0..4206f89 100644
--- a/ElectronNET.API/Electron.cs
+++ b/ElectronNET.API/Electron.cs
@@ -15,6 +15,11 @@
///
public static App App { get { return App.Instance; } }
+ ///
+ /// Enable apps to automatically update themselves. Based on electron-updater.
+ ///
+ public static AutoUpdater AutoUpdater { get { return AutoUpdater.Instance; } }
+
///
/// Control your windows.
///
diff --git a/ElectronNET.API/Entities/BlockMapDataHolder.cs b/ElectronNET.API/Entities/BlockMapDataHolder.cs
new file mode 100644
index 0000000..9294ac0
--- /dev/null
+++ b/ElectronNET.API/Entities/BlockMapDataHolder.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ElectronNET.API.Entities
+{
+ ///
+ ///
+ ///
+ public class BlockMapDataHolder
+ {
+ ///
+ /// The file size. Used to verify downloaded size (save one HTTP request to get length).
+ /// Also used when block map data is embedded into the file(appimage, windows web installer package).
+ ///
+ public double Size { get; set; }
+
+ ///
+ /// The block map file size. Used when block map data is embedded into the file (appimage, windows web installer package).
+ /// This information can be obtained from the file itself, but it requires additional HTTP request,
+ /// so, to reduce request count, block map size is specified in the update metadata too.
+ ///
+ public double BlockMapSize { get; set; }
+
+ ///
+ /// The file checksum.
+ ///
+ public string Sha512 { get; set; }
+
+ ///
+ ///
+ ///
+ public bool IsAdminRightsRequired { get; set; }
+ }
+}
diff --git a/ElectronNET.API/Entities/ReleaseNoteInfo.cs b/ElectronNET.API/Entities/ReleaseNoteInfo.cs
new file mode 100644
index 0000000..c9ebf2a
--- /dev/null
+++ b/ElectronNET.API/Entities/ReleaseNoteInfo.cs
@@ -0,0 +1,18 @@
+namespace ElectronNET.API.Entities
+{
+ ///
+ ///
+ ///
+ public class ReleaseNoteInfo
+ {
+ ///
+ /// The version.
+ ///
+ public string Version { get; set; }
+
+ ///
+ /// The note.
+ ///
+ public string Note { get; set; }
+ }
+}
diff --git a/ElectronNET.API/Entities/UpdateCancellationToken.cs b/ElectronNET.API/Entities/UpdateCancellationToken.cs
new file mode 100644
index 0000000..f89348c
--- /dev/null
+++ b/ElectronNET.API/Entities/UpdateCancellationToken.cs
@@ -0,0 +1,29 @@
+namespace ElectronNET.API.Entities
+{
+ ///
+ ///
+ ///
+ public class UpdateCancellationToken
+ {
+ ///
+ ///
+ ///
+ public bool Cancelled { get; set; }
+
+ ///
+ ///
+ ///
+ public void Cancel()
+ {
+
+ }
+
+ ///
+ ///
+ ///
+ public void Dispose()
+ {
+
+ }
+ }
+}
diff --git a/ElectronNET.API/Entities/UpdateCheckResult.cs b/ElectronNET.API/Entities/UpdateCheckResult.cs
new file mode 100644
index 0000000..66c75aa
--- /dev/null
+++ b/ElectronNET.API/Entities/UpdateCheckResult.cs
@@ -0,0 +1,23 @@
+namespace ElectronNET.API.Entities
+{
+ ///
+ ///
+ ///
+ public class UpdateCheckResult
+ {
+ ///
+ ///
+ ///
+ public UpdateInfo UpdateInfo { get; set; } = new UpdateInfo();
+
+ ///
+ ///
+ ///
+ public string[] Download { get; set; }
+
+ ///
+ ///
+ ///
+ public UpdateCancellationToken CancellationToken { get; set; }
+ }
+}
diff --git a/ElectronNET.API/Entities/UpdateFileInfo.cs b/ElectronNET.API/Entities/UpdateFileInfo.cs
new file mode 100644
index 0000000..5f5d6f6
--- /dev/null
+++ b/ElectronNET.API/Entities/UpdateFileInfo.cs
@@ -0,0 +1,13 @@
+namespace ElectronNET.API.Entities
+{
+ ///
+ ///
+ ///
+ public class UpdateFileInfo : BlockMapDataHolder
+ {
+ ///
+ ///
+ ///
+ public string Url { get; set; }
+ }
+}
diff --git a/ElectronNET.API/Entities/UpdateInfo.cs b/ElectronNET.API/Entities/UpdateInfo.cs
new file mode 100644
index 0000000..5b33bf0
--- /dev/null
+++ b/ElectronNET.API/Entities/UpdateInfo.cs
@@ -0,0 +1,38 @@
+namespace ElectronNET.API.Entities
+{
+ ///
+ ///
+ ///
+ public class UpdateInfo
+ {
+ ///
+ /// The version.
+ ///
+ public string Version { get; set; }
+
+ ///
+ ///
+ ///
+ public UpdateFileInfo[] Files { get; set; } = new UpdateFileInfo[0];
+
+ ///
+ /// The release name.
+ ///
+ public string ReleaseName { get; set; }
+
+ ///
+ /// The release notes.
+ ///
+ public ReleaseNoteInfo[] ReleaseNotes { get; set; } = new ReleaseNoteInfo[0];
+
+ ///
+ ///
+ ///
+ public string ReleaseDate { get; set; }
+
+ ///
+ /// The staged rollout percentage, 0-100.
+ ///
+ public int StagingPercentage { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs b/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs
index 7cb6542..5c82bf0 100644
--- a/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs
+++ b/ElectronNET.CLI/Commands/Actions/DeployEmbeddedElectronFiles.cs
@@ -27,6 +27,7 @@ namespace ElectronNET.CLI.Commands.Actions
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "shell.js", "api.");
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "screen.js", "api.");
EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "clipboard.js", "api.");
+ EmbeddedFileHelper.DeployEmbeddedFile(hostApiFolder, "autoUpdater.js", "api.");
string splashscreenFolder = Path.Combine(tempPath, "splashscreen");
if (Directory.Exists(splashscreenFolder) == false)
diff --git a/ElectronNET.CLI/ElectronNET.CLI.csproj b/ElectronNET.CLI/ElectronNET.CLI.csproj
index a018aab..9d4dfd6 100644
--- a/ElectronNET.CLI/ElectronNET.CLI.csproj
+++ b/ElectronNET.CLI/ElectronNET.CLI.csproj
@@ -92,6 +92,7 @@ This package contains the dotnet tooling to electronize your application.
+
diff --git a/ElectronNET.Host/api/autoUpdater.js b/ElectronNET.Host/api/autoUpdater.js
new file mode 100644
index 0000000..8c97fe7
--- /dev/null
+++ b/ElectronNET.Host/api/autoUpdater.js
@@ -0,0 +1,28 @@
+"use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+const electron_updater_1 = require("electron-updater");
+const path = require('path');
+let electronSocket;
+module.exports = (socket) => {
+ electronSocket = socket;
+ socket.on('autoUpdaterCheckForUpdatesAndNotify', (guid) => __awaiter(this, void 0, void 0, function* () {
+ const updateCheckResult = yield electron_updater_1.autoUpdater.checkForUpdatesAndNotify();
+ electronSocket.emit('autoUpdaterCheckForUpdatesAndNotifyComplete' + guid, updateCheckResult);
+ }));
+ socket.on('autoUpdaterCheckForUpdates', (guid) => __awaiter(this, void 0, void 0, function* () {
+ // autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml');
+ const updateCheckResult = yield electron_updater_1.autoUpdater.checkForUpdates();
+ electronSocket.emit('autoUpdaterCheckForUpdatesComplete' + guid, updateCheckResult);
+ }));
+ socket.on('autoUpdaterQuitAndInstall', (isSilent, isForceRunAfter) => __awaiter(this, void 0, void 0, function* () {
+ electron_updater_1.autoUpdater.quitAndInstall(isSilent, isForceRunAfter);
+ }));
+};
+//# sourceMappingURL=autoUpdater.js.map
\ No newline at end of file
diff --git a/ElectronNET.Host/api/autoUpdater.js.map b/ElectronNET.Host/api/autoUpdater.js.map
new file mode 100644
index 0000000..6529890
--- /dev/null
+++ b/ElectronNET.Host/api/autoUpdater.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"autoUpdater.js","sourceRoot":"","sources":["autoUpdater.ts"],"names":[],"mappings":";;;;;;;;;AAAA,uDAA+C;AAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAC7B,IAAI,cAAc,CAAC;AAEnB,iBAAS,CAAC,MAAuB,EAAE,EAAE;IACjC,cAAc,GAAG,MAAM,CAAC;IAExB,MAAM,CAAC,EAAE,CAAC,qCAAqC,EAAE,CAAO,IAAI,EAAE,EAAE;QAC5D,MAAM,iBAAiB,GAAG,MAAM,8BAAW,CAAC,wBAAwB,EAAE,CAAC;QACvE,cAAc,CAAC,IAAI,CAAC,6CAA6C,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC;IACjG,CAAC,CAAA,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,4BAA4B,EAAE,CAAO,IAAI,EAAE,EAAE;QACnD,6EAA6E;QAC7E,MAAM,iBAAiB,GAAG,MAAM,8BAAW,CAAC,eAAe,EAAE,CAAC;QAC9D,cAAc,CAAC,IAAI,CAAC,oCAAoC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC;IACxF,CAAC,CAAA,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,2BAA2B,EAAE,CAAO,QAAQ,EAAE,eAAe,EAAE,EAAE;QACvE,8BAAW,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IAC1D,CAAC,CAAA,CAAC,CAAC;AACP,CAAC,CAAC"}
\ No newline at end of file
diff --git a/ElectronNET.Host/api/autoUpdater.ts b/ElectronNET.Host/api/autoUpdater.ts
new file mode 100644
index 0000000..a3f3c07
--- /dev/null
+++ b/ElectronNET.Host/api/autoUpdater.ts
@@ -0,0 +1,22 @@
+import { autoUpdater } from 'electron-updater';
+const path = require('path');
+let electronSocket;
+
+export = (socket: SocketIO.Socket) => {
+ electronSocket = socket;
+
+ socket.on('autoUpdaterCheckForUpdatesAndNotify', async (guid) => {
+ const updateCheckResult = await autoUpdater.checkForUpdatesAndNotify();
+ electronSocket.emit('autoUpdaterCheckForUpdatesAndNotifyComplete' + guid, updateCheckResult);
+ });
+
+ socket.on('autoUpdaterCheckForUpdates', async (guid) => {
+ // autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml');
+ const updateCheckResult = await autoUpdater.checkForUpdates();
+ electronSocket.emit('autoUpdaterCheckForUpdatesComplete' + guid, updateCheckResult);
+ });
+
+ socket.on('autoUpdaterQuitAndInstall', async (isSilent, isForceRunAfter) => {
+ autoUpdater.quitAndInstall(isSilent, isForceRunAfter);
+ });
+};
diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js
index f51156a..de630dc 100644
--- a/ElectronNET.Host/main.js
+++ b/ElectronNET.Host/main.js
@@ -6,7 +6,7 @@ const portscanner = require('portscanner');
const imageSize = require('image-size');
let io, server, browserWindows, ipc, apiProcess, loadURL;
let appApi, menu, dialogApi, notification, tray, webContents;
-let globalShortcut, shellApi, screen, clipboard;
+let globalShortcut, shellApi, screen, clipboard, autoUpdater;
let splashScreen, mainWindowId, hostHook;
const currentBinPath = path.join(__dirname.replace('app.asar', ''), 'bin');
@@ -104,6 +104,7 @@ function startSocketApiBridge(port) {
appApi = require('./api/app')(socket, app);
browserWindows = require('./api/browserWindows')(socket, app);
+ autoUpdater = require('./api/autoUpdater')(socket);
ipc = require('./api/ipc')(socket);
menu = require('./api/menu')(socket);
dialogApi = require('./api/dialog')(socket);
diff --git a/ElectronNET.Host/package.json b/ElectronNET.Host/package.json
index ca9a69e..3d6fea9 100644
--- a/ElectronNET.Host/package.json
+++ b/ElectronNET.Host/package.json
@@ -1,6 +1,6 @@
{
"name": "electron.net.host",
- "version": "1.0.0",
+ "version": "1.0.2",
"description": "Electron-Host for Electron.NET.",
"repository": {
"url": "https://github.com/ElectronNET/Electron.NET"
@@ -12,6 +12,7 @@
"start": "tsc -p ."
},
"dependencies": {
+ "electron-updater": "^4.0.6",
"image-size": "^0.7.4",
"portscanner": "^2.2.0",
"socket.io": "^2.2.0"
diff --git a/ElectronNET.WebApp/electron.manifest.json b/ElectronNET.WebApp/electron.manifest.json
index 59d5d4d..847cbde 100644
--- a/ElectronNET.WebApp/electron.manifest.json
+++ b/ElectronNET.WebApp/electron.manifest.json
@@ -7,9 +7,20 @@
"build": {
"appId": "com.electronnetapidemos.app",
"productName": "ElectronNET API Demos",
- "copyright": "Copyright © 2019",
+ "copyright": "Copyright � 2019",
"buildVersion": "5.22.12",
"compression": "maximum",
+ "win": {
+ "icon": "Assets/electron.ico",
+ "publish": [
+ {
+ "provider": "github",
+ "owner": "ElectronNET",
+ "repo": "electron.net-api-demos",
+ "token": " Insert GH_TOKEN here!"
+ }
+ ]
+ },
"directories": {
"output": "../../../bin/Desktop",
"buildResources": "Assets"
@@ -18,14 +29,18 @@
{
"from": "./bin",
"to": "bin",
- "filter": [ "**/*" ]
+ "filter": [
+ "**/*"
+ ]
}
],
"files": [
{
"from": "./ElectronHostHook/node_modules",
"to": "ElectronHostHook/node_modules",
- "filter": [ "**/*" ]
+ "filter": [
+ "**/*"
+ ]
},
"**/*"
]