Skip to main content

Packaging the Apps

Now that you explored each app in more detail and learned what a real-world Actyx solution could look like, let's discuss the different packaging options you now have. There are a lot of tools that focus solely on the packaging of HTML, CSS and Javascript code into native packages, for a list of tools we can recommend, please check out the respective packaging guides.

Order Management App#

The Order Management App is a mobile app which is meant to run on a worker's tablet or mobile phone. We therefore need to package the app as an Android App Package, or short APK. In the following, we will show and go through one example of how you could package an app so that you can run it on an Android device, using the cross-platform native runtime for web apps, capacitor.


We are using the node package manager (npm) in this example, so if you want to follow along, we recommend you do too!


In order to package an app for Android, you need to set up an Android development environment, which includes downloading Android Studio and the Java Development Kit (JDK).

Packaging an apk#

  1. The first thing you need to do, is navigate into the app folder called order-management. Once in there, run npm run ui:order-management:build and wait for it to be finished. This command has now created a new folder release containing the built app.

  2. Next, please navigate back out of the order-management folder into the root of the directory. From there, please install capacitor and the capacitor CLI:

npm install @capacitor/core @capacitor/cli
  1. Once that is finished, you need to add a config file for capacitor which you can conveniently do using the npx command:
npx cap init

This command will prompt you to enter the name of your app (e.g. Order Management App) and the app ID (e.g. com.actyx.orderManagement).

Naming conventions

There are a few rules that need to be followed regarding the app ID. It must have at least two segments (one or more dots), each segment must start with a letter, all characters must be alphanumeric or an underscore [a-zA-Z0-9_].

  1. When you are finished, open the newly created capacitor.config.json in the project root folder and change the field webDir to the name of the build directory that you created earlier src/order-management/release.

You are now all set for the final part of this packaging guide.

  1. With the command npx cap add android you add the needed gradle and android directories to the project and with the command npx cap open android which will open up Android Studio for you.

  2. Now, inside Android studio navigate to app > res > xml and add a file called network_security_config.xml. Paste the following xml code into the file:


In the Android studio Project/Android view, the folder res is displayed as resources.

<?xml version="1.0" encoding="utf-8"?>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">localhost</domain>
  1. Now the only thing left is to tell your Android manifest about the newly created network_security_config.xml file, so please add the highlighted line below to your AndroidManifest.xml in app/src/main:
  1. The last thing you need to to is to navigate to Build > Build Bundle(s) / APK(s) > Build APK(s) and wait for the APK to be finished being built.

Depending on your Android studio setup you may encounter a few errors here. Following these steps should do the trick though:

  1. install additional Android platform (29) using the SDK manager
  2. Project > Reload from Disk
  3. File > Sync Project with Gradle Files
  4. File > Invalidate caches and restart

If you still encounter issues with Android studio, please refer to the Android Developer Documentation, this is probably not a problem related to Actyx.

You have now turned your React app into an Android apk ๐ŸŽ‰.

Dashboard App#

In our scenario, the dashboard app displays the order status. In the real-world factory, this dashboard would be a TV, powered by some industry PC, probably running Windows. Also here, you have multiple different packaging possibilities such as Cordova or React-Native. In this example, we will show you how you could do it using Electron.

  1. The first thing you need to do in order to add electron to your react app, you need to add a few dependencies to the root directory, so please type in the following commands into your terminal:
npm install concurrently
npm install wait-on
npm install electron
npm install --save-dev @electron-forge/cli
  1. Now that you have installed all necessary dependencies, please open up package.json inside the root directory and change the field main like the following.
"main": "main.js",
  1. Next, create a main.js inside the root directory and paste in the following code:
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
// and load localhost:1234 (or the URL on which the react app is running)
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// 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.whenReady().then(() => {
app.on('activate', function () {
// On macOS 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 (BrowserWindow.getAllWindows().length === 0) createWindow()
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
  1. Now, inside the package.json file, add a command to run the electron app inside the scripts object:
"electron-react": "concurrently \"BROWSER=none npm ui:dashboard:start\" \"wait-on http://localhost:1234 && electron .\""
  1. Finally, to run the app on your machine, simply run npm run electron-react. A new app window should open and load your app.
  1. Once that is finished, simply run npm run make and your application will be packaged into a native app package.

Done! ๐ŸŽ‰

Wago Connector#


Being a headless app, we will turn the Wago Connector App into a Docker image that can be run on all sorts of headless devices. In order to create the Docker image, you need to have Docker installed on your machine. For more information, visit the Docker documentation.

Creating the image#

A docker image is created using the docker build command. Additionally, you need a Dockerfile, and a Docker compose file. These file essentially gives instructions to Docker how the image should be built. We have created these files for you, you can find them inside the wago-connector folder.

  1. To build the Docker image, you now simply have to run the following npm command:
npm run node:wago-connector:docker:build-amd64

Alternatively, you can also use the docker build command:

docker build -t wago-connector-amd64 -f src/wago-connector/Dockerfile .
  1. To check whether the image was successfully built, type in docker image ls into the terminal โ€” you should now see the image appear in the terminal window.
[19:39][~:]$ docker image ls
wago-connector-amd64 latest fe966abbfedc 3 days ago 109MB
  1. If you see the image wago-connector-amd64 in your terminal window, you can now run the docker image. One thing to note is that Docker has a separate network. However, in order for the image to talk to Actyx (and in particular with the Event Service on port 4243), you need to pass this information as an environment variable so that Docker knows, where to look for the required port:
docker run -e AX_STORE_URI="ws://host.docker.internal:4243/store_api" wago-connector-amd64

Docker does not support host.docker.internal on Linux. Therefore, please run the image with network=host as an argument to the docker run command.

If everything worked, you should now see something similar to this:

[19:44][~:]$ docker run -e AX_STORE_URI="ws://host.docker.internal:4243/store_api" wago-connector-amd64
started Wago Connector plc ip:
machine state { stateType: 'disabled', name: 'Wago Connector' }
Need help?

If you run into problems or want to give feedback, you are welcome to join our Discord chat, visit our community forum, raise an issue in the GitHub repo or write us an e-mail to [email protected].