chalmery

chalmery

github

Electron(第一)

Electron 是一個 js 桌面端框架,讓 html,js 打包為桌面應用成為可能,已經有非常多的應用使用了這門技術,如:vscode,notion,figma,思源筆記等等

image-20230614231941-kvlx0yu

一 整體交互形式#

桌面應用最重要的是什麼,或者說和瀏覽器頁面有什麼區別?大致來說就是可以和操作系統交互,那麼什麼叫可以和操作系統交互?讓我們回顧一下瀏覽器,瀏覽器就像一個盒子,裡面的所有頁面的權利是有限的,就比如,

  • 我想在瀏覽器自己寫的 html 頁面通過 js 函數,在文檔這個文件夾下創建一個文件,或者修改一個文件
  • 調用系統通知 api,使用系統通知
  • 修改系統音量?

這些都是做不到的,這些都涉及了操作系統的 api,那 electron 是如何做到的呢,我們看一下這個圖:

bafkreihsovyhp2czleo53nzxtzlrmvbcq3tech4mzljwu2xnauk4sztahm
​​

Electron 就相當於一個中間層,為 js 提供了一個曲線訪問系統 api 的能力,做任何和系統有關的操作,都要通過 electron

一個簡單的例子,我想通過文件選擇器,拿到一個文件的路徑,該如何實現?你可能會想到,瀏覽器也可以呀,通過選擇器,選擇一個文件,還要 Electron 幹嘛?

是沒問題,可以選到一個文件,但是文件的路徑是獲取不到的,簡單思考一下,如果一個普通的網頁,點擊就能獲取到你本機文件的路徑,甚至別的操作系統信息,你作為瀏覽器的開發者會允許這樣嗎?這樣對瀏覽器使用者來講顯然是非常危險的,點開個網頁信息洩密了,甚至電腦上文件丟了。

因此,我們要使用的文件選擇器是操作系統的文件選擇器,這個顯然是 js 辦不到的,因此有了 Electron,它提供了這樣的 api:文檔詳見:https://www.electronjs.org/zh/docs/latest/api/dialog

import {dialog} from "electron";

function open() {
    let files = dialog.showOpenDialogSync({
        title: '選擇文件路徑',
        properties: ['openDirectory', 'multiSelections']
    })
    console.log(files)
    return files
}

文件選擇器有了,我們該如何通知 Electron 呢?換句話說就是,上面的 js 函數是顯示層調用不到的,因此 Electron 提供了一種方式,讓我們可以與它交互。這種方式類似 js 的發布訂閱模型,發布一個事件,消費者監聽事件。

文檔詳見:https://www.electronjs.org/zh/docs/latest/api/ipc-renderer

js 端通過 ipcRenderer.send 發送一個事件通過 Electron

const electron = window.electron

electron.ipcRenderer.send('事件名稱',data)

electron 端通過 ipcMain.on 監聽 js 端發送過來的事件,那當這件事情處理完成了,想要告訴 js 端怎麼辦?通過 event.reply 發送一個事件,攜帶數據給 js,和上面的 ipcRenderer.send 是類似的

import {ipcMain} from "electron"

 ipcMain.on('事件名稱',(event, data)) => {
        //處理


        //回調
        event.reply('新的事件名稱', 要返回的數據)
    })

js 端該如何處理呢?以 React 為例:useEffect 中,通過 ipcRenderer.on,監聽這個事件,然後處理,一定要在 [] 這個 useEffect,代表頁面創建就運行這個函數,監聽這個事件,在 return 中刪除這個事件,不然每次每次頁面加載都會創建一個監聽,這樣會越建越多

useEffect(() => {
    //處理Electron端發送的事件
    electron.ipcRenderer.on('事件名稱', (event, 數據) => {
      //處理
    });

    return () => {
      electron.ipcRenderer.removeAllListeners('事件名稱');
    };
  }, []);

到這裡就完成了一個交互,是不是很簡單。

二 打包#

打包全靠配置,這個是我的配置:

/**
 * @see https://www.electron.build/configuration/configuration
 */
{
  appId: "electron-music",
  productName: "electron-music",
  copyright: "Copyright © 2023 ${author}",
  asar: true,
  directories: {
    output: "release",
    buildResources: "public"
  },
  files: [
    "dist"
  ],
  win: {
    icon: "public/icons/music256x256.png",
    target: [
      {
        target: "dir",
        arch: [
          "x64"
        ]
      },
      {
        target: "nsis",
        arch: [
          "x64"
        ]
      }
    ]
  },
  nsis: {
    "oneClick": false,
    // 創建一鍵安裝程序還是輔助安裝程序(默認是一鍵安裝)
    "allowElevation": true,
    // 是否允許請求提升,如果為false,則用戶必須使用提升的權限重新啟動安裝程序 (僅作用於輔助安裝程序)
    "allowToChangeInstallationDirectory": true,
    // 是否允許修改安裝目錄 (僅作用於輔助安裝程序)
    "installerIcon": "public/icons/music256x256.png",
    // 安裝程序圖標的路徑
    "uninstallerIcon": "public/icons/music256x256.png",
    // 卸載程序圖標的路徑
    "installerHeader": "public/icons/music256x256.png",
    // 安裝時頭部圖片路徑(僅作用於輔助安裝程序)
    "installerHeaderIcon": "public/icons/music256x256.png",
    // 安裝時標題圖標(進度條上方)的路徑(僅作用於一鍵安裝程序)
    "installerSidebar": "public/icons/music256x256.png",
    // 安裝完畢界面圖片的路徑,(僅作用於輔助安裝程序)
    "uninstallerSidebar": "public/icons/music256x256.png",
    // 開始卸載界面圖片的路徑(僅作用於輔助安裝程序)
    "uninstallDisplayName": "electron-music-${version}",
    // 控制面板中的卸載程序顯示名稱
    "createDesktopShortcut": true,
    // 是否創建桌面快捷方式
    "createStartMenuShortcut": true,
    // 是否創建開始菜單快捷方式
    "include": "script/installer.nsi",
    // NSIS包含定制安裝程序腳本的路徑,安裝過程中自行調用  (可用於寫入註冊表 開機自啟動等操作)
    "script": "script/installer.nsi",
    // 用於自定義安裝程序的NSIS腳本的路徑
    "deleteAppDataOnUninstall": true,
    // 是否在卸載時刪除應用程序數據(僅作用於一鍵安裝程序)
    "runAfterFinish": false,
    // 完成後是否運行已安裝的應用程序(對於輔助安裝程序,應刪除相應的復選框)
    "menuCategory": false,
    // 是否為開始菜單快捷方式和程序文件目錄創建子菜單,如果為true,則使用公司名稱
    "perMachine": true,
    //給機器上所有用戶安裝
    "language": "2052"
    //安裝語言(中文)
  },
  mac: {
    icon: 'public/icons/music256x256.png',
    category: 'Productivity',
    target: [
      {
        target: 'default',
        arch: [
          'arm64',
          'x64'
        ]
      }
    ]
  },
  linux: {
    icon: "public/icons/music256x256.png",
    target: [
      "AppImage",
      "tar.gz"
    ],
    "category": "Audio",
    artifactName: "${productName}-Linux-${version}.${ext}"
  }
}

參考: 我的音樂播放器項目

三 注意事項#

1 在 linux 下窗口關閉前做一件事#

看環境,比如 kde 下是做不到比如隱藏窗口的,在 kde 下,點擊關閉按鈕,window 對象對直接就銷毀了。(曲線方式,我們可以不用系統自帶的頂欄,自己實現一個,這樣就不會有這樣的問題了)

app.on('closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

2 linux 下,英偉達顯卡涉及到動畫的頁面報錯(暫未解決)#

報錯內容

libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null)
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。