B4J Tutorial B4JPackager11 - the simplest way to distribute UI apps

Status
Not open for further replies.

Erel

Administrator
Staff member
Licensed User
Better to start with the integrated packager: https://www.b4x.com/android/forum/t...-way-to-distribute-standalone-ui-apps.117880/
B4JPackager11 is a B4J non-ui program that builds a package with your app jar and an embedded modularized Java runtime.

It works with OpenJDK 11 and B4J v6.8+.

Lets start with the output.

It looks like this:



- run.exe is the executable (starting from v1.14 the executable name is based on the jar name). The executable file depends on the other folders. You can distribute the executable and the folders and it will work without any other dependencies.
- run_debug.bat starts the program with a console that shows the program output.
It also creates a template Inno Setup script in the parent folder which you can use to build an installer. The installer will be a single.
On Mac and Linux it doesn't create an executable. It instead creates a bash script file that can be used to start the program.

There are two ways to run B4JPackager11:

Directly from B4J - Start with this method.

Just set the InputJar path and run it.

There are several additional parameters that you can configure:
- NetFrameworkCSC - Path to to the C# compiler which is part of .Net Framework.
- IconFile - Path to the executable icon file (.ico file).
- ExcludedModules - List of excluded modules. javafx.web is excluded by default. You need to remove it from the list if you are using WebView.
- IncludedModules - List of included modules. Should be empty in most cases as the tool tries to discover the dependent modules automatically.
- AdditionalModuleInfoString - A string that will be added to the module.info file. This is required in some cases such as with jPOI: https://www.b4x.com/android/forum/threads/105311/#content

Command line with a json file

You can create a json file with the input jar and optionally other settings and run it from the command line:
B4X:
<java 11>\bin\java -jar B4JPackager11.jar <json file>
The json file should look like this:
B4X:
{
   InputJar: "C:/Users/H/Documents/B4X/X2/Angry Birds/B4J/Objects/AngryBirds.jar"
}
Use forward slashes as I did above.

If you want to remove javafx.web from the excluded modules:
B4X:
{
   InputJar: "C:/Users/H/Documents/B4X/X2/Angry Birds/B4J/Objects/AngryBirds.jar",
   ExcludedModules: []
}
Platforms

You must build the package on the target platform.
Windows - Java 11 should already be installed. Note that Java 11 is 64 bit only.

OpenJDK 11 + OpenJFX 11 (SDK + jmods) - GPL + classpath exception license
Mac - https://b4xfiles-4c17.kxcdn.com/b4j/mac_jdk-11.0.1.zip
Linux - https://b4xfiles-4c17.kxcdn.com/b4j/linux_jdk-11.0.1.zip

OpenJDK 14 (same license):
Mac - https://b4xfiles-4c17.kxcdn.com/b4j/mac_jdk-14.0.1.zip
Linux - https://b4xfiles-4c17.kxcdn.com/b4j/linux_jdk-14.0.1.zip
Windows - https://b4xfiles-4c17.kxcdn.com/jdk-14.0.1.zip

Notes

- All files in the packager temp folder are deleted when it runs.
- MediaPlayer will fail to play files from File.DirAssets. Copy them when the program starts.

Updates

- V1.21 - Integrated version. Adds support for Java 14.
- V1.15 - Updated the inno script template based on Peter's suggestions: https://www.b4x.com/android/forum/t...-the-inno-setup-file-by-default-maybe.114539/
- V1.14 - The executable name is set to be the same as the input jar name. Internally it also creates a copy of javaw.exe with the same name. This sets the process name in task manager. Note that the description will still be "OpenJDK ...".
- V1.13 - Allows configuring VM arguments. It can be done with the VMArgs global variable or a VMArgs key in the json file.
- V1.12 - Skips automatic inclusion for services based on inner classes as it breaks the jdeps tool.
- V1.11 - Adds a check that InputJar points to a jar file.
- V1.10 - Adds support for command line arguments. Usage example: https://www.b4x.com/android/forum/threads/associating-files-with-your-app.106984/
(Currently only supported on Windows)
- V1.05 - Fixes the "failed to delete temp folder" issue when the folder is open in Windows Explorer.
- V1.04 - New AdditionalModuleInfoString field. This is required when packaging for an app that uses jPOI.
- v1.02 - Configures the Inno Setup script to 64 bit.
- v1.01 - Fixes a localization issue.
 

Attachments

Last edited:

highflyer

Member
Licensed User
Is there any way to avoid the opening of the terminal in nix and MacOS when running the packaged app ??
 

Erel

Administrator
Staff member
Licensed User
I am thinking of using the Eclipse/IBM JRE/JVM which is called OpenJ9.
I don't think that it includes the JavaFX modules. It will be difficult to add them yourself.

Is there any way to avoid the opening of the terminal in nix and MacOS when running the packaged app ??
The current implementation is indeed not perfect on Mac and Linux. It will be improved.
 

Foz

Member
Licensed User
Just as a note, Java 11 is only 64-bit, the ISS script generated is missing "ArchitecturesInstallIn64BitMode=x64" in the set up, so it goes for installation as a 32 bit application (Program Files x86).
 

David Meier

Active Member
Licensed User
Hi
This is a very cool and useful feature, thx for it. There is one thing I observed on my mac. Though it works, the program is not running alone. Clicking on the generated run.command opens a terminal window and the program is started from there.
This is not so elegant, can this be done differently?
Kind regards
David
 
Last edited:

David Meier

Active Member
Licensed User
Hi
This is a very cool and useful feature, thx for it. There is one thing I observed on my mac. Though it works, the program is not running alone. Clicking on the generated run.command opens a terminal window and the program is started from there.
This is not so elegant, can this be done differently?
Kind regards
David
As far as now I have found this program: http://sveinbjorn.org/platypus
With Platypus you can very easily add all files and directories from B4JPackager11 into one program package. It also gives you the possibility to add a custom icon. I haven't done a lot of testing but it seems to work. So B4JPackager11 and Platypus = Stand alone application on OS X.
 

agraham

Expert
Licensed User
My System needs an additional line call to Sleep(0) in Sub PrepareFolders otherwise if the Temp folder exists it occasionally doesn't recognize that it has been deleted. The Sleep(0) seems to let the System actually finalize the deletion. I could just delete the File.Exists test but it seems better to add the Sleep(0).

B4X:
    If File.Exists(TempFolder, "") Then
        DeleteFolderRecursive(TempFolder)
        File.Delete(TempFolder, "")
        Sleep(0) ' Needs a delay before testing if folder exists.
    End If
    If File.Exists(TempFolder, "") Then
        Log("Failed to delete temp folder")
        ExitApplication2(1)
    End If
A suggestion to make this easier to use: I would like to be able to pick the target jar using a File Picker and then have the temp folder created in the same folder as the target jar, and maybe named something more appropriate like 'Package'. I would do this myself but as this is presently cross-platform and as Erel has threatened in post #6 to improve the Mac and Linux implementation maybe he could consider this at that time. I would also rename run.exe to have the same name as the target jar.
 

keirS

Well-Known Member
Licensed User
The packager doesn't pass on command line arguments to Java. I changed the C# for the process arguments to:

B4X:
   p.StartInfo.Arguments = "@release_java_modules.txt -m ${TargetModule}/${PackageName}.main "  + string.Join(" ", args);
which works but I am not familiar with how escape sequences work with strings in C# (other than they are different to how VB.net works) so I am not sure if the arguments will always be passed correctly?
 

JOTHA

Well-Known Member
Licensed User
Directly from B4J - Start with this method.
Just set the InputJar path and run it.
Can anyone tell me how to set the InputJar path, maybe i'm too stupid for that ...
B4X:
    'InputJar = m.GetDefault("InputJar", InputJar)  '-- Original -- funzt nicht --
    'InputJar = m.GetDefault("C:\Users\JOTHA\Downloads\B4JPackager11\Objects\B4JPackager11.jar", InputJar)  '-- funzt nicht --
    'InputJar = m.GetDefault("InputJar", "C:\Users\JOTHA\Downloads\B4JPackager11\result.jar")  '-- funzt nicht --
    'InputJar = m.GetDefault("InputJar", "C:\Users\JOTHA\Downloads\B4JPackager11\Objects\B4JPackager11.jar")  '-- funzt nicht --
"result.jar" is the file which i want to have as the instllation exe-file ...
 
Status
Not open for further replies.
Top