配置electron應(yīng)用自動(dòng)更新

本文介紹了 electron 開(kāi)發(fā)桌面端應(yīng)用的自動(dòng)更新升級(jí)版本的方法, 以及更新服務(wù)器的搭建. electron項(xiàng)目搭建使用 vue-cli-plugin-electron-builder,自動(dòng)更新使用的是 electron-updater, 它與electron-builder搭配使用.

下文 background.ts 文件中還涉及了連接串口的使用方法, 當(dāng)作筆記, 故未刪除.

安裝

yarn add electron-updater
// 如果沒(méi)有安裝 `electron-builder`, 也一并安裝

配置文件

vue.config.js

module.exports = {
  pluginOptions: {
    electronBuilder: {
      // List native deps here if they don't work
      // 原生包必須這里聲明下
      externals: ["serialport"],
      // If you are using Yarn Workspaces, you may have multiple node_modules folders
      // List them all here so that VCP Electron Builder can find them
      nodeModulesPath: ["../../node_modules", "./node_modules"],
      nodeIntegration: true,
      builderOptions: {
        // options placed here will be merged with default configuration and passed to electron-builder
        appId: "com.grgbanking.screenshow",
        productName: "串口與自動(dòng)更新", // 項(xiàng)目名嗓蘑,也是生成的安裝文件名鱼鸠,即xBox.exe
        copyright: "Copyright ? 2020", // 版權(quán)信息
        asar: true,
        extraResources: "./extra-resources",
        win: {
          icon: "public/logo.png", 
          // !!!!!!!!!!!!!!重點(diǎn), 這里必須有publis, 否則打包時(shí)不會(huì)生成latest.yml文件!!!!!!!!!!!!!!!
          publish: [
            {
              provider: "generic",
              url: "http://127.0.0.1:8080/" // 更新文件服務(wù)器地址
            }
          ],
          target: [
            {
              target: "nsis", // 利用nsis制作安裝程序
              arch: [
                "x64" // 64位
                // 'ia32'
              ]
            }
          ]
        },
        linux: {
          icon: "public/logo.png", 
          category: "Graphics",
          target: "snap"
        },
        nsis: {
          oneClick: false, // 是否一鍵安裝
          allowElevation: true, // 允許請(qǐng)求提升墓塌。 如果為false,則用戶(hù)必須使用提升的權(quán)限重新啟動(dòng)安裝程序香缺。
          allowToChangeInstallationDirectory: true, // 允許修改安裝目錄
          // installerIcon: "./xxx.ico",// 安裝圖標(biāo)
          // uninstallerIcon: "./xxx.ico",//卸載圖標(biāo)
          // installerHeaderIcon: "./xxx.ico", // 安裝時(shí)頭部圖標(biāo)
          createDesktopShortcut: true, // 創(chuàng)建桌面圖標(biāo)
          createStartMenuShortcut: true, // 創(chuàng)建開(kāi)始菜單圖標(biāo)
          shortcutName: "串口測(cè)試" // 圖標(biāo)名稱(chēng)
        }
      }
    }
  }
};

打包后生成的 latest.yml文件

打包時(shí)必須配置上文的 publish 字段, 否則不生成改文件(在package.json中設(shè)置build的做法已經(jīng)不再支持). 程序更新依賴(lài)這個(gè)文件做版本判斷,作為自動(dòng)更新的服務(wù)器里面必須有這個(gè)文件, 否則報(bào)錯(cuò).

version: 0.2.0 # 與package.json 版本相同, 程序更新必須修改package.json中的version字段
files:
  - url: 串口與自動(dòng)更新 Setup 0.2.0.exe
    sha512: 9w2Jps2cg+mjDaHLcCq29cKG48y9DKM5O11leYg0wYhrGUGH8680Z/AEAL207o7LorH3n0h2Dg1HFYuJRpSYkQ==
    size: 56726689
path: 串口與自動(dòng)更新 Setup 0.2.0.exe
sha512: 9w2Jps2cg+mjDaHLcCq29cKG48y9DKM5O11leYg0wYhrGUGH8680Z/AEAL207o7LorH3n0h2Dg1HFYuJRpSYkQ==
releaseDate: '2021-03-05T04:03:28.119Z'

自動(dòng)更新程序核心api

background.ts

import { app, protocol, BrowserWindow, WebContents, ipcMain } from "electron";
import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
// 串口工具
import SerialPort from "serialport";
// 自動(dòng)更新
import { autoUpdater } from "electron-updater";

console.log("當(dāng)前平臺(tái)", process.platform);
const feedUrl = `http://127.0.0.1:8080/${process.platform}`;

// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
  { scheme: "app", privileges: { secure: true, standard: true } }
]);

let webContents: WebContents;

function sendUpdateMessage(message: string, data: unknown) {
  webContents.send("message", { message, data });
}
// 檢查更新
function checkForUpdates() {
  // 設(shè)置更新服務(wù)器的地址, 其實(shí)就是一個(gè)靜態(tài)文件服務(wù)器地址
  autoUpdater.setFeedURL(feedUrl);

  autoUpdater.on("error", function(message) {
    sendUpdateMessage("error", message);
  });
  autoUpdater.on("checking-for-update", function(message) {
    sendUpdateMessage("checking-for-update", message);
  });
  autoUpdater.on("update-available", function(message) {
    sendUpdateMessage("update-available", message);
  });
  autoUpdater.on("update-not-available", function(message) {
    sendUpdateMessage("update-not-available", message);
  });

  // 更新下載進(jìn)度事件
  autoUpdater.on("download-progress", function(progressObj) {
    sendUpdateMessage("downloadProgress", progressObj);
  });
  // 下載完成事件
  autoUpdater.on("update-downloaded", function(
    event,
    releaseNotes,
    releaseName,
    releaseDate,
    updateUrl,
    quitAndUpdate
  ) {
    ipcMain.on("updateNow", (e, arg) => {
      // 停止當(dāng)前程序并安裝
      autoUpdater.quitAndInstall();
    });
    sendUpdateMessage("isUpdateNow", null);
  });
  // 執(zhí)行檢查更新
  autoUpdater.checkForUpdates();
}

async function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  });
  webContents = win.webContents;
  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string);
    if (!process.env.IS_TEST) win.webContents.openDevTools();
  } else {
    createProtocol("app");
    win.loadURL("app://./index.html");
  }
}
app.on("ready", async () => {
  createWindow();
  // 測(cè)試串口工具
  SerialPort.list().then(ports => {
    console.log(ports);
    const port = new SerialPort("COM4", { autoOpen: true }, function() {
      console.log("open");
    });
    port.write("ROBOT POWER ON", function(err) {
      if (err) {
        return console.log("Error on write: ", err.message);
      }
      console.log("message written");
    });
    port.on("data", data => {
      console.log(data);
    });
  });
  // 檢查更新
  setTimeout(checkForUpdates, 1000);
});

app.vue

<template>
    <h1>hello world</h1>
</template>
<script>
import { defineComponent } from "vue";
import { ipcRenderer } from "electron";

export default defineComponent({
  setup() {
    ipcRenderer.on("message", (event, { message, data }) => {
      console.log(message, data);
      switch (message) {
        case "isUpdateNow":
          if (confirm("現(xiàn)在更新手销?")) {
            ipcRenderer.send("updateNow");
          }
          break;
        default:
          document.querySelector("h1").innerHTML = message;
          break;
      }
    });
  }
});
</script>

靜態(tài)資源服務(wù)器

基于 express的靜態(tài)資源服務(wù)器, 這里要注意的是更新服務(wù)器靜態(tài)文件資源是最新打包后的文件, 需要更新 package.json 中版本號(hào).

const express = require("express");
const app = express();
const port = 8080;
app.use(express.static("./public"));
app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

其中 public 文件夾中有個(gè)win32 文件夾, 對(duì)應(yīng)了查找更新文件的地址const feedUrl = http://127.0.0.1:8080/${process.platform};, 其中 process.platform 的值在 windows 中為 win32, 下面是 win32 中存的打包后的文件:

├─latest.yml
├─串口與自動(dòng)更新 Setup 0.1.0.exe
├─win-unpacked  # 這個(gè)也是非必須

其中 串口與自動(dòng)更新 Setup 0.1.0.exe 安裝程序和 win-unpacked 只要一個(gè)即可, 另外 win-unpacked 文件夾名字可以任意取, 或者把里面的文件放到 latest.yml 同一目錄也可.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市图张,隨后出現(xiàn)的幾起案子原献,更是在濱河造成了極大的恐慌馏慨,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姑隅,死亡現(xiàn)場(chǎng)離奇詭異写隶,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)讲仰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)慕趴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鄙陡,你說(shuō)我怎么就攤上這事冕房。” “怎么了趁矾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵耙册,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我毫捣,道長(zhǎng)详拙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任蔓同,我火速辦了婚禮饶辙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斑粱。我一直安慰自己弃揽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布则北。 她就那樣靜靜地躺著矿微,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尚揣。 梳的紋絲不亂的頭發(fā)上涌矢,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音惑艇,去河邊找鬼蒿辙。 笑死拇泛,一個(gè)胖子當(dāng)著我的面吹牛滨巴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俺叭,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼恭取,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了熄守?” 一聲冷哼從身側(cè)響起蜈垮,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤耗跛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后攒发,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體调塌,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年惠猿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了害驹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胳赌。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出珊擂,到底是詐尸還是另有隱情,我是刑警寧澤吼驶,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布翼抠,位于F島的核電站,受9級(jí)特大地震影響扼鞋,放射性物質(zhì)發(fā)生泄漏申鱼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一藏鹊、第九天 我趴在偏房一處隱蔽的房頂上張望润讥。 院中可真熱鬧,春花似錦盘寡、人聲如沸楚殿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脆粥。三九已至,卻和暖如春影涉,著一層夾襖步出監(jiān)牢的瞬間变隔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工蟹倾, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匣缘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓鲜棠,卻偏偏與公主長(zhǎng)得像肌厨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豁陆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容