【Scratch二次开发】03-构建桌面应用

构建应用

下载项目

构建应用需要另一个项目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 项目位置。

image-20210713233837962

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-winicon.icn
macOS 系统icon-macicon.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();
});

完成后的页面如下。

image-20210714002309684

然后执行命令,启动调试。

npm run debug

启动后,界面如下。

image-20210714002401427

这表示 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 的环境信息。

image-20210714002401427

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值