构建应用
下载项目
构建应用需要另一个项目scratch-desktop
,先下载下来。
git clone https://github.com/LLK/scratch-desktop.git
cd scratch-desktop
npm install
GUI 准备
gui 项目包 link 到本地。
cd scratch-gui
npm install
npm link
desktop 关联本地的 gui 项目。
cd scratch-desktop
npm install
npm link scratch-gui
这样,desktop 的 node_modules 下面的scratch-gui
快捷方式,指向的就是 gui 项目位置。
Electron
[!danger]
官方的 desktop 比较麻烦,安装失败好多次。我们发现,其实 desktop 使用的是 Electron 框架,我们可以自己搭建 Electron 框架,自己编译构建应用。
package.json
新建package.json
,内容如下。
{
"name": "scratch-electron",
"version": "1.0.1",
"description": "Scrtch GUI",
"scripts": {
"debug": "electron ./debug/start.js",
"start": "electron ./index.js",
"build-win": "electron-builder --win",
"build-mac": "electron-builder --mac",
"elec-i": "cross-env ELECTRON_MIRROR=https://cdn.npm.taobao.org/dist/electron/ npm install electron -S"
},
"license": "ISC",
"devDependencies": {
"console-color-mr": "2.0.1",
"cross-env": "7.0.2",
"electron": "^10.4.5",
"electron-builder": "22.9.1",
"electron-rebuild": "^2.3.4",
"javascript-obfuscator": "2.6.3"
},
"build": {
"productName": "ScratchElectron",
"appId": "kujiajia.club",
"copyright": "Copyright © 2021 Code++",
"asar": false,
"directories": {
"output": "build"
},
"electronDownload": {
"mirror": "https://npm.taobao.org/mirrors/electron/"
},
"mac": {
"icon": "assets/icon.icns",
"artifactName": "${productName}_setup_${version}.${ext}"
},
"win": {
"icon": "assets/icon.ico",
"target": [
{
"target": "nsis",
"arch": ["ia32"]
}
]
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true
}
}
}
安装依赖
执行下面命令,安装依赖。
npm run elec-i
npm install
npm link scratch-gui
创建图标
新建assets
文件夹,把应用图标的图片放进来。
系统 | 图片 | 文件名 |
---|---|---|
win 系统 | icon.icn | |
macOS 系统 | icon.icns |
调试页面
创建bebug
文件夹,分别创建下面三个文件,用于调试。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>调试</title>
</head>
<body>
<h3>系统参数</h3>
<div>
Node.js - <span id="node-version"></span><br />
Chromium - <span id="chrome-version"></span><br />
Electron - <span id="electron-version"></span>
</div>
<h3>浏览器参数</h3>
<div>Language - <span id="language-navigator"></span></div>
</body>
</html>
preload.js
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]);
}
for (const type of ['language']) {
replaceText(`${type}-navigator`, navigator.language);
}
});
start.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
app.commandLine.appendSwitch('lang', 'zh_CN');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
devTools: true,
preload: path.join(__dirname, 'preload.js'),
},
});
mainWindow.webContents.openDevTools();
mainWindow.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit();
});
完成后的页面如下。
然后执行命令,启动调试。
npm run debug
启动后,界面如下。
这表示 Electron 已经安装成功,我们可以使用了。
注意,调试页面上面的 Node.js 版本很重要,这是 Electron 内置的版本,我们外部的 Node 版本也需要一样。这样打包时候才不会报错。
启动命令
创建index.js
文件,内容如下。
const { app, ipcMain, dialog, BrowserWindow } = require('electron');
const process = require('process');
const window = require('./window');
console.log(`*🚀开始启动客户端应用程序`);
let winInstance = null;
app.commandLine.appendSwitch('lang', 'zh_CN');
function initialize() {
let isGetLock = app.requestSingleInstanceLock();
if (!isGetLock) {
app.quit();
process.exit(0);
}
app.on('second-instance', () => {
if (winInstance) {
if (winInstance.isMinimized()) winInstance.restore();
winInstance.focus();
winInstance.show();
} else {
winInstance = window.create();
}
});
app.on('ready', async () => {
try {
winInstance = window.create();
} catch (error) {
if (error.code == 'EADDRINUSE') {
dialog.showErrorBox('端口被占用!', '请关闭其他程序或重启计算机');
app.quit();
} else {
dialog.showErrorBox('启动失败', '初始化应用失败,请卸载后重新安装');
app.quit();
}
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
app.on('window-all-closed', () => {
app.quit();
});
app.on('gpu-process-crashed', () => {
console.log('App crashed!!!');
app.exit(0);
});
}
initialize();
ipcMain.on('quit', () => {
app.quit();
process.exit(0);
});
创建window.js
文件,内容如下。
const { app, BrowserWindow, Menu, dialog } = require('electron');
const path = require('path');
let mainWindow = null;
function createWindow(callback) {
const indexPage = path.resolve(__dirname, './www/index.html');
const config = {
title: '酷加加编程器',
show: true,
center: true,
resizable: true,
movable: true,
minimizable: true,
maximizable: true,
fullscreen: true,
skipTaskbar: false,
acceptFirstMouse: true,
closable: true,
backgroundColor: '#00BFFF',
allowRunningInsecureContent: true,
frame: true,
webPreferences: {
devTools: true,
webSecurity: false,
allowDisplayingInsecureContent: true,
allowRunningInsecureContent: true,
nodeIntegration: true,
},
};
Menu.setApplicationMenu(null);
mainWindow = new BrowserWindow(config);
mainWindow.maximize();
mainWindow.loadFile(indexPage);
mainWindow.on('close', async (event) => {
event.preventDefault();
mainWindow.focus();
const index = await dialog.showMessageBoxSync({
type: 'warning',
title: '退出应用',
defaultId: 0,
message: '退出应用',
detail: '为防止项目丢失,请将项目文件保存到电脑后再关闭应用!',
buttons: ['取消', '继续退出'],
noLink: true,
cancelId: 0,
});
if (index == 1) {
mainWindow = null;
app.exit();
}
});
mainWindow
.on('closed', function () {
mainWindow = null;
})
.once('ready-to-show', function () {
if (callback instanceof Function) {
callback(mainWindow);
}
mainWindow.show();
});
return mainWindow;
}
module.exports = {
create(callback) {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.destroy();
}
mainWindow = createWindow(callback);
return mainWindow;
},
};
打包
执行下面的命令,分别打包两个安装文件。
# windows电脑打包
npm run build-win
# 苹果电脑打包
npm run build-mac
[!note]
**Eltctron 对于 Node 的版本有要,**下面是我使用的版本信息。
Electron 版本:10.3.1
内置 Node 版本:12.16.3
查看 Electron 内置的版本,可以启动 electron 应用后,使用`process.versions[‘node’]查看版本。
刚才
npm run debug
命令,执行后打开的应用就是显示 Electron 的环境信息。