Desktop Native Overview
A desktop native application is an application that can be installed and run locally on a desktop computer. The desktop native application is a web application running in an electron environment with the ability to integrate with the desktop environment and communicate and work with the desktop resources as the application developer permits. Access to the desktop environment is managed by poly-filling existing Volt MX apis or adding your own using Native Function Interfaces. As is typically the case with Volt MX built applications, the desktop native applications can be client-server based and interface with the Volt MX Foundry server using services and providers specific to your application needs. Using Volt MX, desktop native applications can be created for Mac and Windows computers.
Note: The electron JS based desktop native build doesn’t support “free-form” architecture applications. It supports only MVC architecture applications.
Desktop Native Applications
Creating Desktop Native Applications
To create a desktop native application in Volt MX, create a project and choose Native App and then select Desktop for the target device size. When the project is created, the forms for the application will be under the Responsive Web/Desktop.
When a form is selected, you can choose from the different platforms to show a device shell specific to the platform.
Widgets from the widget libraries can be used to layout the UI you need for your application look and feel. Each widget has a set of properties that can be used configure the widget for the appearance and capabilities you’d like.
Window Events and Properties
In Volt MX, a form is used to represent the window of your desktop native application. A desktop window has a set of properties for managing its size and state. These are represented in the Form tab of the Volt MX properties when the form is selected on the canvas or in the project explorer. These properties determine if the window can be minimized, maximized, restored or closed and can be set differently for each platform on which your application will run.
In addition to properties, there are a set of actions your application can take when window events are triggered. These are accessible in the Action tab. In addition to general actions, there are a set specific to the desktop window state.
These properties and actions are added to your desktop native application through the Volt MX Form NFI which is a default NFI. Default NFIs are automatically added to your application.
Adding Menus and Tray icons to your application
Windows in desktop native application typically have menu bars with actions to perform specific to your application. In Volt MX, these menus are created, modified and deleted using apis and passing menu templates to define the menus and their capabilities. The apis are defined as follows:
- voltmx.application.createDesktopAppMenu(menuTemplate)
- voltmx.application.deleteDesktopAppMenu()
- voltmx.application.insertDesktopAppMenuItem(menuTemplate, id, position) id can be the menu id or label; position is 'before' or 'after'
- voltmx.application.deleteDesktopAppMenuItem(menuid)
menuid can be the id or label - voltmx.application.createDesktopTrayItem(iconPath, menuTemplate, toolTip)
- voltmx.application.deleteDesktopTrayItem()
These apis are added to your desktop native application through the Volt MXA pplication NFI which is a default NFI. Default NFIs are automatically added to your application.
The template definition for menus of desktop native applications follows the protocol for electron menu definition: See here
Application Security
Applications that you build for Desktop Native platforms are electron applications. They are generated configured for Context Isolation and Process Sandboxing. With Context Isolation, electron code and preload scripts are run in a separate javascript context from the Volt MX forms.
There are typically two types of processes with electron applications; the main process and renderer processes. The Volt MX forms run in renderer processes. Process Sandboxing is used to limit the resources of your local computer the renderer processes have access to. Resources of the local computer can be accessed from the main process, but not directly by the renderer processes.
In order for the renderer processes to be able to communicate with the main process to access local resources, they communicate across the context bridge. The main process will expose to the renderer processes only the apis it permits the renderer processes to call through the context bridge. Within Volt MX this set of apis and restrictions of resources are managed through Native Function Interfaces (NFIs).
Desktop Native NFIs
A Native Function Interface (NFI) is an extension to your application to invoke additional modules to add features. For desktop native applications NFIs enable you to call node modules and access your local desktop resources.
Volt MX provides several NFIs that you can add to your desktop native application and you can build your own.
Note: To see the default NFIs reflected in Iris, you need to build the application at least once in the desktop native environment.
The NFIs provided are the following:
VoltMXApplication | Provides apis to manage window menus and tray icons |
VoltMXDB | Provide apis for local desktop DB manipulation using sqlite |
VoltMXForm | Provides apis for window state management such as maximized, minimized, restored |
VoltMXIO | Provides apis for file IO on the local desktop |
Desktop native NFIs are zip files containing a number of files. All of these files must be zipped in a folder named the same as the NFI. With the exception of the api file, the other files will be generated for you when using the Create option in the popup for managing NFIs.
api file (.js) | This is the javascript file containing the functions you want to call from your desktop native application |
wrapper file (.js) | The wrapper file’s primary responsibility is to assign the api define in your preload file into the namespace for the voltmx application to address it. |
preload file (.js) | The preload file defines the apis and parameters to be passed across the bridge between the renderer and main processes. |
handler file (.js) | The handler file receives the calls in the main process and invokes the apis from the api file. |
bootstrap file (.js) | The bootstrap file defines the channel constants to identify the requests passed across the bridge. |
intellisense directory with a tern.json file | The tern.json file is used for intellisense of the apis. |
metadata.properties file | The metadata.properties file identifies the metadata of the NFI so Volt MX code generation knows what to include in the application. |
Included in the metadata.properties file are a set of properties.
moduleName= < NFI module name > | The name of the NFI. e.g. VoltMXApplication |
moduleVersion= < module version > | The version of the NFI module; e.g. 1.0.0 |
moduleDescription= < some text > | A description of the purpose of the NFI and the categories of apis provided. |
os=Desktop | Must be ‘Desktop’ |
sdkVersion= < a version > | Typically the version of the environment on which it’s supported. For desktop native this will be same as the module version. |
apiNamespace= < namespace for the apis > | Namespace to categorize the apis. e.g. com.sample.io |
wrapperFile= < name of wrapper js file > | |
handlerFile= < name of handler js file > | |
preloadFile= < name of preload js file > | |
nodeModules= < list of node dependencies > | Optional. Comma separated list of node module dependencies and their version |
To add NFIs to your desktop native application, from the menu select Edit -> Manage Native Function Apis. Select the Desktop tab. From this popup you can import an NFI, create a new NFI, or delete an existing NFI from your application.
All enabled packages under the Desktop tab will get added to the desktop native application.
Import NFI
When choosing to import an NFI, select the zip file containing the NFI. The metadata.properties file will identify the information related to the NFI and it’ll get added to the list.
Create NFI
When choosing the Create button to create an NFI, the following popup is displayed.
Select the js file that contains the api you’d like your application to be able to call.
When the js file is selected, the table will fill-in with exported functions from the js file and their parameter names. If the application doesn’t need a response back from the api, you can change it to Async. If the application needs a response back, make it Sync. If there is a function in the javascript file you do not want to include as an api, you can choose Disable to exclude it from the apis that can be called from your application.
If there are additional javascript files needed by your application (not including dependent node modules), select the folder containing the javascript files in the Additional JS (optional) field. Note all files in the hierarchy of the folder will be copied to the NFI.
Name the NFI. Give the NFI a version. Enter a namespace for the api. If there are node module dependencies select a .json file in the Add node dependencies (.json) field. The json will be parsed and the ‘dependencies’ element in the json will be included as node module dependencies for your application.
For example:
When you click the Create button an NFI zip file with the NFI name is created and saved to the < workspace >/desktopNativeNFIs directory.
You may unzip an NFI and enhance the preload, handlers and wrapper javascript files. The preload and wrapper cannot contain references to node modules. The handler can. For information regarding the type of parameters that can be passed across the bridge (defined in the preload file), see the electron documentation regarding the contextBridge.
NFI Apis
Volt MX Form
voltmx.form.enableMaximizable(enable) | Enable/disable window maximize button |
voltmx.form.enableMinimizable(enable) | Enable/disable window minimize button |
voltmx.form.enableRestorable(enable) | Enable/disable window restore button |
voltmx.form.enableClosable(enable) | Enable/disable window close |
voltmx.form.setTitle(aTitle) | Sets the window title |
Volt MX Application
voltmx.application.createDesktopAppMenu(menuTemplate) | Create and set the window menubar from the menu template. This will overwrite all default options. |
voltmx.application.deleteDesktopAppMenu() | Delete the window menubar. This will remove all default options as well. |
voltmx.application.insertDesktopAppMenuItem(menuTemplate, id, position) | Insert a menu or menuitem in the window menubar.id is the id or label of a menuitem relative to which this menu template will be placed.Position is ‘before’ or ‘after’ |
voltmx.application.deleteDesktopAppMenuItem(menuid) | Delete the menu item from the menubar having the id or label |
voltmx.application.createDesktopTrayItem(iconPath, menuTemplate, toolTip) | Add an application tray item for the application. See here for supported image formats. |
voltmx.application.deleteDesktopTrayItem() | Delete the application from the tray |
voltmxapplication.application.addContextMenuItems(contextMenu) | Adds a context menu using the specified contextMenu template |
voltmxapplication.application.removeContextMenu() | Deletes the entire context menu |
voltmxapplication.application.removeContextMenuItems(label) | Deletes a specific context menu item identified by the provided ID or label |
Note : Any menu item changes enacted by these APIs will not be persisted beyond the app launch during which they were invoked.
Volt MX IO
voltmx.io.FileSystem.copyBundledRawFileTo() | Returns Boolean value,if failure throws appropriate exception, See VoltMX voltmx.io.documentation |
voltmx.io.FileSystem.getDataDirectoryPath() | Return the directory where application data is stored. |
new voltmx.io.File(filePath).createFile() | Create a file having the path and name of the filePath |
new voltmx.io.File(filePath).copyTo(targetPath, newName) | Copy the file or directory |
new voltmx.io.File(filePath).createDirectory() | Create a directory having the filePath name and/or hierarchy |
new voltmx.io.File(filePath).exists() | Return a boolean if the filePath exists |
new voltmx.io.File(filePath).getFileList() | Return an array of the files in the directory |
new voltmx.io.File(filePath).isDirectory() | Return a Boolean if the filePath is a directory |
new voltmx.io.File(filePath).isFile() | Return a boolean if the filePath is a file |
new voltmx.io.File(filePath).moveTo(targetPath, newName) | Move the file or directory |
new voltmx.io.File(filePath).read() | Read the file content as a buffer |
new voltmx.io.File(filePath).readAsText() | Read the file content as a string. |
new voltmx.io.File(filePath).remove(deleteRecursive) | Remove the file or directory.deleteRecursive is a boolean |
new voltmx.io.File(filePath).rename(newName) | Rename the file |
new voltmx.io.File(filePath).write(data, append) | Write the string or buffer to the file |
Volt MX DB
voltmx.db.changeVersion(dbaseObjectId, oldVersion, newVersion, transactionCallback, errorCallback, successCallback) | Change the version of the database. See VoltMX voltmx.db documentation |
voltmx.db.executeSql(transactionId, sqlStatement, args, successCallback, errorCallback) | Execute an SQL statement in the transaction. See VoltMX voltmx.db documentation |
voltmx.db.openDatabase(dbName, version, displayName, estimatedSize) | Open the database and return the dbaseObjectId.
See VoltMX voltmx.db documentation Note: |
voltmx.db.sqlResultsetRowItem(transactionId, sqlResultSet, index) | Return the indexed item from the result set. See VoltMX voltmx.db documentation |
voltmx.db.readTransaction(dbaseObjectId, transactionCallback, transactionErrorCallback, successCallback) | Execute a transaction to read records from the database. See VoltMX voltmx.db documentation | voltmx.db.transaction(dbaseObjectId, transactionCallback, transactionErrorCallback, successCallback) | Execute a transaction to read or write to the database. See VoltMX voltmx.db documentation |
Mandatory Steps in Building an Application for Desktop Native:
-
Desktop Native plugin
- Build the project at least once to download the Desktop Native plugin.
-
Select the desired Database configuration.
-
If SQLite Database is selected, Enable OfflineObjects VoltMXDB NFI
- Navigate to Edit -> Open Manage Native Function API(s).
- Select the Desktop tab.
- Enable VoltMXDB.
Note: Version 2.0.0 of VoltMXDB includes all the Offline Object updates.
-
Rebuild the Application to apply the changes.
Note: Unlike IndexedDB, where the database can be viewed directly in Developer Tools under the Application tab, SQLite database file for Desktop Native resides in the system's user app data folder for both Windows and macOS.
- Windows :
<System Drive>\Users\<User>\AppData\Roaming\<YourApp>\data\sync.db
- macOS :
/Users/<User>/Library/Application Support/<YourApp>/data/sync.db
- Windows :
Desktop Native(Electron Apps)
IndexedDB is the database that supports offline objects.
Building a Desktop Native Application
Build Prerequisites
To build and package application,
- Ensure to have Node.js version 16.4.0 or higher installed. You can download it from the here
- Git is required for version control. Install it from here
- For Windows Application : The Wix Toolset must be installed in your Windows environment. To install the Wix Toolset, see here
Building
Once you’ve created the forms of your application, added widgets, setup properties and actions and you’re ready to build and run, choose Build -> Build Native Local.
Choose Generate Native App from the Post Build Action dropdown and in the Platform and Channels table, under the DESKTOP channel choose the option for the (Local Machine) app or Installer you’d like to build. The app and Installer are listed for the platform on which your Volt MX is running. Due to platform module dependencies, you can only build the app for the same OS on which Volt MX is running. Note: The app will be generated to run across architectures for the same OS.
When the build is completed, the generated app will be in the
Icons for the application and application signing can be configured in the Project -> Settings under the Native section for MacOS or Windows.
Project Settings
Desktop Native platforms support two databases, namely IndexedDB and SQLite.
To switch the database, select the appropriate option from Project Settings -> Native -> Desktop
There are some platform specific project settings for the macOS and Windows native platforms. To view or update these settings, go to Project Settings -> Native -> Desktop and choose either macOS or Windows.
Windows Application Settings
The screen shot below shows the Application UI tab of the Windows application settings.
- Display Name – The name of your application.
- Description – A short description of your application.
- Package Name – A short name used when packaging you application.
- Package Display Name – A human readable name for your package. Usually the same as the Display Name
- Publisher Name – The (short) name of your company.
- Publisher Display Name – A possibly longer, more descriptive name of your company.
- Version – The version of your application
- Application icon (.ico) – An icon file to be used for your application. The file is picked using a file picker. The icon you choose will be copied into your project when the settings are saved. It is recommended that you use a 256x256 px icon.
The next screen shot shows the Build Local tab of the Windows settings
-
Windows signing certificate – A valid signing certificate for your Windows application. This file is chosen using a file picker. The certificate file is copied into your project when the settings are saved.
-
Certificate password – The password associated with your signing certificate.
MacOS Application Settings
The following screen shot shows the MacOS specific project settings.
- Bundle Identifier – The bundle ID for your application.
- Bundle Version – The version of your application
- Enable App Notarization – Enable the checkbox to Notarize your app
- Developer ID – Your Apple Developer ID.
- Development Team ID – The Apple Developer Team to which you belong.
- App Password – An application password generated for your app on the Apple Developer site.
- MacOS icon set (.icns) – An icon set file containing all the required icon formats for your MacOS application. The icon set format allows you to embed all needed sizes into a single file.
NOTE: For signing and notarizing MacOS applications, we use the process documented in the following article: here
We use the app-specific password option for notarizing your application. To learn about app-specific passwords and how to generate them, see here
Offline Objects
Supported Databases
DesktopNative Support
- IndexedDB (Default)
- SQLite
NOTE : To switch the database, select the appropriate option from Project Settings -> Native -> Desktop
Supported Architecture
Windows
- Installer Type: .msi
- Supported Versions: Windows 10 and later
- Architecture: x86 (32-bit), x64 (64-bit)
Mac
- Installer Type: .dmg
- Architecture: arm, x64
NOTE : The build-system architecture will determine what target devices can run the application. For example, an app built on an ARM chip will only work on a system with an ARM chip.
App Uninstallation
MacOS
An uninstaller app named "Uninstall_<appname>"
will be created in the application's installation directory. You can use this app to uninstall the application.
Windows
An uninstaller shortcut named "Uninstall_<appname>"
will be created in the application's installation directory. This shortcut can be used to uninstall the application.
Note : This process will delete the AppData folder under Users directory and all contents within the installation directory but the empty installation directory itself will need to be manually removed.
Modifying Native Apps
After your app is built, there may be scenarios where you want to modify your application, in particular, the startup file, main.js. When an application is generated, main.js will reside in the
TroubleShooting
-
When building and/or running an application on a Mac, a terminal window opens and does not exit. You can configure your environment so the terminal windows are automatically exited. See here
-
When building a desktop native application on a Mac, you may get a build failure error due to the temp/
or nativeApps/ directory not able to be deleted. This may occur due to the terminal windows opened during build and/or run of the application, remaining open. Close them and retry the build. Alternatively you can manually delete the directory under temp and/or nativeApps and build again. -
There was an electron-forge security vulnerability due to the http-cache-semantics package that was indirectly included. Electron-forge is a node development time dependency. If you are concerned, the vulnerability can be removed by adding http-cache-semantics 1.1.1 to package.json devDependencies (in
/bundles/com.kony.desktopnative directory). If you modify the package.json in the com.kony.desktopnative directory, be aware, it will get overwritten when you upgrade to a newer version of the com.kony.desktopnative plugin.
Debugging your Desktop Native Application
Debugging the renderer process
If you are having issues with your desktop native generated application and would like to debug it, the renderer process can be debugged by building the app in Debug mode (in Build Native Local popup) and running the application. When the window opens, there should be a View menu with Open Developer Tools and Reload items. When you choose Open Developer Tools, you can place your breakpoints in the javascript code and reload the application.
Debugging the main process
If the window does not open at all or you need to debug the main process for another reason, you can do so by modifying the run.bat or run.sh and adding the –inspect-brk=
node_modules.bin\electron . --inspect-brk=9292
You’ll also need to open a chrome browser and navigate to chrome://inspect. In the Configure section of the inspect page, define the port you wish to debug on (in our example above it would be localhost:9292).
Then run run.bat or run.sh and you will be able to debug the main process.
Notes
- Ensure that you use 'voltmx.ui.Alert’ API instead of native alerts for consistent behavior.
- Do not use a for loop to run CRUD operations, if you use please use promises from application code.
-
ScreenRecorder apis will not function without the use of electron’s desktopCapturer. See here To add this capability to the desktop native application an NFI would need to be created with apis to access desktopCapturer from the main process.
-
For GeoLocation, you will need to alter the main.js of the application to add your Google API key. See the GOOGLE_API_KEY section of here
-
Volt MX Camera widget is not supported for DesktopNative apps at this time. However the camera apis do function.
-
Protected mode has no affect for desktop native apps at this time.
- When running a desktop native app on a MacOS platform during development, the first window menu entry will say ‘Electron’ rather than the project name. However when the installer is built for the app, the menu will correctly be the project name for the installed app. The menu will be correct on Windows during development and in the installed app.
Known Issues
- Error reporting in Iris needs improvements for notarization flow
- For windows, project settings under General -> Application UI settings are not being applied during app package generation