Skip to content

python 3.8.10

If using Python, the framework can be divided into 3 parts.

  • Frontend UI
  • Electron main process
  • Python business process

Concepts

Frontend UI

Responsible for software interface display and effects. You can use any frontend technology. See documentation: Frontend Module

Electron

Business involving OS functionality, such as calling OS APIs, opening folders, system dialogs, etc. See documentation: Basic Features

Python

Use Python to write business logic.

Directory Structure

bash
project
├── ...
├── python Business directory
    ├── dist Executable program built using cx_Freeze
    ├── main.py Entry point, demo uses Flask framework
    ├── requirements.txt Python dependencies
    ├── setup.py Build script for the cx_Freeze module
    ├── fastapi-demo.py

Standalone Development and Debugging of Python Project

  1. Edit ./cmd/bin.js
javascript
// bin development configuration
  /**
   * Execute custom commands
   * ee-bin exec
   */
  exec: {
    python: {
      directory: './python',
      cmd: 'python',
      args: ['./main.py', '--port=7074'],
      stdio: "inherit", // ignore
    },
  1. Edit ./package.json
javascript
  "scripts": {
    "dev-python": "ee-bin exec --cmds=python",
  }
  1. Debug
bash
npm run dev-python

How to Run a Python Project in Electron

Start it through the cross module API.

API Mode

Create a Python service via API

javascript
  // File electron/service/cross.js

  /**
   * create python service
   * In the default configuration, services can be started with applications. 
   * Developers can turn off the configuration and create it manually.
   */   
  async createPythonServer() {
    // method 1: Use the default Settings
    //const entity = await cross.run(serviceName);

    // method 2: Use custom configuration
    const serviceName = "python";
    const opt = {
      name: 'pyapp',
      cmd: path.join(getExtraResourcesDir(), 'py', 'pyapp'),
      directory: path.join(getExtraResourcesDir(), 'py'),
      args: ['--port=7074'],
      windowsExtname: true,
      appExit: true,
    }
    const entity = await cross.run(serviceName, opt);
    logger.info('server name:', entity.name);
    logger.info('server config:', entity.config);
    logger.info('server url:', entity.getUrl());

    return;
  }

Start with Application Launch

If you want the Python executable to start when the desktop application runs, there are several ways.

Import and call directly in the preload module.

javascript
// File electron/preload/index.js

/*************************************************
 ** preload is a pre-load module, this file will be loaded when the program starts **
 *************************************************/
const { crossService } = require('../service/cross');

function preload() {
  // Call directly
  crossService.createPythonServer();
}

Get Service Address

Get the local service address by program name, typically ip:port (http://127.0.0.1:7074). If the configured port 7074 is occupied, the framework will randomly generate one.

javascript
  /**
   * Get service url
   */  
  async getUrl(args) {
    const { name } = args;
    const serverUrl = cross.getUrl(name);
    return serverUrl;
  }

Kill Process

Kill a process by program name, or kill all processes.

javascript
  /**
   * kill service
   * By default (modifiable), killing the process will exit the electron application.
   */  
  async killServer(args) {
    const { type, name } = args;
    if (type == 'all') {
      cross.killAll();
    } else {
      cross.killByName(name);
    }

    return;
  }

Communication

HTTP is the most universal communication protocol currently. IPC communication for different languages may be implemented in the future.

javascript
  /**
   * Access the api for the cross service
   */
  async requestApi(name, urlPath, params) {
    const serverUrl = cross.getUrl(name);
    const apiHello = serverUrl + urlPath;
    console.log('Server Url:', serverUrl);

    const response = await axios({
      method: 'get',
      url: apiHello,
      timeout: 1000,
      params,
      proxy: false,
    });
    if (response.status == 200) {
      const { data } = response;
      return data;
    }

    return null;
  }