Linux下打包electron项目

本来 electron-builder是支持在windows下开发,然后一条命令打包到不同平台的,但此命令需要使用远程服务器来完成打包,然后此服务器已经停止很长时间了,而且从官方文档可感知后续不会开启。所以要打linux包必须到linux平台下打包。

本文采用Deepin国产linux操作系统为例进行Electron打包:

1.安装node:

1.1 下载

从nodejs官网到本地后上传到Linux服务器,也可在linux中直接下载。

下载地址是:https://nodejs.org/en/download/

解压到/usr/local/nodejs文件夹。(可自定义位置)

1.2 建立软链接

通过建立软链接的方式将这个设置为全局,使之在任何位置可执行node命令。

$ sudo ln -s /usr/local/nodejs/bin/node /usr/local/bin
$ sudo ln -s /usr/local/nodejs/bin/npm /usr/local/bin

1.3 修改镜像源

编辑npm config修改镜像源:

npm config edit

弹出配置文档,i编辑,esc退出编辑模式,:wq写入后退出。

electron_mirror=https://npm.taobao.org/mirrors/electron/
electron-builder-binaries_mirror=https://npm.taobao.org/mirrors/electron-builder-binaries/

2.下载 Electron + Vite + Vue3+TS 脚手架项目

自己新建vue+vite+electron+ts项目费时且易错,可直接下载下面的脚手架项目来使用。

GitHub - electron-vite/electron-vite-vue: 🥳 Really simple Electron + Vite + Vue boilerplate.

直接下载electron-vite-vue项目到本地,然后传到linux服务器上,打linux包必须在linux服务器上进行。

当然linux要下载安装vscode。(从应用商城中下载)

3.在linux下打包

在linux下安装了vscode,把我们下载的脚手架项目拷贝到linux下,用vscode打开

原项目package.json缺少homepage和description两项配置,加上这两项,然后加上build命令,修改后如下:

{
  "name": "electron-vue-vite",
  "version": "2.0.0",
  "main": "dist/electron/main/index.js",
  "author": "路飞",
  "homepage":"http://www.baidu.com",
  "description": "一个vue+electron脚手架项目",
  "license": "MIT",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build && electron-builder"
  },
  "engines": {
    "node": ">=14.17.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.3.3",
    "electron": "^19.0.3",
    "electron-builder": "^23.0.3",
    "typescript": "^4.7.3",
    "vite": "^2.9.9",
    "vite-plugin-electron": "^0.4.6",
    "vite-plugin-resolve": "^2.1.2",
    "vue": "^3.2.36",
    "vue-tsc": "^0.36.0"
  },
  "env": {
    "VITE_DEV_SERVER_HOST": "127.0.0.1",
    "VITE_DEV_SERVER_PORT": 3344
  },
  "keywords": [
    "electron",
    "rollup",
    "vite",
    "vue3",
    "vue"
  ]
}

在终端中初始化依赖项:

npm install

等初始化完成后,执行打包命令:

npm run build

运行日志:

saft@saft-PC:~/Desktop/docment/electronvuets$ npm run build

> electron-vue-vite@2.0.0 build /home/saft/Desktop/docment/electronvuets
> vue-tsc --noEmit && vite build && electron-builder

(node:16208) [DEP0025] DeprecationWarning: sys is deprecated. Use util instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
vite v2.9.12 building for production...
1 modules transformed.
dist/electron/preload/splash.js   1.48 KiB / gzip: 0.70 KiB
dist/electron/preload/splash.js.map 3.71 KiB
vite v2.9.12 building for production...
1 modules transformed.
dist/electron/main/index.js   1.37 KiB / gzip: 0.77 KiB
vite v2.9.12 building for production...
17 modules transformed.
dist/electron.fe1dfbad.png   61.65 KiB
dist/vite.92024911.svg       1.50 KiB
dist/vue.03d6d6da.png        6.69 KiB
dist/index.html              0.60 KiB
dist/style.b05f3b27.css      0.59 KiB / gzip: 0.33 KiB
dist/index.0f17d918.js       52.73 KiB / gzip: 21.28 KiB
 electron-builder  version=23.1.0 os=5.10.101-amd64-desktop
 loaded configuration  file=/home/saft/Desktop/docment/electronvuets/electron-builder.json5
 writing effective config  file=release/2.0.0/builder-effective-config.yaml
 packaging       platform=linux arch=x64 electron=19.0.5 appOutDir=release/2.0.0/linux-unpacked
 downloading     url=https://npm.taobao.org/mirrors/electron/19.0.5/electron-v19.0.5-linux-x64.zip size=83 MB parts=2
 downloaded      url=https://npm.taobao.org/mirrors/electron/19.0.5/electron-v19.0.5-linux-x64.zip duration=7.957s
 building        target=deb arch=x64 file=release/2.0.0/electron-vue-vite_2.0.0_amd64.deb
 default Electron icon is used  reason=application icon is not set

