electron && angular 構建桌面應用(二)


electron如何工作?

Electron由主進程和渲染器進程所組成。每個進程在應用程序中扮演不同的角色,Electron包含不同的模塊來幫助您構建應用程序。某些模塊,例如從系統剪貼板讀寫的能力,在這兩種類型的進程中都可用。其他的,比如訪問操作系統接口的能力,僅限於主進程。

主進程 main process

Electron運行packagemain腳本的進程被稱為主進程主流程有幾個重要的職責。它可以響應應用程序生命周期事件,例如啟動、退出、准備退出、后台調用、前台跳轉等等。主過程也負責與本機操作系統接口通信。如果你想要顯示對話框去打開或者保存文件,可以從主進程中執行。package.json里的main配置的js文件,即為主進程。

渲染進程 renderer process

主進程可以使用Electron瀏覽器窗口模塊創建和銷毀渲染器進程,渲染器進程可以加載web頁面來顯示用戶界面。每一個進程利用Chromium的多進程架構,並在自己的線程上運行,然后,這些頁面可以加載其他JavaScript文件並在此進程中執行代碼。與普通web頁面不同,你可以在自己的渲染進程中,訪問所有Node APIs,允許使用本機模塊和較低級別的系統交互。每個渲染進程都是獨立的,無法訪問操作系統集成的接口。如果需要觸發打開或保存文件對話框或訪問任何其他操作系統集成,其對應的渲染進程必須與主進程進行通訊。

使用electron的api

Electron在主進程和渲染進程中提供了大量API去幫助開發桌面應用程序, 在主進程和渲染進程中,你可以通過require的方式將其包含在模塊中以此,獲取Electron的API。

import { app, BrowserWindow, screen, ipcMain } from 'electron';

  所有Electron的API都被指派給一種進程類型。 許多API只能被用於主進程或渲染進程中,但其中一些API可以同時在上述兩種進程中使用。 每一個API的文檔都將聲明你可以在哪種進程中使用該API。

Electron中的窗口是使用BrowserWindow類型創建的一個實例, 它只能在主進程中使用。

// 這樣寫在主進程會有用,但是在渲染進程中會提示'未定義'
const { BrowserWindow } = require('electron')

const win = new BrowserWindow()

因為進程之間的通信是被允許的, 所以渲染進程可以調用主進程來執行任務。 Electron通過remote模塊暴露一些通常只能在主進程中獲取到的API。 為了在渲染進程中創建一個BrowserWindow的實例,我們通常使用remote模塊為中間件:

import { remote, ipcRenderer } from 'electron';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent{
  remote: typeof remote;
  fs: typeof fs;
  ipcRender: typeof ipcRenderer; 
  constructor(){
    this.remote = window.require('electron').remote;
    const win = this.remote.BrowserWindow();
  }
}

使用Nodejs的api

Electron同時對主進程和渲染進程暴露了Node.js 所有的接口。 這里有兩個重要的定義:

1)所有在Node.js可以使用的API,在Electron中同樣可以使用。 在Electron中調用如下代碼是有用的:

import * as path from 'path';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent{
  fs;
  constructor(){
    this.fs = window.require('fs');
    console.log("fs:", this.fs.readdirSync('/'));
    console.log("path:", path.join(__dirname, 'dist/index.html'));
  }
}

坑1:渲染進程使用nodejs的api時,如fs,需要通過var fs = window.require('fs)這種方式引入。寫成var fs = require('fs') 或 import * as fs from 'fs' 時會報找不到fs module的錯誤。還可以通過配置webpack的配置項來解決該問題。

更佳的解決方案是通過webpack自身來幫我們解決,即修改webpack提供的target產出目標為electron,即:

 

  • 修改electron主線程webpack的target配置項為electron-main
  • 修改electron渲染線程的webpack的target配置項為electron-renderer

 

這樣就可以更好的解決上面的問題。

 

坑2:electron默認在渲染進程中不支持使用nodejs。需要在主進程中進行以下配置:

win = new BrowserWindow({
    width: 500,
    height: 800,
    webPreferences: {
      nodeIntegration: true,
    },
  });

需將nodeIntegration置為true。

渲染進程與主進程間通信

渲染進程中使用ipcRenderer.

import { Component } from '@angular/core';
import { remote, ipcRenderer } from 'electron';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent{
  remote: typeof remote;
  ipcRender: typeof ipcRenderer; 
  constructor(){
    this.remote = window.require('electron').remote;
    this.ipcRender = window.require('electron').ipcRenderer;
  }

  sendMsg(){
    this.ipcRender.send('create-folder');
    this.ipcRender.on('create-folder-result', function(event, data) {
      console.log(data);//finished!
    })
  }
}

  主進程使用ipaMain

import { app, BrowserWindow, screen, ipcMain } from 'electron';

let win: BrowserWindow = null;

function createWindow(): BrowserWindow {

  // Create the browser window.
  win = new BrowserWindow({
    width: 500,
    height: 800,
    webPreferences: {
      nodeIntegration: true,
    },
  });

 
  win.loadURL('http://localhost:4200');

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

  return win;
}

try {

  // This method will be called when Electron has finished
  // initialization and is ready to create browser windows.
  // Some APIs can only be used after this event occurs.
  app.on('ready', createWindow);

  // Quit when all windows are closed.
  app.on('window-all-closed', () => {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
      app.quit();
    }
  });

  app.on('activate', () => {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (win === null) {
      createWindow();
    }
  });

  ipcMain.on('create-folder', (evt, arg) => {
    console.log("ipcMain");
    evt.sender.send('create-folder-result', { msg: 'finished!' })
  })

} catch (e) {
  // Catch Error
  // throw e;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM