当前位置: 代码迷 >> 综合 >> 使用 electron 开发桌面应用并打包
  详细解决方案

使用 electron 开发桌面应用并打包

热度:60   发布时间:2023-12-09 10:25:22.0

一、概要

文档

官网:https://www.electronjs.org/
文档:https://www.electronjs.org/docs

环境准备:

安装 node.js

包管理工具 npm

node -v
npm -v

二、创建一个 Electron DEMO

参考文档:https://www.electronjs.org/docs/tutorial/quick-start#prerequisites

项目架构

从开发的角度来看,Electron 应用本质上是一个 Node.js 应用。 这意味着您的 Electron 应用程序的起点将是一个 package.json 文件,就像在其他的Node.js 应用程序中一样。 最小的 Electron 应用程序具有以下结构:

my-electron-app/
├── package.json
├── main.js
├── preload.js
└── index.html
安装 Electron
mkdir my-electron-app && cd my-electron-appnpm init -ynpm install -g electron
创建主进程脚本文件main.js

主脚本指定了运行主进程的 Electron 应用程序的入口(就我们而言,是 main.js 文件)。 通常,在主进程中运行的脚本控制应用程序的生命周期、显示图形用户界面及其元素、执行本机操作系统交互以及在网页中创建渲染进程。 Electron 应用程序只能有一个主进程。

const {
     app, BrowserWindow } = require('electron')
const path = require('path')function createWindow () {
    const win = new BrowserWindow({
    width: 800,height: 600,webPreferences: {
    preload: path.join(__dirname, 'preload.js')}})win.loadFile('index.html')
}app.whenReady().then(() => {
    createWindow()app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()}})
})app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
    app.quit()}
})

上面发生了什么?

  • 第 1 行:为了管理应用程序的生命周期事件以及创建和控制浏览器窗口,您从 electron 包导入了 app 和 BrowserWindow 模块 。
  • 第2行: 导入 path 包,该包为操作文件路径提供了实用的功能。
  • 第 4 行:在此之后,你定义一个方法用来创建一个带有预加载脚本的新的浏览器窗口,并加载index.html文件进入该窗口 (第 13 行,我们将在后面探讨这个文件)。
  • 第 16 行:你通过调用 createWindow方法,在 electron app 第一次被初始化时创建了一个新的窗口。
  • 第 18 行:您添加一个新的侦听器,只有当应用程序激活后没有可见窗口时,才能创建新的浏览器窗口。 例如,在首次启动应用程序后或重启运行中的应用程序。
  • 第 25 行:您添加了一个新的侦听器,当应用程序不再有任何打开窗口时试图退出。 由于操作系统的 窗口管理行为 ,此监听器在 macOS 上是禁止操作的。
创建网页 index.html

这是应用程序初始化后您想要显示的页面。 此网页代表渲染过程。 您可以创建多个浏览器窗口,每个窗口都使用自己的独立渲染进程。 你可以选择性地从您的预加载脚本中公开额外的 Node.js API 来授予对它们访问权限。

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Hello World!</title><meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: white;"><h1>Hello World!</h1><p>We are using Node.js <span id="node-version"></span>,Chromium <span id="chrome-version"></span>,and Electron <span id="electron-version"></span>.</p>
</body>
</html>
定义一个预加载脚本 preload.js

您的预加载脚本就像是Node.js和您的网页之间的桥梁。 它允许你将特定的 API 和行为暴露到你的网页上,而不是不安全地把整个 Node.js 的 API暴露。 在本例中,我们将使用预加载脚本从process对象读取版本信息,并用该信息更新网页。

window.addEventListener('DOMContentLoaded', () => {
    const replaceText = (selector, text) => {
    const element = document.getElementById(selector)if (element) element.innerText = text}for (const type of ['chrome', 'node', 'electron']) {
    replaceText(`${
      type}-version`, process.versions[type])}
})

上面发生了什么?

  • 第 1 行:首先定义了一个事件监听器,当web页面加载完成后通知你。
  • 第 2 行:接着您定义了一个功能函数用来为index.html中的所有placeholder设置文本。
  • 第 7 行:接下来您遍历了您想展示版本号的组件列表。
  • 第 8 行:最终,您调用 replaceText 来查找index.html中的版本占位符并将其文本值设置为process.versions的值。
修改您的 package.json 文件

您的 Electron 应用程序使用 package.json 文件作为主入口(像任何其它的 Node.js 应用程序)。 您的应用程序的主脚本是 main.js,所以相应修改 package.json 文件

{
    "name": "my-electron-app","version": "0.1.0","author": "your name","description": "My Electron app","main": "main.js"
}

注意:如果未设置 main 字段,Electron 将尝试加载包含在 package.json 文件目录中的 index.js 文件。

注意:author 和 description 字段对于打包来说是必要的,否则运行 npm run make 命令时会报错。

默认情况下, npm start 命令将用 Node.js 来运行主脚本。 要使用 Electron 来运行脚本,您需要将其更改为这样:

{
    "name": "my-electron-app","version": "0.1.0","author": "your name","description": "My Electron app","main": "main.js","scripts": {
    "start": "electron ."}
}
运行您的应用程序
npm start

以上过程,其实对应的就是官方提供的DEMO,通过以上过程,你基本了解了一个 electron demo 的开发过程。

克隆示例项目的仓库
git clone https://github.com/electron/electron-quick-start
进入这个仓库
cd electron-quick-start
安装依赖并运行
npm install && npm start

以上 npm命令 如果出现错误,就使用 cnpm 代替,因为我本地安装了 cnpm ,然后在使用 npm命令 的时候有时候报错,换成 cnpm 就好了。

cnpm install && cnpm start

程序可以正常运行。

打包应用程序

安装 electron-packager

npm install -g electron-packagerelectron-packager -hUsage: electron-packager <sourcedir> <appname> [options...]Required parameterssourcedir          the base directory of the application sourceExamples:        electron-packager ./electron-packager ./ --allOptional parametersappname            the name of the app, if it needs to be different from the "productName" or "name"in the nearest package.jsonOptionsversion            prints the version of Electron Packager and Node, plus the target platform andarch, for bug reporting purposes, and exits immediately* All platforms *all                equivalent to --platform=all --arch=allapp-copyright      human-readable copyright line for the appapp-version        release version to set for the apparch               all, or one or more of: ia32, x64, armv7l, arm64, mips64el (comma-delimited ifmultiple). Defaults to the host archasar               whether to package the source code within your app into an archive. You can eitherpass --asar by itself to use the default configuration, OR use dot notation toconfigure a list of sub-properties, e.g. --asar.unpackDir=sub_dir - do not use--asar and its sub-properties simultaneously.Properties supported include:- ordering: path to an ordering file for file packing- unpack: unpacks the files to the app.asar.unpacked directory whose filenamesregex .match this string- unpackDir: unpacks the dir to the app.asar.unpacked directory whose names globpattern or exactly match this string. It's relative to the <sourcedir>.build-version build version to set for the appdownload a list of sub-options to pass to @electron/get. They are specified via dotnotation, e.g., --download.cacheRoot=/tmp/cacheProperties supported:- cacheRoot: directory of cached Electron downloads. For default value, see@electron/get documentation- mirrorOptions: alternate URL options for downloading Electron zips. See@electron/get documentation for details- rejectUnauthorized: whether SSL certs are required to be valid when downloadingElectron. Defaults to true, use --no-download.rejectUnauthorized to disablechecks.electron-version the version of Electron that is being packaged, seehttps://github.com/electron/electron/releaseselectron-zip-dir the local path to a directory containing Electron ZIP filesexecutable-name the name of the executable file, sans file extension. Defaults to appnameextra-resource a file to copy into the app's resources directoryicon               the local path to an icon file to use as the icon for the app.Note: Format depends on platform.ignore             do not copy files into app whose filenames RegExp.match this string. See also:https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html#ignoreand --no-prune. Can be specified multiple timesno-deref-symlinks  make sure symlinks are not dereferenced within the app sourceno-junk            do not ignore system junk files from the packaged appno-prune           do not prune devDependencies from the packaged appout                the dir to put the app into at the end. Defaults to current working diroverwrite          if output directory for a platform already exists, replaces it rather thanskipping itplatform           all, or one or more of: darwin, linux, mas, win32 (comma-delimited if multiple).Defaults to the host platformprebuilt-asar      path to a prebuilt asar file (asar, ignore, no-prune, and no-deref-symlinksoptions are incompatible with this option and will be ignored)quiet              Do not print informational or warning messagestmpdir             temp directory. Defaults to system temp directory, use --no-tmpdir to disableuse of a temporary directory.* darwin/mas target platforms only *app-bundle-id      bundle identifier to use in the app plistapp-category-type  the application category typeFor example, `app-category-type=public.app-category.developer-tools` will set theapplication category to 'Developer Tools'.darwin-dark-mode-supportforces support for Mojave/10.14 dark mode in the packaged appextend-info        a plist file to merge into the app plisthelper-bundle-id   bundle identifier to use in the app helper plistosx-sign           (macOS host platform only) Whether to sign the macOS app packages. You can eitherpass --osx-sign by itself to use the default configuration, or use dot notationto configure a list of sub-properties, e.g. --osx-sign.identity="My Name"For info on supported values see https://npm.im/electron-osx-sign#opts---optionsProperties supported include:- identity: should contain the identity to be used when running `codesign`- entitlements: the path to entitlements used in signing- entitlements-inherit: the path to the 'child' entitlementsosx-notarize       (macOS host platform only, requires --osx-sign) Whether to notarize the macOS apppackages. You must use dot notation to configure a list of sub-properties, e.g.--osx-notarize.appleId="foo@example.com"For info on supported values see https://npm.im/electron-notarize#method-notarizeopts-promisevoidProperties supported include:- appleId: should contain your apple ID username / email- appleIdPassword: should contain the password for the provided apple ID- appleApiKey: should contain an App Store Connect API key- appleApiIssuer: should contain the API key's issuerprotocol           URL protocol scheme to register the app as an opener of.For example, `--protocol=myapp` would register the app to openURLs such as `myapp://path`. This argument requires a `--protocol-name`argument to also be specified.protocol-name      Descriptive name of URL protocol scheme specified via `--protocol`usage-description  Human-readable descriptions of how the app uses certain macOS features. Displayedin the App Store. A non-exhaustive list of properties supported:- Camera- Microphone* win32 target platform only *win32metadata      a list of sub-properties used to set the application metadata embedded intothe executable. They are specified via dot notation,e.g. --win32metadata.CompanyName="Company Inc."or --win32metadata.ProductName="Product"Properties supported:- CompanyName (default: author name from nearest package.json)- FileDescription (default: appname)- OriginalFilename (default: renamed exe)- ProductName (default: appname)- InternalName (default: appname)- requested-execution-level (user, asInvoker, or requireAdministrator)- application-manifest

打包命令:

electron-packager <sourcedir> <appname> [options...]

以上命令:

  • 将目录切换到项目所在路径,或者使用参数sourcedir指定。
  • 参数 appname 是打包后的名字。
  • 参数 plateform 确定了你要构建哪个平台的应用(Windows、Mac 还是 Linux),windows是win32。
  • 参数 arch 决定了使用 x86 还是 x64 还是两个架构都用。
  • 参数 app-version 标记版本号,值应该是0.0.1,而不是v0.0.1,否则会报错rcedit.exe failed with exit code 1. Fatal error: Unable to parse version string for FileVersion
  • 第一次打包应用需要比较久的时间,因为所有平台的二进制文件都需要下载,之后打包应用会比较快了。

示例:

electron-packager ./  electronDemo --platform=win32 --arch=x64 --app-version=0.0.1 --icon=./favicon.ico --overwrite --out=./bin

报错

(node:39648) ExperimentalWarning: The fs.promises API is experimental
Cannot find module 'electron' from 'D:\dev\php\magook\trunk\server\electron\electron-quick-start'

第一个错误是版本低了

升级 npm

npm install npm@latest -g
npm -v
7.11.1

下载新版nodejs,重新安装

node -v
v14.16.1

运行程序cnpm install && cnpm start可以正常运行。

重新打开cmd,执行打包命令,发现没有出现上面的两个问题,但是出现了新的问题

read ECONNRESET

这是连接超时,再次执行,发现又没有报错了,提示正在下载electron-v12.0.5-win32-x64.zip,但是速度很慢,最终还是断开了。

尝试修改源的地址

npm config set ELECTRON_MIRROR http://npm.taobao.org/mirrors/electron/

还是没有效果。

由于未知原因,electron-packger / electron-builder 在真实打包时并不识别npm的镜像地址,此时,你需要修改环境变量

ELECTRON_MIRROR = http://npm.taobao.org/mirrors/electron/

在这里插入图片描述

还别说,快多了。

终于打包完成了。

在这里插入图片描述

但是在resources\app下面居然看到完整的项目代码,这就有点过分吧。而且打包后的总大小177M,其中可执行文件125M,大的离谱!!

双击electronDemo.exe,能正常运行。

在这里插入图片描述