可以看到,electron-builder会默认取到当前系统框架信息os=5.10.101-amd64-desktop,作为参数,打包对应于本框架的应用程序。

这时候在项目release目录下生成了安装包,我们先试试安装此程序:

 

安装完成后菜单中会出现electron-vue-vite程序。

再试试免安装程序可否直接运行:

 

点运行后打开electron程序

扩展1:自定义图标

linux中定义应用程序图标与win中有差异。应用程序默认图标以及左上角图标在 electron-builder.json5 文件中设置:

win系统的在win下添加icon节点,并设置ico格式的图标文件为佳。linux和mac应设置为icns格式大小在256*256以上。(在deepin中使用png测试失败)linux下要执行安装程序后才看得到桌面图标效果。根据electronbuilder要求,linux下icns格式文件需要在文件名中包含尺寸,格式如msg@256x256.icns

/**
 *  electron-builder.json5  文件 
 */
{
  "appId": "cn.you.app",
  "asar": true,
  "directories": {
    "output": "release/${version}"
  },
  "files": [
    "dist"
  ],
  "mac": {
    "icon": "public/msg@256x256.icns",
    "artifactName": "${productName}_${version}.${ext}",
    "target": [
      "dmg"
    ]
  },
  "win": {
    "icon": "public/msg.ico",
    "target": [
      {
        "target": "nsis",
        "arch": [
          "x64"
        ]
      }
    ],
    "artifactName": "${productName}_${version}.${ext}"
  },
 "linux": {
   "icon": "public/msg@256x256.icns",
    "category":"Network",
    "target": [
                "deb"
            ]
        },
  "nsis": {
    "oneClick": false,
    "perMachine": false,
    "allowToChangeInstallationDirectory": true,
    "deleteAppDataOnUninstall": false
  }
}

png图片在线转ico工具:PNG转ICO - 在线转换图标文件 (aconvert.com)

扩展2:隐藏系统菜单

只需加一句即可

app.whenReady().then(() => {
 ……
  //隐藏系统默认菜单
  Menu.setApplicationMenu(null)
})

扩展3:禁用GPU加速

如果本身没有GPU硬件设备,添加一句设置来禁用gpu加速

app.disableHardwareAcceleration()

扩展4:制作托盘小程序

使用Tray创建托盘小程序,托盘的图标需要与之前的图标设置不同,linux下建议用png格式的图片,windows下用ico更佳。

//获取托盘图标。程序默认图标在electron-builder.json5中设置。
function getTrayIcon() {
  
  if (process.platform == 'darwin') {
    //MacOS
    return join(__dirname, '../../msg@256x256.png');
  }
  else if (process.platform == 'linux') {
    //linux 
    return join(__dirname, '../../msg@256x256.png');
  }
  else   // windows
     return join(__dirname, '../../msg.ico');
}

app.whenReady().then(() => {
  createWindow()
   // 创建系统托盘
  let iconpath=getTrayIcon()
  tray = new Tray(nativeImage.createFromPath(iconpath))
  const contextMenu = Menu.buildFromTemplate([
    {
      label: '显示icon路径',
      click () { showNotification('提示',iconpath) }
    },
    {
      label: '显示通知',
      click () { showNotification('提示',process.platform) }
    }, {
      label: '子菜单',
      submenu: [
        { label: 'Basic' },
        { label: '显示通知',click(){showNotification('提示','这是一条通知消息!')} }
      ]
    },
    { label: '退出程序',
    click(){ app.quit()} }
  ])

  tray.setToolTip('This is my application.')
  tray.setContextMenu(contextMenu)

  
})

扩展5:引入element-plus UI组件

项目中添加element-plus组件库制作精美页面。

npm i --save element-plus

main.ts中增加:

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
​
createApp(App)
  .use(router)
  .use(ElementPlus, {locale: zhCn})
  .mount('#app')

然后就可以使用element控件了

扩展6:播放声音

windows下直接可以这样写:

播歌曲文件:

const playmp3=async ()=>{
  var auto=new Audio("庆祝.mp3");
  auto.volume=1;
  auto.play();
}

文本转声音:

const Speak=async(m:string)=>{
  //文字转声音
   var u=new SpeechSynthesisUtterance();
   u.text=m
   //该lang属性使您能够指定文本的语言。zh、 en-US 等
   u.lang='zh';
   //该rate属性定义了应该说出文本的速度。这应该是介于0和10之间的浮点值,默认值为1。
   u.rate=rate.value/10;
   //该volume属性允许您调整语音的音量。应在此处指定介于0和1之间的浮点值。默认值为1。
   u.volume=volume.value/100;
   speechSynthesis.speak(u)
}

