Electron - 跨平台的視窗應用程式

一、Electron介紹


Electron Logo

Electron(原名為Atom Shell)是GitHub開發的一個開源框架[5]它允許使用Node.js(作為後端)和Chromium(作為前端)完成桌面GUI應用程式的開發。Electron現已被多個開源Web應用程式用於前端與後端的開發,著名專案包括GitHub的Atom微軟Visual Studio Code

由於開發環境就是基於 Node.js,請務必安裝好。


很多知名的桌面應用程式都是使用 Electron 開發的例如:

  • Github Desktop
  • Discord
  • WordPress.com
  • Visual Studio Code
  • Slack
  • Atom


二、專案建立

以下實務操作將建立一個桌面鬧鐘通知應用程式,此範例從此處學習

首先我們建立專案資料夾,並初始化:

mkdir electron-alarm-clock && cd electron-alarm-clock
npm init -y

  • 你可以直接手動新增資料夾,然後進入(可以不用這麼工程師的方式)
  • 進入專案後使用終端機輸入 npm init -y 進行初始專案(-y 是將詢問的條件通通默認 yes)

安裝 electron:

npm install --save--dev electron

  • --save-dev 會將指定套件存於 package.json 的 devDependencies
  • 因為 electron 只有開發階段才需要用到,因此只需要 --save--dev


在 package.json 修改程式進入點位置:

main 的部分,將 index.js 改為 main.js
script 的部分,新增 start
[ package.json ]
{
  "name": "electron-alarm-clock",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^1.8.4"
  }
}

新增檔案 main.js: 

[ main.js ]
const {
    app,
    BrowserWindow,
} = require('electron')

const path = require('path')
const url = require('url')

app.on('ready', createWindow)

app.on('window-all-closed', () => {
    // darwin = MacOS
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

app.on('activate', () => {
    if (win === null) {
        createWindow()
    }
})

function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({
        width: 400,
        height: 400,
        maximizable: false,
        webPreferences: {
            nodeIntegration: true
        }
    })

    win.loadURL(url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file:',
        slashes: true
    }))

    // Open DevTools.
    // win.webContents.openDevTools()

    // When Window Close.
    win.on('closed', () => {
        win = null
    })

}

在 main.js 中我們指定畫面來源為 index.html,

[ index.html ]
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Electron</title>
</head>

<body>
    <h1>Hello Electron</h1>
    <p>Node Version:
        <script>document.write(process.versions.node)</script>
    </p>
    <p>Chrome Version:
        <script>document.write(process.versions.chrome)</script>
    </p>
    <p>Electron Version:
        <script>document.write(process.versions.electron)</script>
    </p>
</body>

</html>
在 script 中,我們可以調用 node.js 的物件,在這邊我們範例使用 process

運行結果:
npm start

以上我們完成了基本的環境與專案建立。

三、鬧鐘提醒程式開發

這邊基本上可以自行開發創作,
以下功能會進行時間的偵測,並透過 Notification 進行提醒。


元素布置

首先放置「顯示當前時間的元素」、「可輸入時間的輸入方塊」,

以及載入畫面端主程式 app.js
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Electron</title>
</head>

<body>
    <h1>Hello Electron</h1>
    <p>Node Version:
        <script>document.write(process.versions.node)</script>
    </p>
    <p>Chrome Version:
        <script>document.write(process.versions.chrome)</script>
    </p>
    <p>Electron Version:
        <script>document.write(process.versions.electron)</script>
    </p>
    <hr>
    <div class="now-time"></div>
    <input type="text" class="alarm-time">

    <script src="app.js"></script>
</body>

</html>


顯示時間並不斷地更新
在時間操作上,我們使用套件 moment.js ⏱,比較方便操作。
npm install --save moment
[ app.js ]
const moment = require('moment')

const elNow = document.querySelector('.now-time')
const elAlarm = document.querySelector('.alarm-time')
elAlarm.addEventListener('change', onAlarmTextChange)

let time = moment()

let nowTime
let alarmTime

/** Set Time */
const now = moment(time).format('HH:mm:ss')
nowTime = now
elNow.innerText = now

const alarm = moment(time).add(5, 'seconds').format('HH:mm:ss')
alarmTime = alarm
elAlarm.value = alarm

timer()

/** Now Time */
function timer() {
    time = moment().format('HH:mm:ss')

    /** Set Now */
    nowTime = time
    elNow.innerText = time

    setTimeout(() => {
        timer()
    }, 1000)
}

/**
 * Save To Global Variable,
 * Can't Read Dom In Minimize Status.
 * @param {event} event
 */
function onAlarmTextChange(event) {
    alarmTime = event.target.value
}

  • 提醒時間:預設當前時間過後 5 秒
  • nowTime:把當前時間存成全域變數
  • alarmTime:把提醒時間存成全域變數 

可以看到不斷地更新當前時間。

npm start


















提醒時間

判斷時間如果符合提醒,就跳出通知。

[ app.js ]
/** Now Time */
function timer() {
    time = moment().format('HH:mm:ss')

    /** Set Now */
    nowTime = time
    elNow.innerText = time

    check()

    setTimeout(() => {
        timer()
    }, 1000)
}

/** Check Time */
function check() {
    const diff = moment(nowTime, 'HH:mm:ss').diff(moment(alarmTime, 'HH:mm:ss'))
    if (diff === 0) {
        alert('wake up!')
    }
}

timer 中呼叫 check

當時間到的時候,會跳出訊息。
npm start


通知訊息

通知的部分,因為在 Windows10 好像 Notification 會有點失效問題 😪,

在這邊選用一個套件 node-notifier 來進行通知。

npm install --save node-notifier
[ app.js ]
const notifier = require('node-notifier')
const path = require('path')
/** Check Time */
function check() {
    const diff = moment(nowTime, 'HH:mm:ss').diff(moment(alarmTime, 'HH:mm:ss'))
    if (diff === 0) {
        const msg = "It's" + alarmTime + ". Wake Up!"
        /** const msg = `It's ${alarmTime}. Wake Up!` */
        notice(msg)
    }
}

/**
 * System Notification
 * @param {string} msg
 */
function notice(msg) {
    /** https://github.com/mikaelbr/node-notifier */
    notifier.notify({
        title: 'Alarm Clock',
        message: msg,
        icon: path.join(__dirname, 'clock.ico'),
        sound: true,
    })
}

四、程式編譯

將程式編譯成 exe,我們使用 electron-packager,

在 package.json 中,新增封裝指令 build:
npm install electron-packager --save-dev
[ package.json ]
{
  "scripts": {
    "start": "electron .",
    "build": "electron-packager . AlarmClock --out AlarmClock --overwrite --platform=win32 --arch=x64 --icon=clock.ico --prune=true --squirrel-install --ignore=node_modules/electron-* --electron-version=1.7.9 --ignore=AlarmClock-win32-x64 --version-string.CompanyName=Robby --version-string.ProductName=AlarmClock",
  },
}

  • electron-packager . AlarmClock:把當前目錄 . 打包起來,並將應用程式命名 AlarmClock
  • --out AlarmClock:輸出資料夾於 AlarmClock,產出後預設資料夾為 AlarmClock-win32-x64
  • --overwrite:如果已經存在資料夾和檔案,會進行覆寫
  • --platform=win32:平台為 Windows(Mac: darwin, Linux: linux)
  • --arch=x64:應用程式 64位元(ia32, all)
  • --icon=clock.ico:應用程式 ICON
  • --ignore=node_modules/electron-*:忽略的檔案
  • --electron-version=1.7.9:electron 的核心版本
  • --version-string.CompanyName=Robby:軟體公司名稱(顯示於軟體資訊中)
  • --version-string.ProductName=AlarmClock:軟體名稱(顯示於軟體資訊中) 
試著編譯看看。

npm run build

應用程式就可以直接執行了!


留言

這個網誌中的熱門文章

Visual Sudio2019創建MFC ActiveX工程製作IE OCX插件

Little Endian VS Big Endian

Converting Between Byte Arrays and Hexadecimal Strings in Java