Connect IQ SDK

Overriding Resources

Connect IQ supports a wide variety of Garmin devices, like watches, bike computers, and handhelds. Even within these broader categories, devices can have different screen sizes, shapes, and resolutions. Application developers may wish to define specific resources, like fonts and bitmap graphics, for certain devices or device families for a better user experience. For example, an app may need to use a round background image for round devices, but use a square background image for square devices. Connect IQ offers a few ways to manage app resources: device and family qualifiers, Jungles, and build exclusions.

Device, Family, and Localization Qualifiers

The simplest way to override resources is with device, family, and localization qualifiers, which are added to a resources folder by adding a hyphen (-) followed by a valid qualifier value. Let’s take a look at an example:

Figure 1: A project that uses a fēnix 5 device resource qualifier

Resource qualifiers are applied to the base resources folder, and all resources found within that folder will inherit the qualifiers of the base folder. Resources with more specific qualifiers will always take precedence over less specific ones if they share a resource ID.

In Figure 1, the resources-fenix5 directory uses a -fenix5 qualifier to segregate resources specifically intended for the fēnix 5. When this project is built for fēnix 5, the layout and drawable in the resources-fenix5 directory will be used to display a different background image than the one in the more generic resources directory. All other supported products will compile with the default resources.

Note: Multiple qualifiers separated by hyphens may be used on a single folder, but device qualifiers are not allowed to co-exist with family qualifiers in the same folder name (e.g. resources-round-fenix3) and will be skipped by the resource compiler if encountered.

Device Qualifiers

The device qualifier format allows for resources to target specific devices (as demonstrated in Figure 1). Resources included in a folder with a device qualifier will override the resources with the same ID that are defined in the base resource folder when building for the associated device. Device qualifiers also take precedence over less specific qualifiers, such as family qualifiers.

Family Qualifiers

The family qualifier format allows for resources to target specific device families, which is a group of devices differentiated by shared screen characteristics. There are two family qualifiers:

The screen shape must always be specified when using a family qualifier, and the screen size may be added to further refine the target family. Here are some examples of valid and invalid family qualifier examples:

Resources with more specific qualifiers will always take precedence over less specific ones, so on a round, 218px x 218px device, any resources contained in the resources-round-218x218 resources folder will be used in place of those in resources-round if they share an ID. In addition any resource folder that carries a family qualifier will always defer to resource folders named with device qualifiers.

Localization Qualifiers

Localization qualifiers are a way to specify language-specific string resources, and are specified as an ISO 639–2 language code. These qualifiers may be combined with either device or family qualifiers, and are always specified last in the qualifier naming scheme. For example:

Build Configuration via Jungles

Connect IQ runs on a diverse set of purpose built devices. Because of the variety of inputs, screen shapes, and resources, it often is necessary to include code and resources tailored to specific conditions. For example, on a square device a progress bar may be rectangular, but on a round device it might look better as an arc that orbits the screen.

Jungles allow developers to write custom build instructions for Monkey C projects. With Jungle files, developers may define per-device or per-device family paths to source and resource directories, exclude portions of source code with annotations, or specify Monkey Barrels that should be included when a project is built.

Lets say you are writing a wearable app that has different code for round, semi-round, and rectangle layouts. Jungles make it easy to manage project build configurations in one place:

# Configure paths based on screen shape
round.resourcePath = $(base.resourcePath);resource-round
semiround.resourcePath = $(base.resourcePath);resource-semiround
rectangle.resourcePath = $(base.resourcePath);resource-rectangle

These instructions tell round devices to use the resource-round, resource-semiround, and resource-rectangle paths for the round, semi-round, and rectangle the devices respectively. Barrels also use Jungles for their own build configuration, allowing them to have a separate build configuration from the parent project.

The Default Jungle File

The Connect IQ SDK includes a default Jungle file, which is always applied to projects even if no custom Jungle files are present. It defines a base qualifier, which represents all source files (.mc) contained in the project, and all resource files found in the resources at the root of a Connect IQ project. It also defines default device, family, and location qualifiers that are the basis for the qualifier scheme described in the previous section.

When a project is built, the instructions from the default Jungle file are applied first, then any instructions from custom Jungle files are applied. This makes it possible for customizations to override the default build instructions.

Jungle Syntax

Jungle files contain build instructions that are made up of qualifiers, local variables, and values. Jungle files may also contain comments.

Build Instructions
Instructions are made up of qualifier-value or variable-value pairs separated by an equal sign (=), and terminate with a new line character.
Qualifiers are analogous to the device and family qualifiers described in the previous section. They are treated as reserved words, can only be set equal to other qualifiers, and are globally scoped. Qualifiers and their properties can be used with the dereference operator $(VAR) and are evaluated after all Jungle files for a project have been processed.

Qualifiers have six properties that can be referenced by following a qualifier with a dot (.) and a property name:

Local Variables
Variables are a convenient way of re-using values, such as long path strings. Unlike qualifiers, local variables have no properties, cannot be set equal to a qualifier, and are locally scoped. Variables can be used with the dereference operator $(VAR) and are evaluated after the Jungle file in which they are defined has been processed.
Values are a list of one or more string values that represent the value of a particular qualifier, qualifier property, or local variable. Multiple list items are separated by semicolons (;).
Lines preceded with a hash mark (#) are treated as comments and are ignored by the compiler.

A basic Jungle file build instruction will use this pattern (comments are optional):

# This is a comment
qualifier[.property] = value

Jungle files must be named with a .jungle extension, and are kept in the root of the Connect IQ project.

Note: Dereferenced qualifiers are evaluated “lazily”, which means that when building for a specific device, all qualifiers and properties are resolved for that device after all Jungle files are processed, while local variables will be resolved after processing the Jungle files in which they are defined. The exception to lazy evaluation is when a qualifier or local variable is dereferenced when setting that qualifier or variable, in which case the qualifier or variable is evaluated during Jungle file processing.

Sources and Resources

Setting source and resource paths are a common use for Jungles. In addition to tailoring source code and resources to particular devices to improve user experience, it can also help with memory management since only the sources defined in the Jungle file are compiled into the executable.

As a practical example, assume an application will use a shared set of resources for fēnix devices contained in a fenix-resources directory at the root of the project. Since these products are not all in the same families, a custom Jungle file must be written to tell the compiler these devices should use this shared resources folder. We can start by setting the resource path for fēnix 5:

# Set the fenix 5 resource directory
fenix5.resourcePath = $(fenix5.resourcePath);fenix-resources

Let’s break this down a little:

The device qualifier for the fēnix 5 defined in the default Jungle file followed by the resourcePath property
The original value of the fenix5.resourcePath property, accessed with the dereference operator $(VAR).

The default Jungle file defines the base resource path as the resource directory in the root of the project, and all devices inherit this. It also defines device-specific and family-specific resource directories that can be used implicitly in any project. Including this in the resource path ensures that the device can still look in these directories for resources if required resources aren’t found in more device-specific locations. If this is omitted, it would tell the compiler to only look for fenix 5 resources in the fenix-resources directory.

The shared directory we want to add as a resource location for the device.

If this looks familiar, it’s because it’s pretty similar in concept to setting PATH environment variables. Path precedence goes from left to right in Jungle files, so the compiler will process inherited resources first before processing resources found within ‘fenix-resources’, which can potentially override resources already defined. Adding the fenix-resources directory to other fēnix devices just requires similar instructions for each additional device:

# Set the fenix 5 resource locations
fenix5.resourcePath = $(fenix5.resourcePath);fenix-resources

# Set the fenix 3 resource locations
fenix3.resourcePath = $(fenix3.resourcePath);fenix-resources

Setting source paths works in essentially the same way, allowing apps to selectively include specific source code on a per-device or per-device family basis.

Localization Resources

Localization strings are a kind of resource in Connect IQ, but have a slightly different syntax since multiple languages may be supported by a single device or device family. Suppose an application supports both English and Spanish, and all of the fēnix English localization resources are stored in a fenix-resources-eng directory, while the Spanish localization resources are kept in a fenix-resources-spa directory.

# Set the fenix 5 English language resource location
fenix5.lang.eng = $(fenix5.lang.eng);fenix-resources-eng

# Set the fenix 5 Spanish language resource location = $(;fenix-resources-spa

# Set the fenix 3 English language resource location
fenix3.lang.eng = $(fenix3.lang.eng);fenix-resources-eng

# Set the fenix 3 Spanish language resource location = $(;fenix-resources-spa

The lang qualifier property is used in this build instruction to specify that a localization resource is being set, and is followed by an additional ISO 639–2 language code localization qualifier to indicate for which language the supplied resource locations are intended. A list of supported localization qualifiers can be found in the [Appendices][] chapter. Specifying an unsupported localization qualifier will result in an error at compile time.

When specifying localization resources within Jungle files, the supported languages must also be set in a project’s manifest, otherwise the associated localization overrides will be ignored.

Excluded Annotations

In some cases, there are specific modules, classes, methods, or variables that should only be used by a subset of devices, but excluding an entire source file is excessive. The excludedAnnotations qualifier property allows build instructions to specify specific [annotations][Annotations] that will be excluded when an application is built. This may help save memory during app execution on a device.

A common reason for excluding source is when an application uses one algorithm that takes advantage of the latest APIs on newer devices, but must use a simpler algorithm on older devices that don’t have the latest APIs available. For example, the following example shows an app that has two methods—one that uses the newer Sensor.AccelerometerData, and one that relies on Sensor.Info.accel data:

using Toybox.WatchUi;

class MyAmazingAppView extends WatchUi.View {

    function onUpdate(dc) {

        if (Toybox.Sensor has AccelerometerData) {
            // If a newer device, call this method
        } else {
            // If an older device, call this method

    newHotnessAlgorithm() {
        // Advanced functionality using Sensor.AccelerometerData

    oldAndBustedAlgorithm() {
        // Basic functionality using Sensor.Info.accel data

This will function properly as-is, but all of the code is included regardless of the build target. If the app is approaching memory limits, it may be useful to exclude the unused method, especially if the method is sufficiently large and impacts available memory. To do this, set the excludeAnnotations qualifier property in the Jungle file to the appropriate annotation value:

# Exclude the oldAndBustedAlgorithm() from fenix 5
fenix5.excludeAnnotations = older

Monkey Barrel Management

Eclipse provides tools to work with Monkey Barrels, but Barrels can also be added manually to the project’s main Jungle file using the barrelPath qualifier property:

# Include all the Barrels from the 'barrels' directory at the root of the project
base.barrelPath = barrels

# Include a specific Barrel from the 'barrels' directory
base.barrelPath = barrels/IconLibrary.barrel

# Include multiple, specific Barrels from the 'barrels' directory
base.barrelPath = barrels/IconLibrary.barrel;barrels/GraphLibrary.barrel

It’s also possible to use the annotations qualifier property to import select, annotated portions of a barrel. This is useful when a Barrel contains a library of classes and methods, but an application only needs to use a fragment of the library. For example, assume the GraphLibrary barrel imported above contains several different graphing methods, but an application only needs to use a bar graph. The Barrel author was kind enough to annotate each method, so rather than using the entire Barrel, we can limit imported code to only those methods that are needed:

# Import the 'bar' annotated method from the GraphLibrary Barrel
base.GraphLibrary.annotations = bar

In order for the compiler to correctly resolve Monkey Barrels, Barrel dependencies must also be added to the project’s manifest file:

    <iq:depends name="IconLibrary" version="0.0.0"/>

Once completed, the specified Barrels will be available for use in a project.

Defining Project Dependencies

What if a quick change is made to a developer’s barrel code in the development process of a dependant application? It would be cumbersome to [export a barrel][Exporting a Monkey Barrel] and update the dependencies in the manifest.xml every time the code is changed in the Barrel project. Connect IQ application projects can have direct Monkey Barrel project dependencies removing the need for these steps.

Adding a Barrel project dependency is done by specifying the Jungle file or files of the project or projects depended upon within the barrelPath. Jungle files can be specified individually or grouped in the barrelPath.

For example, a developer is creating an application, but she wants to include a standard set of icons that define her brand. She realizes in development that she needs to add a few more icons and decides to finally create that super specialized function that she is always needing. She can work dynamically on both projects and link her application project to her Barrel code by adding the Barrel project’s Jungle file to the barrePath like this:

# Include a specific Barrel project
base.barrelPath = MyIconBarrel/MyIconBarrel.jungle

Another developer is working on a math intensive application. Thankfully, someone has created an extensive MathLibrary Barrel that he has pulled in. He also has a local MyIconLibrary Barrel project with some standard icons. He has a set of icons for round devices defined in a roundIcons.jungle file that he wants to use in his application. He includes both the packaged MathLibrary.barrel and his own roundIcons defined in his local barrel project like this:

# Include a specific Barrel from the 'barrels' directory and a Jungle from a Barrel project
base.barrelPath = barrels/MathLibrary.barrel;MyIconBarrel/roundIcons.jungle

Our second developer realizes that he wants to support rectangle devices as well. These have been defined in a rectangleIcons.jungle. He includes multiple build instructions from MyIconBarrel by grouping the Jungle files in square brackets [] like this:

# Include a specific Barrel from the 'barrels' directory and multiple Jungles from a Barrel project
base.barrelPath = barrels/MathLibrary.barrel;[MyIconBarrel/roundIcons.jungle;MyIconBarrel/rectangleIcons.jungle]

Take a look at the Monkey Barrels chapter to learn more about Monkey Barrels and how they can be used.

Using Jungles in Eclipse Projects

The Connect IQ Eclipse plug-in makes a few features available for managing a Jungle file that is used in a particular project.

By default, each project is configured to look for a monkey.jungle file in the root of the project and will use it if it exists. However, if a project is organized differently or a different Jungle file name is preferred, the Jungle file location can be set easily in the project’s properties in Eclipse:

Figure 2: Specifying a project’s Jungle file in Eclipse

In addition, the Eclipse plug-in includes a Jungle file editor, which will open *.jungle files, and supports syntax highlighting for various Jungle elements. Jungle editor options, including customization of syntax colors, can be managed in the Eclipse preferences.

Figure 3: Setting the Jungle file editor options

Using Jungles from the Command Line

For those that prefer to use the monkeyc [shell command][Basic Commands] to build projects rather than Eclipse, the -f option is required and accepts a list of Jungle files, separated by semicolons (;):

monkeyc -o myApp.prg -d fenix5 -f monkey.jungle;monkey2.jungle

In lieu of this new option, the -z option to specify resource paths, the -x option to specify build exclusions, the -m option to specify the manifest file, and the ability to specify source paths have been deprecated and will be removed in a future SDK release. Here is a general description of how this will work:

The manifest file of the project must be specified within a Jungle file passed at the command line and any Jungle can contain this specification. Here is what it looks like:

project.manifest = manifest.xml

There can be only one[1] manifest file defined within the set of jungle files provided. When relative paths are used within a jungle file the path will be resolved against the Jungle file’s parent directory. Relative paths within the default.jungle are resolved against the parent directory of the manifest file that is found.

Note: Legacy projects using -m, -x, -z, and/or supplying source files at the command line will result in a compiler warning.

Build File Exclusions

The resource compiler also supports excluding files, directories or annotations as part of the build process using the <build> tag in an application’s resources XML files:

  <exclude file=""/>
  <exclude dir="source-excluded" />
  <exclude annotation="roundImpl"/>

The <build> tag can be defined in the resource directory of any device or family-based qualifier. Only the single most detailed and relevant <build> resource defined will be used when compiling an application. This feature is useful when adding specific files or features for one device or device family and not another, saving memory that would otherwise be wasted for non-shareable code.

Build exclusions provide a lot of the same capabilities as Jungle files, and will eventually be removed in a future Connect IQ release. If used in combination with a Jungle file, build exclusions will continue to work, but a warning will be generated indicating that they have been deprecated.

  1. When multiple manifests are found, one must destroy the other and absorb its power to become the strongest manifest.  ↩