Difference between revisions of "Standalone Executables on Windows"
Yvonne.milne (Talk | contribs) (→Deploying Standalone Executables) |
Yvonne.milne (Talk | contribs) (→Deploying Standalone Executables) |
||
Line 467: | Line 467: | ||
If your application is built in Python, there is a python3 directory included which contains the python modules you have installed with pip. | If your application is built in Python, there is a python3 directory included which contains the python modules you have installed with pip. | ||
+ | |||
+ | ==Pre-9.5 Deployment== | ||
To deploy, install the whole standalone application directory, e.g for the example_timeclock App the directory is:<pre>drive:\lianja\installers\standalone\example_timeclock</pre> | To deploy, install the whole standalone application directory, e.g for the example_timeclock App the directory is:<pre>drive:\lianja\installers\standalone\example_timeclock</pre> | ||
Line 478: | Line 480: | ||
Note: In v7.0, the exe and required libraries are located in the application directory itself, e.g. ''example_timeclock'' (this has been corrected in v7.1). These need to be placed in a ''bin'' directory, either by renaming the directory to ''bin'' or by creating a ''bin'' sub-directory and copying all the other files into the new sub-directory. | Note: In v7.0, the exe and required libraries are located in the application directory itself, e.g. ''example_timeclock'' (this has been corrected in v7.1). These need to be placed in a ''bin'' directory, either by renaming the directory to ''bin'' or by creating a ''bin'' sub-directory and copying all the other files into the new sub-directory. | ||
+ | |||
+ | ==Post-9.5 Deployment== | ||
+ | From v9.5 you can also choose to deploy your App in the following ways: | ||
+ | * Zip - set the [[#Standalone Zip|Standalone Zip]] App setting to true | ||
+ | * Self-extracting exe - set the [[#Standalone Exe|Standalone Exe]] App setting to true | ||
+ | |||
+ | Additionally, using the [[#Standalone Lib|Standalone Lib]] and [[#Standalone Data|Standalone Data]] App settings allows any required library files and databases to be included in the deployment zip or exe. | ||
[[Category:Lianja v7.0]] | [[Category:Lianja v7.0]] |
Revision as of 06:49, 26 March 2024
Contents
- 1 See Also
- 2 Overview
- 3 Sample App: example_timeclock
- 4 Building Standalone Executables
- 5 Building and Testing Standalone Executables
- 6 Deploying Standalone Executables
See Also
Deployment, Lianja Package Manager, Packaging Lianja Desktop Apps for Windows
Overview
From Lianja 7.0 developers can build standalone executables on Windows.
These executables can only be built for Apps that have been hand-coded in LianjaScript, Python, JavaScript, TypeScript or Babel using the Lianja UI Framework.
Alternatively, you can also visually build forms in the App Builder that use any of the following scripting languages as the Lianja UI framework is scripting language independent across Desktop, Web and Mobile Apps.
- LianjaScript/VFP
- Python
- JavaScript
- Typescript
Forms are based on a tabview section which contains canvas, grid or webview based sections in its tabs. See the blog article Working with forms in Lianja for further details.
This functionality is primarily for building small GUI Apps, not for business Apps running under the Lianja App Center with Users and Roles.
Sample App: example_timeclock
The example_timeclock sample App is included in the Lianja App Builder distribution from v7.0.0 in the 'General' category.
This app uses the new Camera UI Framework class and is a small App to handle clocking in and out of employees in a company.
Feel free to enhance this to suit your own needs by adding support for storing the clock in/out date and time along with the employees photo.
Building Standalone Executables
Scripting Language
Select the scripting language in the App Settings:
Standalone
Check 'Standalone' in the UI Presentation Rules App Settings.
Standalone Lib
From v9.5, checking the 'Standalone Lib' setting (in 'Standalone Options' shown in the screenshot above) will include library files. When the standalone app is run the library directory is set to the standalone App library directory.
The following text files are used to specify which library files should be included:
dependencies.txt
This is generated automatically when the App is built if the App contains any WebView Based Sections.
For example, the 'Tabbed Form' (form2) App, includes the following sections:
and its dependencies.txt is generated as:
@articleview @catalogview @commentsview @carouselview @calendar
The '@sectiontype' format references the corresponding 'sectiontype-dependencies.txt' file in the library containing the names of any required files and directories, e.g. catalogview-dependencies.txt:
bootstrap-3.3.4 jquery-1.10.2 catalogview.*
includes.txt
The 'includes.txt' file is used to specify any additional files that should be included.
As in 'dependencies.txt' these can be:
- folder names
- individual file names
- wildcards (like catalogview.*)
- @filename to include the contents of '@filename-dependencies.txt'
Standalone Zip
From v9.5, checking the 'Standalone Zip' setting (in 'Standalone Options' shown in the screenshot above) will create a zip file for the standalone App.
Standalone Exe
From v9.5, checking the 'Standalone Exe' setting (in 'Standalone Options' shown in the screenshot above) will create an installer as a self-extracting exe file for the standalone App. This can be unzipped / installed on a target machine.
Standalone Data
From v9.5, specifying a comma separated list of databases in the 'Standalone Data' setting (in 'Standalone Options' shown in the screenshot above) will copy the databases into the standalone App directory. When the standalone app is run the data directory is set to the standalone App data directory.
Setup
From v9.5, if the file setup.prg (or setup.py or setup.js) is contained within the App it is executed before the standalone App is run. You can check to see if the App is running standalone using Lianja.standalone and check the file path using Lianja.standalonefilepath.
You would typically do nothing in setup if the App is not running standalone.
if not Lianja.standalone return endif // e.g. to share data on a network set datadir to f:\lianja\data
Script
Then write the 'main' script with the same name as the App. In the case of the sample example_timeclock App, this is example_timeclock.prg or example_timeclock.js or example_timeclock.py (see code below). You can switch the 'Scripting language' in the App Settings to test each one.
LianjaScript/Visual FoxPro
Note the READ EVENTS at the end of the code which is needed for a standalone App.
example_timeclock.prg
local oform = createObject("Form") oform.resize(600, 600) oform.closable = 1 oform.caption = "Time clock - LianjaScript" oform.minwidth = 600 oform.minheight = 600 oform.addObject("ocont", "container") ocont.margin = 10 ocont.autosize = 1 ocont.layout = "V" ocont.backcolor = "black" ocont.addObject("obadgenolab", "label") obadgenolab.fixedheight = 24 obadgenolab.autowidth = 1 obadgenolab.alignment = "center" obadgenolab.caption = "Enter Badge Number" obadgenolab.backcolor = "darkgray" obadgenolab.forecolor = "white" obadgenolab.fontbold = 1 obadgenolab.fontsize = 10 ocont.addspacing(10) ocont.addObject("obadgeno", "textbox") obadgeno.fixedheight = 24 obadgeno.autowidth = 1 obadgeno.placeholder = "Enter your badge number, Take a Photo then CLOCK IN or CLOCK OUT" ocont.addspacing(10) ocont.addObject("obadgenolab2", "label") obadgenolab2.fixedheight = 24 obadgenolab2.autowidth = 1 obadgenolab2.alignment = "center" obadgenolab2.caption = "Take a Photo" obadgenolab2.backcolor = "darkgray" obadgenolab2.forecolor = "white" obadgenolab2.fontbold = 1 obadgenolab2.fontsize = 10 ocont.addspacing(10) ocont.addObject("ocamera", "camera") ocamera.autowidth = 1 ocamera.autoheight = 1 ocamera.backcolor = "black" ocont.addspacing(10) ocont.addObject("obadgenolab3", "label") obadgenolab3.fixedheight = 24 obadgenolab3.autowidth = 1 obadgenolab3.alignment = "center" obadgenolab3.caption = "Clock in / Clock out" obadgenolab3.backcolor = "darkgray" obadgenolab3.forecolor = "white" obadgenolab3.fontbold = 1 obadgenolab3.fontsize = 10 ocont.addObject("ocont2", "container") ocont2.layout = "H" ocont2.fixedheight = 60 ocont2.backcolor = "black" ocont2.spacing = 10 ocont2.addObject("obtn1", "commandbutton") obtn1.resize(60, 50) obtn1.flat = 1 obtn1.fixedheight = 50 obtn1.caption = "CLOCK IN" obtn1.stylesheet = "btn" ocont2.addObject("obtn2", "commandbutton") obtn2.flat = 1 obtn2.resize(60, 50) obtn2.fixedheight = 50 obtn2.stylesheet = "btn" obtn2.caption = "CLOCK OUT" // event handlers proc clockin() ocamera.takePhoto() thisform.showSuccessMessage("You clocked in on " + dtoc(date()) + " at " + ampm()) endproc proc clockout() ocamera.takePhoto() thisform.showSuccessMessage("You clocked out on " + dtoc(date()) + " at " + ampm()) endproc obtn1.click = clockin obtn2.click = clockout // modal form oform.show() // must put read events at the bottom so the window stays open until closed by user read events
Python
- Check that pip is the latest version. From a Windows Command Prompt (replace drive: with the drive for your Lianja App Builder installation):
cd drive:\lianja\bin python -m pip install --upgrade pip --no-warn-script-location
- In the Lianja App Builder Console Workspace, create the python3 directory to contain the modules local to the App (this has already been created for the example_timeclock App):
mkdir python3
- Install local Python modules (pip can be run from the Lianja/VFP tab in the Console Workspace Command Window), e.g. numpy:
pip install --target=drive:\lianja\apps\example_timeclock\python3\ numpy
Note: the local installation of the Python modules causes these modules to be included when the standalone executable is generated. During App development, any required modules also need to be installed in the default location for Lianja, i.e. without a --target specified.
To check modules installed in the default location:
pip list
To check the Python path (from the Python tab):
import sys
print(sys.path)
example_timeclock.py
import sys import types from datetime import datetime import Lianja class myCommandbutton(Lianja.Commandbutton): pass oform = createObject("form") oform.resize(600, 600) oform.closable = 1 oform.caption = "Time clock - Python" oform.minwidth = 600 oform.minheight = 600 oform.addObject("ocont", "container") ocont.margin = 10 ocont.autosize = 1 ocont.layout = "V" ocont.backcolor = "black" ocont.addObject("obadgenolab", "label") obadgenolab.fixedheight = 24 obadgenolab.autowidth = 1 obadgenolab.alignment = "center" obadgenolab.caption = "Enter Badge Number" obadgenolab.backcolor = "darkgray" obadgenolab.forecolor = "white" obadgenolab.fontbold = 1 obadgenolab.fontsize = 10 ocont.addspacing(10) ocont.addObject("obadgeno", "textbox") obadgeno.fixedheight = 24 obadgeno.autowidth = 1 obadgeno.placeholder = "Enter your badge number, Take a Photo then CLOCK IN or CLOCK OUT" ocont.addspacing(10) ocont.addObject("obadgenolab2", "label") obadgenolab2.fixedheight = 24 obadgenolab2.autowidth = 1 obadgenolab2.alignment = "center" obadgenolab2.caption = "Take a Photo" obadgenolab2.backcolor = "darkgray" obadgenolab2.forecolor = "white" obadgenolab2.fontbold = 1 obadgenolab2.fontsize = 10 ocont.addspacing(10) ocont.addObject("ocamera", "camera") ocamera.autowidth = 1 ocamera.autoheight = 1 ocamera.backcolor = "black" ocont.addspacing(10) ocont.addObject("obadgenolab3", "label") obadgenolab3.fixedheight = 24 obadgenolab3.autowidth = 1 obadgenolab3.alignment = "center" obadgenolab3.caption = "Clock in / Clock out" obadgenolab3.backcolor = "darkgray" obadgenolab3.forecolor = "white" obadgenolab3.fontbold = 1 obadgenolab3.fontsize = 10 ocont.addObject("ocont2", "container") ocont2.layout = "H" ocont2.fixedheight = 60 ocont2.backcolor = "black" ocont2.spacing = 10 ocont2.addObject("obtn1", "myCommandbutton") obtn1.resize(60, 50) obtn1.flat = 1 obtn1.fixedheight = 50 obtn1.caption = "CLOCK IN" obtn1.stylesheet = "btn" ocont2.addObject("obtn2", "myCommandbutton") obtn2.flat = 1 obtn2.resize(60, 50) obtn2.fixedheight = 50 obtn2.stylesheet = "btn" obtn2.caption = "CLOCK OUT" # event handlers def clockin(self): ocamera.takePhoto() now = datetime.now() oform.showSuccessMessage("You clocked in at " + now.strftime("%m/%d/%Y %I:%M:%S %p")) def clockout(self): ocamera.takePhoto() now = datetime.now() oform.showSuccessMessage("You clocked out at " + now.strftime("%m/%d/%Y %I:%M:%S %p")) # We can dynamically bind events to custom classes in Lianja/Python bindEvent(obtn1, clockin, "click") bindEvent(obtn2, clockout, "click") # modal form oform.show() Lianja.readEvents()
JavaScript
example_timeclock.js
var oform = createObject("Form"); oform.resize(600, 600); oform.closable = 1; oform.caption = "Time clock - JavaScript"; oform.minwidth = 600; oform.minheight = 600; oform.deleteonclose = 1; oform.addobject("ocont", "container"); ocont.margin = 10; ocont.autosize = 1; ocont.layout = "V"; ocont.backcolor = "black"; ocont.addObject("obadgenolab", "label"); obadgenolab.fixedheight = 24; obadgenolab.autowidth = 1; obadgenolab.alignment = "center"; obadgenolab.caption = "Enter Badge Number"; obadgenolab.backcolor = "darkgray"; obadgenolab.forecolor = "white"; obadgenolab.fontbold = 1; obadgenolab.fontsize = 10; ocont.addspacing(10); ocont.addObject("obadgeno", "textbox"); obadgeno.fixedheight = 24; obadgeno.autowidth = 1; obadgeno.placeholder = "Enter your badge number, Take a Photo then CLOCK IN or CLOCK OUT"; ocont.addspacing(10); ocont.addObject("obadgenolab2", "label"); obadgenolab2.fixedheight = 24; obadgenolab2.autowidth = 1; obadgenolab2.alignment = "center"; obadgenolab2.caption = "Take a Photo"; obadgenolab2.backcolor = "darkgray"; obadgenolab2.forecolor = "white"; obadgenolab2.fontbold = 1; obadgenolab2.fontsize = 10; ocont.addspacing(10); ocont.addObject("ocamera", "camera"); ocamera.autowidth = 1; ocamera.autoheight = 1; ocamera.backcolor = "black"; ocont.addspacing(10); ocont.addObject("obadgenolab3", "label"); obadgenolab3.fixedheight = 24; obadgenolab3.autowidth = 1; obadgenolab3.alignment = "center"; obadgenolab3.caption = "Clock in / Clock out"; obadgenolab3.backcolor = "darkgray"; obadgenolab3.forecolor = "white"; obadgenolab3.fontbold = 1; obadgenolab3.fontsize = 10; ocont.addObject("ocont2", "container"); ocont2.layout = "H"; ocont2.fixedheight = 60; ocont2.backcolor = "black"; ocont2.spacing = 10; ocont2.addObject("obtn1", "commandbutton"); obtn1.resize(60, 50); obtn1.flat = 1; obtn1.fixedheight = 50; obtn1.caption = "CLOCK IN"; obtn1.stylesheet = "btn"; ocont2.addObject("obtn2", "commandbutton"); obtn2.flat = 1; obtn2.resize(60, 50); obtn2.fixedheight = 50; obtn2.stylesheet = "btn"; obtn2.caption = "CLOCK OUT"; // event handlers function clockin() { ocamera.takePhoto() oform.showSuccessMessage("You clocked in on " + new Date().toLocaleString()) }; function clockout() { ocamera.takePhoto(); oform.showSuccessMessage("You clocked out on " + new Date().toLocaleString()) }; obtn1.click = clockin; obtn2.click = clockout; // modal form oform.show(); // must put read events at the bottom so the window stays open until closed by user read_events();
Building and Testing Standalone Executables
To build and test, switch to the Console workspace and click the 'Desktop App View' button in the Headerbar:
The Output window will show the compilation and build operations.
To build and test the other scripts in the example_timeclock App - LianjaScript (.prg), Python (.py) and JavaScript (.js) are available - just select the required scripting language in the App Settings and click the 'Desktop App View' button again.
Lianja Standalone App Debugger
From v9.5 standalone Apps can be debugged at runtime.
Under construction
Deploying Standalone Executables
When building a standalone executable with LianjaScript, all the .prg files in the App directory are linked together into a .src file and this is compiled.
The resulting object file is bound onto the end the Lianja runtime executable and the authenticode code signing is adjusted so as to not be affected by the application payload.
All of the supporting libraries are included in the standalone application directory.
If your application is built in Python, there is a python3 directory included which contains the python modules you have installed with pip.
Pre-9.5 Deployment
To deploy, install the whole standalone application directory, e.g for the example_timeclock App the directory is:drive:\lianja\installers\standalone\example_timeclock
and it has a single bin sub-directory containing the executable and required libraries:
drive:\lianja\installers\standalone\example_timeclock\bin
To run, the executable is:
drive:\lianja\installers\standalone\example_timeclock\bin\example_timeclock.exe
Note: In v7.0, the exe and required libraries are located in the application directory itself, e.g. example_timeclock (this has been corrected in v7.1). These need to be placed in a bin directory, either by renaming the directory to bin or by creating a bin sub-directory and copying all the other files into the new sub-directory.
Post-9.5 Deployment
From v9.5 you can also choose to deploy your App in the following ways:
- Zip - set the Standalone Zip App setting to true
- Self-extracting exe - set the Standalone Exe App setting to true
Additionally, using the Standalone Lib and Standalone Data App settings allows any required library files and databases to be included in the deployment zip or exe.