Gradle Package As Mac App

-->

The application plugin can generate Unix (suitable for Linux, macOS etc.) and Windows start scripts out of the box. The start scripts launch a JVM with the specified settings defined as part of the original build and runtime environment (e.g. JAVAOPTS env var). The default script templates are based on the same scripts used to launch Gradle itself, that ship as part of a Gradle distribution. The module-level build.gradle file, located in each project/module/ directory, allows you to configure build settings for the specific module it is located in. Configuring these build settings allows you to provide custom packaging options, such as additional build types and product flavors, and override settings in the main/ app manifest.

Azure Pipelines

This guidance explains how to automatically build Xamarin apps for Android and iOS.

App

Example

For a working example of how to build a Xamarin app, import (into Azure Repos or TFS) or fork (into GitHub) this repo:

The sample code includes an azure-pipelines.yml file at the root of the repository. You can use this file to build the app.

Follow all the instructions in Create your first pipeline to create a build pipeline for the sample app.

Build environment

You can use Azure Pipelines to build your Xamarin apps without needing to set up any infrastructure of your own. Xamarin tools are preinstalled on Microsoft-hosted agents in Azure Pipelines. You can use macOS or Windows agents to run Xamarin.Android builds, and macOS agents to run Xamarin.iOS builds. If you are using a self-hosted agent, you must install Visual Studio Tools for Xamarin for Windows agents or Visual Studio for Mac for macOS agents.

For the exact versions of Xamarin that are preinstalled, refer to Microsoft-hosted agents.

Create a file named azure-pipelines.yml in the root of your repository. Then, add the following snippet to your azure-pipelines.yml file to select the appropriate agent pool:

Build a Xamarin.Android app

To build a Xamarin.Android app, add the following snippet to your azure-pipelines.yml file. Change values to match your project configuration. See the Xamarin.Android task for more about these options.

Package

Sign a Xamarin.Android app

See Sign your mobile Android app during CI for information about signing your app.

Next steps

See Android guidance for information about:

  • Signing and aligning an Android APK
  • Testing on the Android Emulator
  • Testing on Azure-hosted devices
  • Retaining build artifacts with the build record
  • Distributing through App Center
  • Distributing through Google Play

Build a Xamarin.iOS app

To build a Xamarin.iOS app, add the following snippet to your azure-pipelines.yml file. Change values to match your project configuration. See the Xamarin.iOS task for more about these options.

Sign and provision a Xamarin.iOS app - The PackageApp option

To generate a signed and provisioned Xamarin.iOS app .ipa package, set packageApp to true and make sure prior to this task you installed the right Apple Provisioning Profile and Apple Certificates that match your App Bundle ID into the agent running the job.

To fulfill these mandatory requisites use the Microsoft Provided tasks for installing an Apple Provisioning Profile and installing Apple Certificates.

Tip

The Xamarin.iOS build task will only generate an .ipa package if the agent running the job has the appropriate provisioning profile and Apple certificate installed. If you enable the packageApp option and the agent does not have the appropriate apple provisioning profile(.mobileprovision) and apple certificate(.p12) the build may report succeeded but there will be no .ipa generated.

For Microsoft Hosted agents the .ipa package is by default located under path:
{iOS.csproj root}/bin/{Configuration}/{iPhone/iPhoneSimulator}/

You can configure the output path by adding an argument to the Xamarin.iOS task as following:

This example locates the .ipa in the Build Artifact Staging Directory ready to be pushed into Azure DevOps as an artifact to each build run.To push it into Azure DevOps simply add a Publish Artifact task to the end of your pipeline.

See Sign your mobile iOS app during CI for more information about signing and provisioning your iOS app.

Expand menu Advanced for the Xamarin.iOS build task and add /p:IpaPackageDir='/Users/vsts/agent/2.153.2/work/1/a' in the input field Arguments to place the generated .ipa package in the Build Artifact Staging Directory. To push it into Azure DevOps simply add a Publish Artifact task to the end of your pipeline.

Set the Xamarin SDK version on macOS

To set a specific Xamarin SDK version to use on the Microsoft-hosted macOS agent pool, add the following snippet before the XamariniOS task in your azure-pipelines.yml file. For details on properly formatting the version number (shown as 5_4_1 below), see How can I manually select versions of tools on the Hosted macOS agent?.

Build Xamarin.Android and Xamarin.iOS apps with one pipeline

You can build and test your Xamarin.Android app, Xamarin.iOS app, and related apps in the same pipeline by defining multiple jobs in azure-pipelines.yml. These jobs can run in parallel to save time. The following complete example builds a Xamarin.Android app on Windows, and a Xamarin.iOS app on macOS, using two jobs.

Next steps

See Xcode guidance for information about:

  • Testing on Azure-hosted devices
  • Retaining build artifacts with the build record
  • Distributing through App Center
  • Distributing through the Apple App Store

A self-contained application is a wrapper for your JavaFX application, making it independent of what the user might have installed.

6.1 Introduction

JavaFX packaging tools provide built-in support for several formats of self-contained application packages. The basic package is simply a single folder on your hard drive that includes all application resources as well as Java Runtime. It can be redistributed as is, or you can build an installable package (for example, EXE or DMG format).

From the standpoint of process, producing a self-contained application package is very similar to producing a basic JavaFX application package as discussed in Chapter 5, 'Packaging Basics,' with the following differences:

  • Self-contained application packages can only be built using JDK 7 Update 6 or later. (The standalone JavaFX SDK does not support self-contained applications.)

  • Self-contained application packages must be explicitly requested by passing additional arguments to the <fx:deploy> Ant task or javafxpackager tool.

  • Operating system and tool requirements must be met to be able to build a package in a specific format.

While it is easy to create a basic self-contained application package, tailoring it to achieve the best user experience for a particular distribution method usually requires some effort and a deeper understanding of the topic.

6.2 Pros and Cons of Self-Contained Application Packages

Deciding whether the uses of self-contained application packages is the best way to deploy your application depends on your requirements.

Self-contained application packages have several benefits:

  • They resemble native applications for the target platform, in that users install the application with an installer that is familiar to them and launch it in the usual way.

  • They offer no-hassle compatibility. The version of Java Runtime used by the application is fully controlled by the application developer.

  • Your application is easily deployed on fresh systems with no requirement for Java Runtime to be installed.

  • Deployment occurs with no need for admin permissions when using ZIP or user-level installers.

On the other hand, there are a few caveats:

  • 'Download and run' user experience

    Unlike web deployment, the user experience is not about 'launch the application from the web.' It is more one of 'download, install, and run' process, in which the user might need to go through additional steps to get the application launched. For example, the user might have to accept a browser security dialog, or find and launch the application installer from the download folder.

  • Larger download size

    In general, the size of self-contained application packages will be noticeably larger than the size of a standalone application, because a private copy of Java Runtime is included.

  • Package per target platform

    Self-contained application packages are platform specific and can only be produced for the same system that you build on. If you want to deliver self-contained application packages on Windows, Linux and Mac you will have to build your project on all three platforms.

  • Application updates are the responsibility of developer

    Web-deployed Java applications automatically download application updates from the web as soon as they are available. The Java Autoupdate mechanism takes care of updating the Java and JavaFX Runtimes to the latest secure version several times every year. There is no built-in support for this in self-contained applications.

6.3 Basics

Each self-contained application package includes the following:

  • The application code, packaged into a set of JAR files, plus any other application resources (data files, native libraries)

  • A private copy of the Java and JavaFX Runtimes, to be used by this application only

  • A native launcher for the application

  • Metadata, such as icons

Multiple package formats are possible. Built-in support is provided for several types of packages, but you can assemble your own packages by post-processing a self-contained application packaged as a folder, for example if you want to distribute your application as a ZIP file.

6.3.1 Self-Contained Application Structure

The basic form of a self-contained application is a single folder on your hard drive, such as the example in Figure 6-1. When any of the installable packages are installed, the result is a folder with the same content.

Figure 6-1 Example of a Self-Contained Application Package


The internal structure of a self-contained application folder is platform-specific and may change in future. However, the following points are guaranteed:

  • The application package, as defined in Chapter 5, 'Packaging Basics,', is included as a folder, preserving the application directory structure.

  • A copy of Java Runtime is included as another folder, and the Java Runtime directory structure is preserved.

Because directory structure is preserved, the application can load external resources using paths relative to the application JAR or java.home system property.


Note:

Only a subset of Java Runtime is included by default. Some optional and rarely used files are excluded to reduce the package size, such as all executables. If you need something that is not included by default, then you need to copy it in as a post-processing step. For installable packages, you can do this from the config script that is executed after populating the self-contained application folder. See Section 6.3.3, 'Customization Using Drop-In Resources.'


6.3.2 Basic Build

The easiest way to produce a self-contained application is to modify the deployment task. To request creation of all applicable self-contained application packages simply add nativeBundles='all' to the <fx:deploy> task, as shown in Example 6-1.

Example 6-1 Simple Deployment Task to Create All Self-contained Application Packages

You can also specify the exact package format you want to produce. Use the value image to produce a basic package, exe to request an EXE installer, dmg to request a DMG installer, and so on. For the full list of attribute values, see the nativeBundles attribute in the <fx:deploy> entry in the Ant Task Reference.

If you have a JavaFX project in Netbeans 7.2, you can add the above snippet as a post-build step by overriding the '-post-jfx-deploy' target, as shown in Example 6-2. Add the following code to the build.xml file in the main project directory.

Example 6-2 Custom build.xml Script to Create Self-contained Application Packages in NetBeans IDE

You can also produce native packages using the JavaFX Packager tool. self-contained application packages are built by default if you use the -makeall command, or you can request them explicitly using the -native option in the -deploy command. See the javafxpackager command reference.

Example 6-3 shows the use of the -native option with the -deploy command, used to generate all applicable self-contained application packages for the BrickBreaker application. The -deploy command requires a JAR file as input, so it assumes that dist/BrickBreaker.jar has already been built:

Example 6-3 JavaFX Packager Command to Generate Self-Contained Application Packages

6.3.3 Customization Using Drop-In Resources

The packaging tools use several built-in resources to produce a package, such as the application icon or config files. One way to customize the resulting package is to substitute built-in resource with your customized version.

For this you need to:

  • Know what resources are used

  • Drop custom resources into a location where the packaging tool will look for them

The following sections explain how to do this.

6.3.3.1 Preparing Custom Resources

To get more insight into what resources are being used, enable verbose mode by adding the verbose='true' attribute to <fx:deploy>, or pass the -v option to the javafxpackager -deploy command.

Verbose mode does the following:

  • It prints the following items:

    • A list of config resources used for the package you are generating

    • The role of each resource

    • The expected custom resource name

  • It saves a copy of all config files to the temp folder, so you can use and customize it.

Example 6-4 shows sample output, with the important parts highlighted:

Now you can grab a copy of the config file and tune it to your needs. For example, you can take Info.plist and add localized package names.

Note: It is recommended that you disable verbose mode once you are done with customization or add a custom cleanup action to remove sample config files.

6.3.3.2 Substituting a Built-In Resource

Packaging tools look for customized resources on the classpath before reverting to built-in resource. The Javafx Packager has '.' (the current working directory) added to the classpath by default. Hence, to replace the application icon, simply copy your custom icon to ./package/macosx/DemoApp.icns in the directory where javafxpackager is run (typically, the root project directory).

The classpath for JavaFX Ant tasks is defined when task definitions are loaded. You must add an additional path to the lookup before the path ant-javafx.jar.

Example 6-5 shows how to add '.' to the classpath. For a more detailed code snippet, see Example 10-1).

Example 6-5 Enabling Resource Customization for JavaFX Ant Tasks

If you created a JavaFX project using Netbeans 7.2 or later, then the JavaFX Ant tasks are predefined, and '.' is already added to the classpath by default.

Once you provide a customized resource, verbose build output will report that it is used. For example, if you added a custom icon to an application, then the verbose output would report the addition, shown in Example 6-6.

Example 6-6 Verbose Output After Adding a Customized Icon Resource

6.3.4 Customization Options

Many of the existing JavaFX Ant elements are used to customize self-contained application packages. Different sets or parameters are needed for different packages, and the same element might have different roles. Table 6-1 introduces most of the customization options.

Table 6-1 Customization Options with Ant Elements and Attributes

TagAttributeDetails

<fx:application>

id

Identifier of application. Format is platform/package specific. If not specified, then a value will be generated.


version

Application version. Default: 1.0.


name

Short name of the application. Most bundlers use it to create the name of the output package. If not specified, then the name of the main class is used.

<fx:preferences>

shortcut

If set to true, then a desktop shortcut is requested.


menu

If set to true then an entry in the applications menu is requested.


install

If set to false, then a user-level installer is requested. Default behavior depends on the package format. See Table 6-2.

<fx:fileset>

type

Defines the role of files in the process of assembling the self-contained application package. Resources of types jnlp and native are not used for building self-contained application packages. Resources of type license are used as a source of content for a click-through license or a license embedded into the package

<fx:info>

title

Application title.


vendor

Application vendor.


category

Application category. Category names are package-format specific.


license

License type (for example, GPL). As of JavaFX 2.2, this attribute is used only for Linux bundles.


copyright

Short copyright statement.


description

Application description.

<fx:jvmarg>


JVM arguments to be passed to JVM and used to run the application (for example, large heap size).

<fx:property>


Properties to be set in the JVM running the application.


6.3.5 Platform-Specific Customization for Basic Packages

Creation and customization of the basic form of self-contained application packages is a fairly straightforward process, but note the following points:

  • Different icon types are needed for different platforms.

    For example, on Windows, the .ico format is expected, and on Mac it is .icns. No icon is embedded into launcher on Linux.

  • To ensure that the icon is set in runtime, you also need to add it to the application stage. For example, add the following code to to the start() method of your application:

  • Consider signing files in output folder if you plan to redistribute them.

    For example, on Windows, the launcher executable can be signed using signtool.exe.

6.3.5.1 Mac OS X

The resulting package on Mac OS X is an 'application bundle' (or .app) in the Mac OS 'dialect/jargon'.

Several config parameters end up in the Info.plist file in the application bundle and need to conform to the rules:

  • Application ID (or main class name if ID is not specified) is used as CFBundleIdentifier.

  • Application version is used as CFBundleShortVersionString.

Mac OS X 10.8 introduces Gatekeeper, which prevents execution of untrusted code by default (regardless of whether this code was implemented in Objective-C or Java).

The user can manually enable the application to run, but this is not a perfect user experience. To get optimal user experience, you need to obtain a Developer ID Certificate from Apple and sign the .app folder produced by JavaFX packaging tools, as follows:

For more details, see the Developer ID and Gatekeeper topic at the Apple Developer site.

6.4 Installable Packages

A self-contained application can be wrapped into a platform-specific installable package to simplify redistribution. JavaFX packaging tools provide built-in support for several formats of installable packages, depending on the availability of third-party tools.

Tuning the user experience for the installation process is specific to the particular installer technology, as described in other sections in this chapter. However, you must decide what type of installer you need. The following considerations that might help with your decision.

  • System-wide or per-user installation?

    System-wide installation results in a package installed into a shared location and can be used by any user on the system. On the other hand it assumes admin permissions and will likely result in additional steps during the installation process, such as an OS prompt to approve elevating installer permissions.

    Per-user installation copies the package into a private user directory and does not require admin permissions. This enables you to show as little dialogs as possible and run the program even if user is not eligible for admin privileges.

    Note that whenever a user- or system-level installable package is requested, the build procedure itself does not require admin permissions.

  • Do you need a click-through license?

    Some installable packages support showing license text before initiating the installation. The installation process starts only after the user accepts the license.

    Think carefully if you really need this, because extra dialogs degrade the user experience.

  • What menu/desktop integration is needed?

    The user should be able to launch your application easily. Therefore, we assume that having a desktop shortcut or adding the application to the list of applications in the menu is required.

Note that the current implementation contains many simplifying assumptions.

For example, installers never ask the user to choose the location to install the package. Developers also have limited control of the installation location—they can only choose system or private user location).

If this is not sufficient for your needs you can try advanced customizations by tuning the config file templates (see Section 6.3.3, 'Customization Using Drop-In Resources') or packaging a basic self-contained application and then wrapping it into an installable package on your own.

As of JDK 7u6, the following installable package formats are supported:

Table 6-2 Installable Package Formats

Package formatInstallation Location(Default mode in bold)Click-Through LicensePrerequisites

EXE

Per user: %LOCALAPPDATA%

System: %ProgramFiles%

Yes (option)

  • Windows

  • Inno Setup 5 or later

MSI

Per user: %LOCALAPPDATA%

System: %ProgramFiles%

No special support

  • Windows

  • WiX 3.0 or later

DMG

Per user: user's desktop folder

System: /Applications

Yes (option)

  • Mac OS X

RPM

Per user: unsupported

System: /opt

No special support

  • Linux

  • RPMBuild

DEB

Per user: unsupported

System: /opt

No special support

  • Linux

  • Debian packaging tools


6.4.1 EXE Package

As of JavaFX 2.2, in order to generate an EXE package, you must have Inno Setup 5 or later installed and available on the PATH. To validate that it is available, try running iscc.exe from the command line where you launch the build or from your build script.

By default, the generated package:

  • Does not require admin privileges to install

  • Is optimized to have a minimum number of dialogs

  • Must be referenced from programs menu or have desktop shortcut (having both are fine)

  • Is configured so the application launches at the end of installation

Figure 6-2 shows a typical dialog box for a self-contained JavaFX application being installed on Windows.

Figure 6-2 Windows Installation Dialog for a Self-Contained JavaFX Application


Customization tips:

  • If you chose system-wide installation, then the user will need to have admin permissions, and the application will not be launched at the end of installation.

  • A click-through license is supported (an .rtf file is required).

  • The image shown in the installation dialogs is different from the application icon.

    You can customize it using the 'drop-in technique' described in Section 6.3.3, 'Customization Using Drop-In Resources.'

    The current version of Inno Setup assumes the image is a bitmap file with maximum size of 55x58 pixels.

  • To ensure the icon is set in the runtime, make sure to explicitly add it to the stage. See Section 6.3.5, 'Platform-Specific Customization for Basic Packages.'

  • Consider signing the resulting .exe package. If you distribute an unsigned executable, then many versions of Windows will scare the user with an 'Unknown Publisher' warning dialog.

    If you sign your package, then this warning will be removed. You will need to get a certificate and then can use the signtool.exe utility to sign the code.

  • You can fine tune the self-contained application folder before it is wrapped into an .exe file, for example to sign the launcher executable.

    To do this, provide a Windows script file, using the technique from Section 6.3.3, 'Customization Using Drop-In Resources.'


Note:

While the resulting package is displayed in the list of installed applications, it does not use Windows Installer (MSI) technology and does not require the use of GUIDs. See the Inno Setup FAQ for details.


6.4.2 MSI Package

MSI packages are generated using the Windows Installer XML (WiX) toolset (also known as WiX). As of JavaFX 2.2, WiX 3.0 or later is required, and it must be available on the PATH. To validate, try running candle /? from the command line where you launch the build or from your build script.

Gradle Package Jar

By default, a generated MSI package:

  • Is optimized for deployment using enterprise deployment tools

  • Installs to a system-wide location

  • Does not have any click-through UI. Only a progress dialog is shown.

  • Must to be referenced from the programs menu or have a desktop shortcut (having both is fine)

  • Will remove all files in the installation folder, even if they were created outside of the installation process. (WiX 3.5 or later is required.)

  • Will try to use the application identifier as UpgradeCode.

    If the application identifier is not a valid GUID, then a random GUID for UpgradeCode is generated.

  • ProductCode is randomly generated. To use a fixed Product code, customize the WiX template file using the technique from Section 6.3.3, 'Customization Using Drop-In Resources.'

If you plan to distribute your MSI package on the network, then consider signing it for the best user experience.

You can also fine tune the self-contained application folder before it is wrapped into the .msi file, (for example, to sign the launcher executable). For details, see Section 6.4.1, 'EXE Package.'

To add a custom UI to the MSI package, you can customize WiX template file used by JavaFX Packager using technique from Section 6.3.3, 'Customization Using Drop-In Resources.'. Consult WiX documentation for more details.

6.4.3 DMG Package

By default, a DMG package provides a simple drag-and-drop installation experience. Figure 6-3 shows an example of the default behavior during installation.

Figure 6-3 Example of Default Installer for Mac OS X


To customize the appearance of the installation window, you can provide a custom background image.

If the background image has different dimensions or you need to position the icons differently, then you must also customize the DMG setup script that is used to tweak sizes and positions of elements on the install view. For details about how to do this, see Section 6.3.3, 'Customization Using Drop-In Resources.'

To fine tune the self-contained application folder before it is wrapped, you can provide your own bash script to be executed after the application folder is populated. You can use it, for example, to enrich it with localization files, and so on. Figure 6-4 shows an example of a 'tuned' application installer.

Figure 6-4 Example of Customized Appearance of Installable Package for Mac OS X


Gradle Package Dependencies In Jar

To create a Gatekeeper-friendly package (for Mac OS X 10.8 or later, see Section 6.3.5.1, 'Mac OS X'), the application in the DMG package must be signed. It is not necessary to sign the DMG file itself. To sign the application, you can use a technique described in Section 6.3.3, 'Customization Using Drop-In Resources' to provide a config script to be executed after the application bundle is populated. For sample DemoApp, the config script is located in the package/macosx/DemoApp-post-image.sh and has the content shown in Example 6-7.

Example 6-7 Example of Config Script to Sign the Application

The DMG installer also supports a click-though license provided in the text format. If use of rich text format is desired, then prepare the license.plist file externally, then add it to the package using the technique from Section 6.3.3, 'Customization Using Drop-In Resources.'

No third party tools are needed to create a DMG package.

6.4.4 Linux Packages

Producing install packages for Linux assumes that the native tools needed to build install packages are installed. For RPM packages, this typically means the RPMBuild package and its dependencies. For DEB packages, dpkg-deb and dependencies are needed.

No admin permissions are needed to build the package.

By default the resulting package:

  • Will install the application to /opt

  • Will add a shortcut to the application menu

  • Does not have any UI for installation (normal behavior for Linux packages)

Customization tips:

  • To place the application into a specific category in the application menu, use the category attribute of <fx:info>.

    Refer to Desktop Menu Specification and your window manager docs for the list of category names.

  • The icon is expected to be a .png file

  • Advanced customization is possible by tuning the build template files using techniques from Section 6.3.3, 'Customization Using Drop-In Resources.'.

    Consult the DEB/RPM packaging guides to get more background on available options.

6.5 Working Through a Deployment Scenario

Consider following scenario. You have a JavaFX application that:

  • Uses several third-party libraries

  • One of the third-party libraries uses JNI and loads a platform-specific native library using System.loadLibrary()

  • Needs a large 1Gb heap

How do you package it as a self-contained application that does not need admin permissions to install?

It is assumed that your application works fine as a standalone, that the main JAR file is built in the dist folder (using <fx:jar>) and that third-party libraries are copied to the dist/lib directory.

One way to assemble a self-contained application package is shown in Example 6-8. The approach is:

  • Include all application JAR files.

  • Add native libraries applicable to current platform as resources of type data.

    Ensure that the fileset base directory is set to the folder containing the library. This ensures that the libraries are copied to the top-level application folder.

  • Request a user-level installation with <fx:preferences install='false'/>

Gradle Package As Mac App Free

Note that the top-level application folder is added to the library search path, and therefore System.loadLibrary() will work fine.

Gradle Package Task

Example 6-8 shows an example <fx:deploy> task.