linux播放声音相对复杂,首先解决虚拟机deepin声音环境

Vmware安装deepin没有声音解决办法secret_breathe的博客-CSDN博客deepin没有声音

在Deepin系统中没有声音的解决办法Linux教程云网牛站 (ywnz.com)

经过上面教程打开linux声音环境后,在linux下测试播放歌曲没问题,依然是使用上面的代码(使用Audio类来播放),但是播放TTS语音合成就无法播放。

使用以下在线测试工具,在win下打开,不管是Edge还是Chrome浏览器打开,Voice下拉有语言库列表,但在linux下用Chrome打开无Voice列表,造成无法播放声音。

Web Speech Synthesis Demo (eeejay.github.io)

 

在liunx下的TTS技术先后尝试了以下方案:

Artyom:基于window.speechSynthesis,在linux下依然因为chrome71版本之后的限制播放不了声音。

say.js:基于festival,不支持中文

ekho:中文效果不佳(须安装ekho-7.5.tar.xz版本才能编译成功Ekho 安装_官网中可直接体验效果。

ekho '有10条新报警消息,请注意查收!'

espeak:中文效果不佳,可使用以下命令播放中文,但发现是外国人讲中国话,极其不自然。10会读成一零。

espeak -v zh 有10条新报警消息,请注意查收!

以下是使用Gespeaker程序,底层调用espeak-ng播放语音的界面:

sudo apt install gespeaker

 

 

festival:不支持中文

WebSpeech:在线版本2000元/年,本地版本底层调用的是espeak,中文效果不佳。

扩展7:使用vue-router

使用vue-router进行路由配置

引入vue-router

npm i --save vue-router

创建router/index.ts

import { createRouter, createWebHashHistory } from "vue-router";
​
const routes= [
    {
      path: '/login',
      name: 'login',
      component: () => import('../view/login/index.vue')
    },
    {
      path: '/error',
      name: 'error',
      component:() => import('../view/error/index.vue')
    }
  ]
​
const router = createRouter({
    history: createWebHashHistory(),
    routes: routes
  })
export default router

main.ts中增加:

import router from './router'
​
createApp(App)
  .use(router)

扩展8:隐藏标题栏+任意拖动+最大最小关闭按钮事件

将BrowserWindow的frame属性设置为false,就可以实现无标题

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600, frame: false })
win.show()

可拖拽区域设置,将html某一块,添加webkit-app-region:drag属性即可。但这样会遮住按钮等的点击事件,可以在对于控件style里增加 -webkit-app-region: no-drag

<body style="-webkit-app-region: drag">
</body>

最大化、最下话、关闭按钮,需要使用到进程间通信,即渲染进程和窗体进程通讯

在electron的main.js中添加监听

const {app, BrowserWindow, ipcMain} = require('electron')
​
ipcMain.on('window-max', () => {
  if(mainWindow.isMaximized()) {
     mainWindow.restore()
  }else{
    mainWindow.maximize()
  }
}
ipcMain.on('window-min', function () {
    mainWindow.minimize();
})
ipcMain.on('window-close', function () {
    mainWindow.close();
})

在preload.js中添加

contextBridge.exposeInMainWorld('ipcRenderer', {
  ...ipcRenderer,
  on: (channel: any, callback: any) => {
    ipcRenderer.on(channel, callback)
  }
})

在页面中对按钮添加事件:

<img src="../../assets/min.png" @click="min()" />
 <img src="../../assets/close.png" @click="close()" />
 ……
<script lang="ts" setup>
const min=()=>{
 window.ipcRenderer.send("window-min")
}
const close=()=>{
 window.ipcRenderer.send("window-close")
}
……

 

扩展9:自定义标题

定义窗口标题有两个办法:

办法一:直接在内容html中使用title设置标题

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
    <title>标题就在这里设置</title>
  </head>
  <body style="margin:0;">
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

这种方法适合单页面应用。以上就是vue单页面应用的index.html典型写法。

办法二:使用BrowserWindow的构造参数设置title,但要去掉html中的title,因为html中title优先级更高。

const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    title:'这里设置标题',
    webPreferences:{
      // 渲染进程(rendee.js)中可以使用 nodejs 
      nodeIntegration: true,
      contextIsolation:false,
      enableRemoteModule: true, // 启用remote模块
    },
  });

官方对此参数的说明:titlestring(可选) - 默认窗口标题 默认为"Electron"。 如果由loadURL()加载的HTML文件中含有标签<title>,此属性将被忽略。

 

 

posted @ 2022-06-22 11:08  小y  阅读(1175)  评论(0编辑  收藏  举报