Electronには自動アップデート機能が組み込まれていますautoUpdater
が、サービスの構成が少し複雑なので、最終的にelectron-updater
ツール プラグインを選択しました。ここでは、electron-updater
アプリケーションを自動的に更新およびアップグレードするための設定方法について説明します。
1. プロジェクトの依存関係とスクリプト
インストールしelectron-updater
てelectron-log
pnpm add -D electron-updater electron-log
package.json の完全な構成は次のとおりです。
{
"name": "post-tools",
"productName": "Post Tools",
"version": "3.0.0",
"description": "一个基于electron和node开发,用于http/https接口测试的工具",
"main": "./out/main/index.js",
"author": "Tiven",
"homepage": "https://tiven.cn",
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"start": "electron-vite preview",
"dev": "electron-vite dev",
"dev:debug": "nodemon --watch ./src/main/index.js --exec \" electron-vite dev\" ",
"build": "electron-vite build",
"postinstall": "electron-builder install-app-deps",
"build:win": "npm run build && electron-builder --win --config",
"build:mac": "npm run build && electron-builder --mac --config",
"build:linux": "npm run build && electron-builder --linux --config",
"git": "tive git -c tive.git.config.cjs"
},
"dependencies": {
"@electron-toolkit/preload": "^2.0.0",
"@electron-toolkit/utils": "^1.0.2"
},
"devDependencies": {
"@ant-design/icons": "4.0.0",
"@electron/notarize": "^1.2.3",
"@vitejs/plugin-react": "^4.0.0",
"about-window": "^1.15.2",
"ahooks": "^3.7.7",
"antd": "^5.6.2",
"axios": "^1.4.0",
"electron": "^24.4.1",
"electron-builder": "^23.6.0",
"electron-builder-squirrel-windows": "^24.5.0",
"electron-log": "^4.4.8",
"electron-updater": "^5.3.0",
"electron-vite": "^1.0.23",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"jsoneditor": "8",
"prettier": "^2.8.8",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite": "^4.3.9"
}
}
2. パッケージングパラメータを設定する
- 電子ビルダー.yml
appId: cn.tiven.app
productName: Post Tools
copyright: Copyright © 2023 ${
author}
directories:
buildResources: build
output: dist
files:
- '!**/.vscode/*'
- '!src/*'
- '!dist2/*'
- '!node_modules/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
asarUnpack:
- resources/**
afterSign: build/notarize.js
win:
executableName: Post Tools
icon: resources/icon.ico
publisherName: tiven
verifyUpdateCodeSignature: false
target:
- nsis
- squirrel
nsis:
oneClick: false
artifactName: ${
name}-${
version}-setup.${
ext}
shortcutName: ${
productName}
uninstallDisplayName: ${
productName}
createDesktopShortcut: always
perMachine: true
allowToChangeInstallationDirectory: true
guid: 2cf313e9-0f05-xxxx-1006-e278272e9b2a
squirrelWindows:
loadingGif: resources/loading.gif
iconUrl: https://tiven.cn/static/img/net-stats.ico
mac:
category: public.app-category.developer-tools
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
dmg:
artifactName: ${
name}-${
version}.${
ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${
name}-${
version}.${
ext}
npmRebuild: false
publish:
provider: generic
url: http://localhost:3000/
最後の 3 行のパラメータ設定が更新の鍵public
となります。ローカル デバッグに使用されるため、ダウンロード速度は非常に速く、オンラインになった後は正式なドメイン名サービスに置き換えることができます。electron-updater
http://localhost:3000/
- dev-app-update.yml
provider: generic
url: http://localhost:3000/
updaterCacheDirName: post-tools-updater
3. 主な更新ロジック
新しいファイルを作成するsrc/main/autoUpdater.js
// src/main/autoUpdater.js
import {
app, dialog } from 'electron'
import {
join } from 'path'
import {
autoUpdater } from 'electron-updater'
import logger from 'electron-log'
import {
getLocalData, setLocalData, sleep } from './helper'
import {
productName } from '@package'
export async function autoUpdateInit() {
//打印log到本地
logger.transports.file.maxSize = 1002430 // 10M
logger.transports.file.format = '[{y}-{m}-{d} {h}:{i}:{s}.{ms}] [{level}]{scope} {text}'
logger.transports.file.resolvePath = () => join(app.getPath('appData'), 'logs/main.log')
await sleep(5000)
//每次启动自动更新检查 更新版本 --可以根据自己方式更新,定时或者什么
autoUpdater.checkForUpdates()
autoUpdater.logger = logger
autoUpdater.disableWebInstaller = false
autoUpdater.autoDownload = false //这个必须写成false,写成true时,我这会报没权限更新,也没清楚什么原因
autoUpdater.on('error', (error) => {
logger.error(['检查更新失败', error])
})
//当有可用更新的时候触发。 更新将自动下载。
autoUpdater.on('update-available', (info) => {
logger.info('检查到有更新,开始下载新版本')
logger.info(info)
const {
version } = info
askUpdate(version)
})
//当没有可用更新的时候触发。
autoUpdater.on('update-not-available', () => {
logger.info('没有可用更新')
})
// 在应用程序启动时设置差分下载逻辑
autoUpdater.on('download-progress', async (progress) => {
logger.info(progress)
})
//在更新下载完成的时候触发。
autoUpdater.on('update-downloaded', (res) => {
logger.info('下载完毕!提示安装更新')
logger.info(res)
//dialog 想要使用,必须在BrowserWindow创建之后
dialog
.showMessageBox({
title: '升级提示!',
message: '已为您下载最新应用,点击确定马上替换为最新版本!',
})
.then(() => {
logger.info('退出应用,安装开始!')
//重启应用并在下载后安装更新。 它只应在发出 update-downloaded 后方可被调用。
autoUpdater.quitAndInstall()
})
})
}
async function askUpdate(version) {
logger.info(`最新版本 ${
version}`)
let {
updater } = getLocalData()
let {
auto, version: ver, skip } = updater || {
}
logger.info(
JSON.stringify({
...updater,
ver: ver,
})
)
if (skip && version === ver) return
if (auto) {
// 不再询问 直接下载更新
autoUpdater.downloadUpdate()
} else {
const {
response, checkboxChecked } = await dialog.showMessageBox({
type: 'info',
buttons: ['关闭', '跳过这个版本', '安装更新'],
title: '软件更新提醒',
message: `${
productName} 最新版本是 ${
version},您现在的版本是 ${
app.getVersion()},现在要下载更新吗?`,
defaultId: 2,
cancelId: -1,
checkboxLabel: '以后自动下载并安装更新',
checkboxChecked: false,
textWidth: 300,
})
if ([1, 2].includes(response)) {
let updaterData = {
version: version,
skip: response === 1,
auto: checkboxChecked,
}
setLocalData({
updater: {
...updaterData,
},
})
if (response === 2) autoUpdater.downloadUpdate()
logger.info(['更新操作', JSON.stringify(updaterData)])
} else {
logger.info(['更新操作', '关闭更新提醒'])
}
}
}
その中には、helper.js
カプセル化された永続データ関連の操作メソッドがあります。
// src/main/helper.js
import {
join } from 'path'
import fs from 'fs'
import {
app } from 'electron'
const dataPath = join(app.getPath('userData'), 'data.json')
export function getLocalData(key) {
if (!fs.existsSync(dataPath)) {
fs.writeFileSync(dataPath, JSON.stringify({
}), {
encoding: 'utf-8' })
}
let data = fs.readFileSync(dataPath, {
encoding: 'utf-8' })
let json = JSON.parse(data)
return key ? json[key] : json
}
export function setLocalData(key, value) {
let args = [...arguments]
let data = fs.readFileSync(dataPath, {
encoding: 'utf-8' })
let json = JSON.parse(data)
if (args.length === 0 || args[0] === null) {
json = {
}
} else if (args.length === 1 && typeof key === 'object' && key) {
json = {
...json,
...args[0],
}
} else {
json[key] = value
}
fs.writeFileSync(dataPath, JSON.stringify(json), {
encoding: 'utf-8' })
}
export async function sleep(ms) {
return new Promise((resolve) => {
const timer = setTimeout(() => {
resolve()
clearTimeout(timer)
}, ms)
})
}
メインプロセスでカプセル化された初期化メソッドapp.whenReady
を呼び出します。autoUpdateInit
app.whenReady().then(() => {
// ...
// 版本更新初始化
autoUpdateInit()
})
4. パッケージ化とデバッグ
ローカルの開発環境では更新が検出されないためelectron-updater
、パッケージ化して運用する必要があります。
electron-updater
更新検出は主にサーバー側のファイル内のバージョン情報latest.yml
(Mac ソフトウェアが生成)を検出し、このバージョン番号はに基づいて生成されます。latest-mac.yml
package.json
version
システムは MacOS である
package.json
と仮定します。version: 1.0.0
デバッグ手順は次のとおりです。
- パッケージングの実行
npm run build:mac
dist
ディレクトリ内に生成されたインストール パッケージ ファイルで、.dmg
接尾辞が次のファイルを見つけます。- インストール
- package.json を変更し、アップグレードのバージョン番号を に変更します
version: 1.1.0
。 - パッケージングコマンドを再度実行してください
- ローカル静的ファイル サービスを開始します。
serve
ツールキットを使用して、serve をグローバルにインストールすることをお勧めします。
pnpm i -g serve
- プロジェクトのルート ディレクトリでコマンドを実行します
serve dist
。このコマンドの機能は、dist ディレクトリ内のすべてのファイルを静的リソースに変換し、http
リクエストを通じて対応するリソースを取得することです。 - デフォルトでは、serve が提供する静的サービスが
3000
ポート上にあります。占有されている場合は、ランダムなポートが割り当てられます。 以降に対応するアドレスを変更することを忘れないでelectron-builder.yml
くださいdev-app-update.yml
。すべてが正常な場合は、http://localhost:3000/latest-mac.yml にアクセスすると、対応するリソースを確認できます。 - すべての準備ができたら、手順 3 でインストールしたアプリケーションを起動します。数秒待つと、上に表示されたアップデートのリマインダーが表示されます。
- 注: MacOS で証明書を構成する必要があります。そうしないと、更新の検出時に問題が発生する可能性があります。コード署名証明書は自分で生成できます。「 Mac 構成の自己作成証明書」を参照してください。
天文ブログへようこそ