Latest Post

Khái niệm về Solidity và tổng quan về ngôn ngữ lập trình Solidity Phương pháp kiểm tra nhiệt độ CPU đơn giản

Để tạo một ứng dụng Node.js Electron chạy dưới nền (background), bạn cần thiết lập ứng dụng để có thể hoạt động mà không cần hiển thị cửa sổ (hoặc với cửa sổ bị ẩn) và vẫn thực hiện các tác vụ như thông báo, xử lý dữ liệu, hoặc giao tiếp với hệ thống.

Dưới đây là hướng dẫn cụ thể:


1. Tạo ứng dụng Electron cơ bản

Đầu tiên, bạn cần đảm bảo rằng ứng dụng Electron của bạn đã được thiết lập. Một tệp main.js cơ bản sẽ trông như sau:

const { app, BrowserWindow } = require('electron');

let mainWindow;

app.on('ready', () => {
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        show: false, // Ẩn cửa sổ khi khởi động
        webPreferences: {
            nodeIntegration: true,
        },
    });

    mainWindow.loadFile('index.html');

    // Đảm bảo không đóng hoàn toàn khi cửa sổ bị tắt
    mainWindow.on('close', (e) => {
        if (!app.isQuiting) {
            e.preventDefault();
            mainWindow.hide(); // Ẩn cửa sổ thay vì đóng
        }
    });
});

2. Chạy ứng dụng dưới nền (Background Process)

a. Ẩn cửa sổ ứng dụng

Sử dụng thuộc tính show: false khi tạo cửa sổ (BrowserWindow).
Bạn cũng có thể ẩn cửa sổ sau khi khởi động bằng mainWindow.hide().

b. Kích hoạt biểu tượng tray (System Tray)

Thêm biểu tượng vào system tray để người dùng vẫn có thể tương tác với ứng dụng.

Ví dụ:

const { Tray, Menu } = require('electron');

let tray;

app.on('ready', () => {
    tray = new Tray('path/to/icon.png'); // Đường dẫn đến icon của ứng dụng
    const contextMenu = Menu.buildFromTemplate([
        { label: 'Mở ứng dụng', click: () => mainWindow.show() },
        { label: 'Thoát', click: () => {
            app.isQuiting = true;
            app.quit();
        }},
    ]);
    tray.setToolTip('Ứng dụng chạy nền của tôi');
    tray.setContextMenu(contextMenu);

    tray.on('click', () => {
        mainWindow.show(); // Hiển thị cửa sổ khi nhấp vào tray
    });
});

c. Giữ ứng dụng hoạt động khi cửa sổ bị ẩn

Sử dụng mainWindow.hide() thay vì mainWindow.close() để ứng dụng không bị đóng hoàn toàn.


3. Chạy tác vụ dưới nền (Background Task)

Sử dụng các module Node.js như child_process, worker_threads, hoặc gói như node-schedule để chạy các tác vụ nền.

Ví dụ: Một task chạy lặp trong nền:

const { setInterval } = require('timers');

function runBackgroundTask() {
    setInterval(() => {
        console.log('Tác vụ đang chạy dưới nền...');
        // Thực hiện logic, như kiểm tra dữ liệu mới hoặc gửi thông báo
    }, 5000); // Mỗi 5 giây
}

// Chạy task khi ứng dụng sẵn sàng
app.on('ready', () => {
    runBackgroundTask();
});

4. Tự động khởi động khi bật máy (Auto Start)

Sử dụng gói electron-settings hoặc auto-launch để tự động khởi động ứng dụng khi người dùng bật máy.

Ví dụ với gói auto-launch:

const AutoLaunch = require('auto-launch');

const appLauncher = new AutoLaunch({
    name: 'MyElectronApp',
    path: app.getPath('exe'), // Đường dẫn tới file thực thi
});

appLauncher.isEnabled().then((isEnabled) => {
    if (!isEnabled) {
        appLauncher.enable();
    }
}).catch((err) => {
    console.error('Lỗi khi thiết lập tự động khởi động:', err);
});

Cài đặt gói:

npm install auto-launch

5. Gửi thông báo từ background

Electron hỗ trợ gửi thông báo native:

const { Notification } = require('electron');

function showNotification(title, body) {
    new Notification({ title, body }).show();
}

app.on('ready', () => {
    showNotification('Ứng dụng đang chạy nền', 'Ứng dụng của bạn đã sẵn sàng!');
});

6. Đóng ứng dụng hoàn toàn

Đảm bảo ứng dụng không còn chạy trong system tray khi người dùng chọn thoát:

tray.on('right-click', () => {
    const contextMenu = Menu.buildFromTemplate([
        { label: 'Thoát', click: () => {
            app.isQuiting = true;
            app.quit();
        }},
    ]);
    tray.popUpContextMenu(contextMenu);
});

Tóm tắt các bước

  1. Ẩn cửa sổ khi khởi động (show: false).
  2. Thêm tray icon để ứng dụng dễ dàng tương tác dưới nền.
  3. Tạo tác vụ nền với setInterval, worker_threads, hoặc các gói như node-schedule.
  4. Tự động khởi động khi bật máy với gói auto-launch.
  5. Gửi thông báo hệ thống khi cần thiết để tương tác với người dùng.

😊

Có, các tác vụ đang chạy trong ứng dụng Electron vẫn sẽ tiếp tục hoạt động ngay cả khi cửa sổ ứng dụng bị ẩn, miễn là ứng dụng vẫn đang chạy (tức là không bị đóng). Điều này là do bản chất của Electron: nó hoạt động như một quá trình Node.js và quá trình này không phụ thuộc vào trạng thái hiển thị của cửa sổ.


Cơ chế hoạt động khi cửa sổ bị ẩn

  1. Quá trình Main Process:
    • Đây là quá trình chính quản lý toàn bộ ứng dụng Electron.
    • Các tác vụ chạy trong Main Process (như giao tiếp với hệ thống, thực hiện các tác vụ định kỳ, hoặc quản lý cửa sổ) vẫn sẽ hoạt động bình thường khi cửa sổ bị ẩn.
  2. Quá trình Renderer Process:
    • Đây là nơi mã JavaScript/HTML/CSS của bạn được hiển thị trong cửa sổ (giao diện người dùng).
    • Khi cửa sổ bị ẩn, Renderer Process vẫn chạy, nhưng người dùng sẽ không thấy giao diện. Bạn có thể tiếp tục thực hiện logic trong trình duyệt (như cập nhật dữ liệu, xử lý sự kiện…).

Khi nào các tác vụ dừng lại?

  1. Nếu ứng dụng bị đóng hoàn toàn (quit):
    • Mọi quá trình, bao gồm cả Main Process và Renderer Process, đều sẽ dừng lại.
    • Điều này xảy ra khi bạn gọi app.quit() hoặc người dùng tắt ứng dụng qua system tray hoặc Task Manager.
  2. Nếu chỉ đóng cửa sổ (ẩn xuống nền):
    • Các tác vụ trong Main Process và Renderer Process vẫn tiếp tục hoạt động.
    • Điều này xảy ra khi bạn sử dụng mainWindow.hide() hoặc không gọi mainWindow.close().

Ví dụ minh họa: Tác vụ vẫn hoạt động khi cửa sổ bị ẩn

Dưới đây là một ví dụ mà tác vụ trong Main Process vẫn chạy khi cửa sổ bị ẩn:

main.js

const { app, BrowserWindow, Tray, Menu } = require('electron');

let mainWindow;
let tray;

app.on('ready', () => {
    // Tạo cửa sổ chính
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        show: false, // Ẩn cửa sổ khi khởi động
        webPreferences: {
            nodeIntegration: true,
        },
    });

    mainWindow.loadFile('index.html');

    // Tạo icon trong system tray
    tray = new Tray('path/to/icon.png');
    const contextMenu = Menu.buildFromTemplate([
        { label: 'Hiện ứng dụng', click: () => mainWindow.show() },
        { label: 'Thoát', click: () => {
            app.isQuiting = true;
            app.quit();
        }},
    ]);
    tray.setContextMenu(contextMenu);

    // Chạy một tác vụ nền trong Main Process
    setInterval(() => {
        console.log('Tác vụ vẫn chạy dưới nền...');
    }, 5000);

    // Ngăn đóng hoàn toàn cửa sổ
    mainWindow.on('close', (e) => {
        if (!app.isQuiting) {
            e.preventDefault();
            mainWindow.hide(); // Ẩn cửa sổ thay vì đóng
        }
    });
});

Khi nào cần tạo tác vụ nền riêng?

Bạn chỉ cần tạo tác vụ nền riêng (ví dụ, dùng worker_threads hoặc child_process) khi:

  1. Tác vụ nặng (như xử lý dữ liệu lớn, phân tích tệp…) làm ảnh hưởng đến hiệu suất Main Process.
  2. Bạn muốn chia các tác vụ ra nhiều luồng (multi-threading) để tăng hiệu suất.
  3. Bạn cần thực hiện một công việc độc lập mà không phụ thuộc vào trạng thái của ứng dụng.

Nếu tác vụ của bạn nhẹ và không phức tạp, thì chỉ cần chạy trực tiếp trong Main Process hoặc Renderer Process là đủ.


Kết luận

  • Cửa sổ bị ẩn không làm dừng các tác vụ đang chạy.
  • Mọi tác vụ trong Main Process hoặc Renderer Process vẫn tiếp tục hoạt động miễn là ứng dụng chưa bị thoát hoàn toàn.
  • Bạn chỉ cần tạo tác vụ nền riêng khi cần hiệu suất cao hoặc xử lý công việc phức tạp.

2 thoughts on “Xây dựng ứng dụng Node.js Electron có thể chạy background

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *