Electron HarmonyOS Porting Guide

[TOC]

Note: If you have not used this framework on other platforms, it is not recommended to use it directly. You should choose a cross-platform framework based on your overall cross-platform evolution plan for your software.

Environment Configuration

Operating System: Ubuntu 22.04

Disk Space: More than 200GB

Memory: More than 32GB

CPU Architecture: x86_64

Building Applications from Source Code

Downloading and Installing Source Code and Tools

Tool Installation

  1. Code Repository URL

master

  1. Install the tools git-lfs and ccache. Note: This step only needs to be executed when pulling the code for the first time.

    # Install git-lfs to ensure large files in the repository can be pulled locally. ccache is a compiler cache.
    $ sudo apt install git-lfs ccache
    

7

  1. Configure the repo tool. Note: This step only needs to be executed when pulling the code for the first time. Please ensure the python3 environment is configured before executing this step.

    # Download the Gitee repo tool (refer to Gitee Help Center: https://gitee.com/help/articles/4316)
    $ mkdir -p ~/bin
    $ curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 > ~/bin/repo
    $ chmod a+x ~/bin/repo
    $ echo 'export PATH=~/bin/:$PATH' >> ~/.bashrc
    $ source ~/.bashrc
    $ pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests
    

Installing Node.js Environment

Three installation methods are available:

Via Ubuntu Standard Repository

This method requires installing npm separately.

sudo apt update
sudo apt install -y nodejs npm

Check version number:

node -v
Via NodeSource Repository

This method installs Node.js with npm included; npm does not need to be installed separately.

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs

Check version numbers:

node -v
npm -v
Via nvm
git clone https://gitee.com/mirrors/nvm
cd nvm
bash install.sh
source ~/.bashrc

Check nvm version and install Node.js:

nvm -v

Install Node.js (version 20.18.1, 32-bit or 64-bit, using 32-bit as an example below), use and check version number:

nvm install node 20.18.1 32
nvm use 20.18.1
node -v

Pulling the chromium-electron Repository Code

  1. Clone the chromium-electron repository from the code repository.

    # Pull chromium-electron code using https
    $ git clone -b master https://gitcode.com/openharmony-sig/electron.git
    $ cd electron   # Switch to the newly cloned electron repository directory
    
    $ git lfs pull  # Execute `git lfs pull` to ensure large files in the repository are downloaded
    
    # Pull the OHOS chromium code corresponding to chromium-electron
    $ repo init -u  https://gitcode.com/openharmony-tpc/manifest.git -b pc_chromium_132 -m chromium.xml --no-repo-verify
    $ repo sync -c  # Can be executed multiple times to ensure all code is pulled successfully
    $ repo forall -c 'git lfs pull'  # Can be executed multiple times to ensure all large files are pulled successfully
    
    # Apply chromium-electron patches to OHOS chromium
    $ pushd src
    $ find -name "*.git*" -exec rm -rf "{}" \;
    $ popd
    $ chmod +x override_files.sh
    $ ./override_files.sh
    
  2. Run the script at Electron_actual_directory/src/build/install-build-deps.sh to install the required build packages. Note: This step only needs to be executed when pulling the code for the first time.

    $ sudo ./src/build/install-build-deps.sh --no-chromeos-fonts
    

    10

  3. Run the script electron_build.sh.

$ ./electron_build.sh

Q&A: Handling Electron Build Errors

Q: Why does the following error occur when running ./electron_build.sh for compilation? cannot access 'rust-toolchain.tar.gz' : No such file or directory

A: Because when executing ./override_files.sh, an unstable network caused the download of rust-toolchain.tar.gz to fail.

Output

After compilation, the build artifacts will be output in the src/out/musl_64 directory as follows:

locales/ libelectron.so electron resources.pak chrome_100_percent.pak chrome_200_percent.pak icudtl.dat libadapter.so libffmpeg.so v8_context_snapshot.bin

You can use the following script to copy the required resources (Note: Please modify source_path to your actual path):

#!/bin/sh
source_path=./Electron_actual_directory/src/out/musl_64
destination_path=./electron
if [ -d ${destination_path} ];then
	rm -rf ${destination_path}
fi
mkdir ${destination_path}
cp ${source_path}/libelectron.so ${destination_path}
cp ${source_path}/libffmpeg.so ${destination_path}
cp ${source_path}/libadapter.so ${destination_path}
cp ${source_path}/electron ${destination_path}
cp ${source_path}/icudtl.dat ${destination_path}
cp ${source_path}/v8_context_snapshot.bin ${destination_path}
cp ${source_path}/chrome_100_percent.pak ${destination_path}
cp ${source_path}/chrome_200_percent.pak ${destination_path}
cp ${source_path}/resources.pak ${destination_path}
mkdir ${destination_path}/locales
cp ${source_path}/locales/zh-CN.pak ${destination_path}/locales
cp ${source_path}/locales/en-US.pak ${destination_path}/locales

Save the script as copy.sh, place it at the same level as the chromium compilation folder, and execute it. After execution, the required resources will be copied to the electron folder at the same level.

HAP Package Building and Usage

The HAP package project is located in the source directory: src/ohos/app/ folder.

Building an Unsigned HAP Package

Create an electron/libs/arm64-v8a folder in the project, replace the resources in the electron/libs/arm64-v8a directory and the web_engine/src/main/resources/resfile directory, and use DevEco Studio to compile and install.

libc++_shared.so needs to be obtained from /src/ohos_sdk/openharmony/native/llvm/lib/aarch64-linux-ohos. This file appears after the SDK archive is extracted.

Place the Electron project source code (or build artifacts if compilation is needed) into the web_engine/src/main/resources/resfile/resources/app directory.

13

The test files required in the resfile/resources/app directory shown above can be found in the resources directory of the chromium-electron repository. After placing both the .so libraries and resfile in the specified locations, click Build -> Build Hap(s)/APP(s) -> Build Hap(s) to compile and generate an unsigned HAP package, or click the Run button in the upper right corner to launch the application.

14

15

After compilation, the unsigned HAP package will be saved to ohos_hap/electron/build/default/outputs/default/, with the filename electron-default-unsigned.hap.

16

Signing and Permissions

App/Service Signing - DevEco Studio - Huawei HarmonyOS Developer (huawei.com)

Example of permission request email content:

Please apply for permissions based on actual needs. The example content is for reference only.

17

The permission configuration file is located at: ohos_hap\web_engine\src\main\module.json5 in the requestPermissions field. Below are the currently declared permissions and their descriptions.

Permission Name Permission Description Necessity
ohos.permission.SYSTEM_FLOAT_WINDOW Allows the application to use the global floating window capability. Apply as needed
ohos.permission.INTERNET Allows use of the Internet network. Basic
ohos.permission.GET_NETWORK_INFO Allows the application to obtain data network information. Basic
ohos.permission.ACCESS_CERT_MANAGER Allows the application to query certificates and private credentials. Apply as needed
ohos.permission.RUNNING_LOCK Allows the application to acquire a running lock for continuous background execution. Basic
ohos.permission.PRINT Allows the application to access printing framework capabilities. Apply as needed
ohos.permission.PREPARE_APP_TERMINATE Allows the application to perform custom pre-termination actions before closing. Basic
ohos.permission.ACCESS_BIOMETRIC Allows the application to use biometric recognition for identity authentication. Apply as needed
ohos.permission.FILE_ACCESS_PERSIST Allows the application to persist access to file URIs. Basic
ohos.permission.PRIVACY_WINDOW Allows the application to set windows as privacy windows, preventing screenshots and screen recording. Apply as needed
ohos.permission.WINDOW_TOPMOST Allows the window to stay on top. Apply as needed
ohos.permission.READ_PASTEBOARD Allows the application to read the clipboard. Basic
ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY Allows the application to access the Download directory and its subdirectories under public directories. It is recommended to apply together with ohos.permission.FILE_ACCESS_PERSIST. Apply as needed
ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY Allows the application to access the Documents directory and its subdirectories under public directories. It is recommended to apply together with ohos.permission.FILE_ACCESS_PERSIST. Apply as needed
ohos.permission.READ_WRITE_DESKTOP_DIRECTORY Allows the application to access the Desktop directory and its subdirectories under public directories. It is recommended to apply together with ohos.permission.FILE_ACCESS_PERSIST. Apply as needed
ohos.permission.LOCATION Allows the application to obtain device location information. Apply as needed
ohos.permission.APPROXIMATELY_LOCATION Allows the application to obtain approximate device location information. Apply as needed
ohos.permission.LOCATION_IN_BACKGROUND Allows the application to obtain device location information while running in the background. Apply as needed
ohos.permission.MICROPHONE Allows the application to use the microphone. Apply as needed
ohos.permission.CAMERA Allows the application to use the camera. Apply as needed
ohos.permission.ACCESS_BLUETOOTH Allows the application to access Bluetooth and use Bluetooth capabilities such as pairing and connecting to peripheral devices. Apply as needed
ohos.permission.CUSTOM_SCREEN_CAPTURE Allows the application to capture screen content. Apply as needed

Permissions in Electron that require ACL signing include (if the certificate has not been obtained and signing fails, you can temporarily comment out these permissions):

"requestPermissions": [
      {
        "name": "ohos.permission.SYSTEM_FLOAT_WINDOW"
      },
      ...
      {
        "name": "ohos.permission.READ_PASTEBOARD",
        "reason": "$string:access_pasteboard",
      },
      ...
      {
        "name": "ohos.permission.READ_WRITE_DOWNLOAD_DIRECTORY",
        "reason": "$string:reason_download",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when":"always"
        }
      },
      {
        "name": "ohos.permission.READ_WRITE_DOCUMENTS_DIRECTORY",
        "reason": "$string:reason_documents",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when":"always"
        }
      },
      {
        "name": "ohos.permission.READ_WRITE_DESKTOP_DIRECTORY",
        "reason": "$string:reason_desktop",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when":"always"
        }
      }
    ]

Running a Signed HAP Package

After obtaining the certificate, configure it in DevEco Studio.

18

After configuration, click the Run button in the upper right corner to run.

19

Alternatively,

Install the HAP package via command line:

hdc app install <signed_hap_package_path>
# e.g: hdc app install pc_entry-default-signed.hap

20

Paths in HarmonyOS

Application Sandbox Directory

Mapping Between Application Sandbox Paths and Actual Physical Paths

When reading and writing files in the application sandbox path, the actual read/write operations are performed on the real physical paths through path mapping. The correspondence between sandbox paths and physical paths is shown in the table below.

Where is currently fixed at 100.

Application Sandbox Path Physical Path Description
/data/storage/el1/bundle /data/app/el1/bundle/public/<PACKAGENAME> Application installation package directory
/data/storage/el1/base /data/app/el1/<USERID>/base/<PACKAGENAME> Application el1-level encrypted data directory
/data/storage/el2/base /data/app/el2/<USERID>/base/<PACKAGENAME> Application el2-level encrypted data directory
/data/storage/el1/database /data/app/el1/<USERID>/database/<PACKAGENAME> Application el1-level encrypted database directory
/data/storage/el2/database /data/app/el2/<USERID>/database/<PACKAGENAME> Application el2-level encrypted database directory

User data must be stored under the /data/storage/el2/base path. The default --user-data-dir for Electron is /data/storage/el2/base/files.

21

To view user data, use the system file manager as shown below:

22

23

Customizing Your HarmonyOS Application

Replacing the Application Name

Location: ohos_hap\electron\src\main\resources\zh_CN\element\string.json

Replace the value of the EntryAbility_label field in the file.

24

Replacing the Icon

Location: ohos_hap\AppScope\resources\base\media

25

Resource Replacement

Since HarmonyOS does not currently have a compilation environment, if the original project requires compilation (e.g., TypeScript needs to be compiled to JavaScript before loading), you need to place the compiled JavaScript files in the project at web_engine/src/main/resources/resfile/resources/app.

Issues you may encounter with open-source third-party libraries:

  1. If an npm library uses addons (i.e., C++ libraries called by JavaScript), it cannot function properly without HarmonyOS platform adaptation. -- Refer to the sqlite3 compilation adaptation solution for guidance. Note: compiling .node requires a minimum C++ version of 17.

  2. If an npm library uses platform-checking APIs such as process.platform or os.type(), it cannot function properly without HarmonyOS platform adaptation, because process.platform returns "openharmony", which third-party libraries may not recognize. -- Code modifications are needed to adapt for the OH platform.

  3. If an npm library contains binary files (e.g., libraries like esbuild), it cannot function properly. -- Linux machines require root privileges; for new PCs, use the HNP solution.

Multi-Instance Configuration

If the application does not need multi-instance support, remove the "multiAppMode" configuration as shown below:

Electron HarmonyOS Feature Notes

Windows

Specifying the Initial Window Size

If the application needs to specify the window size at startup, modify the file electron/src/main/module.json5 in the project and add the metadata property inside abilities as shown below. If centering is not needed, only width and height need to be specified.

{
  "module": {
    "name": "pc_entry",
    "type": "entry",
    "srcEntry": "./ets/Application/AbilityStage.ets",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "2in1"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:app_icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:app_icon",
        "startWindowBackground": "$color:start_window_background",
        "launchType": "specified",
        "removeMissionAfterTerminate": true,
        "exported": true,
        ***************** Add here *****************
        "metadata": [
            {
                "name": "ohos.ability.window.height",
                "value": "800"
            },
            {
                "name": "ohos.ability.window.width",
                "value": "800",
            },
            {
                "name": "ohos.ability.window.left",
                "value": "center"
            },
            {
                "name": "ohos.ability.window.top",
                "value": "center",
            }
        ],
        *********************************************
        "skills": [
          {
            "entities": [
              "entity.system.home",
              "entity.system.browsable"
            ],
            "actions": [
              "action.system.home",
              "ohos.want.action.viewData"
            ],
            "uris": []
          }
        ]
      }
    ]
  }
}

Window Show/Hide

Due to OH system limitations, window show/hide is tightly bound to the application tray. Therefore, before launching the application, a tray must be created first to ensure proper window creation.

const { app, Tray } = require('electron');
const path = require('path');
app.whenReady().then(() => {
    let tray = new Tray(path.join(__dirname, 'tray_icon.png'));
    ...
})

If the application does not need a tray or hidden windows, modify ohos_hap/web_engine/src/main/ets/adapter/AppWindowAdapter.ets and comment out the processMode and startupVisibility properties.

...
    const options: StartOptions = {
      // processMode: contextConstant.ProcessMode.ATTACH_TO_STATUS_BAR_ITEM,
      // startupVisibility: param.show ? contextConstant.StartupVisibility.STARTUP_SHOW : contextConstant.StartupVisibility.STARTUP_HIDE,
      windowLeft: param.left - leftBorder,
      windowTop: param.top - topBorder,
      windowWidth: param.width + leftBorder + leftBorder,
      windowHeight: param.height + leftBorder + topBorder
    }
...

Window Control Buttons

The current window control buttons (close, minimize, maximize) behave consistently with other platforms. When creating windows other than the first window, if the window has a frame (frame property is true), the control buttons are visible. If the window is frameless, the control buttons are not displayed. Sub-windows and floating windows have no control buttons.

If the application needs to display control buttons when creating frameless windows, you can modify the initial state in WebAbility.ets to adjust the initial display state of the control buttons when creating windows. See the figure below:

30

New APIs

Floating Window

A new windowInfo property has been added to BrowserWindow. It is an Object with a single property type (type: String), which can be one of mainWindow, subWindow, or floatWindow. The default value is mainWindow.

let w = new BrowserWindow({
    windowInfo: {
       // type can be mainWindow, subWindow, or floatWindow
       type: 'floatWindow'
    },
    parent: mainWindow;
    x:100,
    y:100,
    width:800,
    height: 600,
    show: true,
    // You can set background color and opacity
    // The priority order for opacity is: transparent, opacity, and the alpha value in backgroundColor
    transparent: true, // Fully transparent
    opacity: 0.5, // Semi-transparent
    backgroundColor: '#660000ee' // Semi-transparent blue
});
w.loadURL("https://www.baidu.com");

systemPreferences Module

Native API Implementation
systemPreferences.getMediaAccessStatus(mediaType)
  • mediaType string - Can be microphone, camera, or screen.

Returns string - The value can be not-determined, granted, denied, restricted, or unknown.

Gets the status of microphone, camera, or screen capture permissions. On the OHOS platform, only granted and denied states are currently returned.

systemPreferences.askForMediaAccess(mediaType)
  • mediaType string - The type of media being requested, can be microphone or camera.

Returns Promise<boolean> - Resolves true if the user grants or has already granted permission. The system authorization dialog will only appear once. If permission has already been requested or was denied, it must be manually changed in Settings -> Privacy & Security. No prompt will appear, and the promise will return the existing permission status.

New Permission Request APIs
systemPreferences.requestSystemPermission(permission)
  • permission string - One of the following values:

    location, camera, microphone, screen-capture, user-download-dir, user-desktop-dir, user-document-dir, bluetooth, pasteboard

Returns Promise<boolean> - Resolves true if the user grants or has already granted permission. The system authorization dialog will only appear once. If permission has already been requested or was denied, it must be manually changed in Settings -> Privacy & Security. No prompt will appear, and the promise will return the existing permission status.

systemPreferences.requestDirectoryPermission(path)
  • path string | null

Returns Promise<boolean> - Resolves true if the user grants or has already granted permission. When path is null, permissions for the user's Download, Desktop, and Documents directories will be requested simultaneously. The promise resolves true if any one of the three directories is authorized. The system authorization dialog will only appear once. If permission has already been requested or was denied, it must be manually changed in Settings -> Privacy & Security. No prompt will appear.

New API to Open Application Info Page in System Settings
systemPreferences.openApplicationInfoEntry()

Opens "System Settings" and navigates to the application information page.

systemPreferences.fileAccessPersist(paths)

  • paths string[] - File or directory paths that need persistent authorization.

Grants persistent authorization for the specified files or directories.

Debugging the Application

Renderer Process

The most widely used tool for debugging a specific renderer process is Chromium's Developer Tools. It can access all renderer processes, including instances of BrowserWindow, BrowserView, and WebView. You can programmatically open them by calling the openDevTools() API on the webContents of a BrowserWindow:

const { BrowserWindow } = require('electron')

const win = new BrowserWindow()
win.webContents.openDevTools()

Main Process

Use the following command-line switches to debug Electron's main process:

--inspect=[port]

Electron will listen for V8 debug protocol messages on the specified port. An external debugger needs to connect to this port. The default port is 9229 and can be changed to another port. This guide uses port 9229 as an example.

Below are the steps to debug the main process of an Electron application on OHOS using Chrome browser on Windows, with port 9229:

  1. Enable the Electron command-line switch. In the file ohos_hap/web_engine/src/main/ets/components/WebWindow.ets, add the inspect parameter with the value '--inspect=9229', add the variable to vec_args, and rebuild and install.
// ohos_hap/web_engine/src/main/ets/components/WebWindow.ets
...
this.xComponent.attribute
      .backgroundColor(Color.Transparent)
      .onLoad(() => {
        let resDir = '--bundle-installation-dir=' + getContext().resourceDir;
        // Create a new variable here
        let inspect = '--inspect=9229';
        // And add it to vec_args
        let vec_args = ['--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', resDir, inspect];
        this.electronRelaunchArgs.forEach((arg: string) => {
          vec_args.push(arg);
        })
        let nativeContext = JsBindingUtils.getNativeContext(ContextType.kMainProcess);
        nativeContext.runBrowser(vec_args);
      })
...
  1. Configure port forwarding. In the command line, execute the port forwarding command. The result is shown in the figure.
hdc fport tcp:9229 tcp:9229

26

  1. Visit the following page to connect to Chrome. The result is shown in the figure.
chrome://inspect
  1. On the inspect page, click the Configure... button.

27

  1. Click the Configure... button. In the popup menu, ensure localhost:9229 is present. If not, add it.

28

  1. After configuration, launch the Electron application on the device. The Chrome browser on Windows will display debuggable page options (this may take a moment). Click inspect to remotely debug the Electron main process.

29

When using command-line parameters, especially those related to security, exercise caution to ensure system security and stability. Risk parameters include but are not limited to the following:

  • --remote-debugging-port

    • Purpose: Enables remote debugging and specifies the debugging port number.
    • Precautions: Ensure the debugging port is only open in trusted network environments. Avoid exposing it on public networks to prevent malicious attacks.
  • --disable-web-security

    • Purpose: Disables the same-origin policy, allowing cross-origin requests.
    • Precautions: Use only in development or testing environments. Never enable in production to prevent potential security vulnerabilities.
  • --no-sandbox

    • Purpose: Disables the sandbox mechanism, reducing process isolation protection.
    • Precautions: Ensure the environment is secure when using this option to prevent malware from exploiting this configuration.
  • --ignore-certificate-errors

    • Purpose: Ignores certificate errors, allowing self-signed certificates.
    • Precautions: Use only in trusted environments. Avoid enabling in production to prevent man-in-the-middle attacks.
  • --gpu-launcher

    • Purpose: Specifies the launcher command for the GPU process.
    • Precautions: Primarily used for advanced debugging or specific GPU configurations. Understand its specific usage and potential impact.
  • --inspect and --inspect-brk

    • Purpose: Starts the debug server, supporting background debugging and pause on startup.
    • Precautions: Avoid using in production environments to ensure debugging security.
  • --host-rules

    • Purpose: Configures routing or redirection of network requests.
    • Precautions: Configure the syntax correctly to ensure network request security and compliance.

Summary: These parameters are very useful during development and debugging, but should be used with caution. Ensure the environment is secure and avoid enabling parameters that may weaken security in production environments.

Publishing Issues

If you encounter the following error when publishing an Electron application to the PC App Store, check whether the application permission declarations include permissions that are only for 2-in-1 devices.

If they do, here are two solutions:

  1. For applications that do not need to be published on pad: Remove the pad_entry module.
  2. For applications that need to be published on both pad and PC: Move the permissions that are only for 2-in-1 devices from the web_engine module to the pc_entry module.

Troubleshooting

For crash issues, please provide the corresponding daily build version (e.g., 20241229.1) or the code commit ID (can be viewed using git log, e.g., 162a67b2a0a2a6f36e47d4e6c10cb780dd8c99b4) and crash stack trace information (click the save button shown in the figure below in DevEco Studio to save the information locally).

31

Secure Shield Mode

Secure Shield Mode is a system-level security protection solution designed for users with high security requirements. This mode significantly enhances system security by enforcing strict functional restrictions, effectively preventing various threats targeting remote attack surfaces. Under Secure Shield Mode, Electron has additional functional restrictions, and developers need to evaluate application usability in this mode.

Enabling Secure Shield Mode

To enable Secure Shield Mode, follow these steps:

  1. Go to System Settings
  2. Select "Privacy & Security"
  3. Click "Secure Shield Mode" and enable it

Functional Restrictions in Secure Shield Mode

To reduce the attack risk for Electron, Secure Shield Mode enforces the following key security restrictions:

  • Completely disables Just-In-Time (JIT) compilation, including for applications that have obtained ACL permissions
  • Suspends WebAssembly support (in the current version, WebAssembly depends on JIT functionality)

Application Compatibility Assessment Guide

When running applications in Secure Shield Mode, the following compatibility checks are recommended:

  1. JavaScript Performance Assessment:

    • Test the application's runtime efficiency in the restricted environment
    • Optimize potential performance bottlenecks
  2. WebAssembly Compatibility Check:

    • Static code analysis: Check the project for WebAssembly-related API calls and third-party library Wasm dependencies.
    • Runtime verification: Execute full-functionality testing in Secure Shield Mode.

Reference Documentation: