APL Package


An Alexa Presentation Language (APL) package is a container for layouts, resources, and styles that you can import into your APL documents. An APL package is a single JSON file that follows the APL document structure. The package doesn't use the mainTemplate property, although including this property doesn't invalidate the package.

For an example of creating your own package and hosting it for use in your document, see Host Layouts, Graphics, and Other Resources in an APL Package.

The Alexa Design System for APL provides a set of packages you can use for styles and pre-built layouts. For details, see Alexa Design System for APL.

Package reference

A package reference is a data record that defines the name of a package, the desired version, and optionally the source of the package. You use a package reference when you define the list of packages to import into a document, or when you define the package to import with the ImportPackage command.

A basic package reference has the properties shown in the following table.

Property Type Default Description

accept

String

version

A range of accepted package versions. Supported in APL 2024.3 and later.

name

String

REQUIRED

The name of the import.

source

URL

When provided, a URL from which to download the package.

version

String

REQUIRED

The version of the import.

Packages use one of two mechanisms to download.

  • When you provide the source property, the document downloads the package from the specified source URL.
  • When you don't provide the source property, the document retrieves the package from an Alexa-supported central repository of packages, using the package name and version properties. For the current set of Amazon-provided packages, see Alexa Design System for APL.

The resources, styles, and layouts defined in packages are accessible from the current package.

The device runtime software caches packages. The device considers that two packages are identical if their name and version properties match, even if they have specified different source properties. The Time to Live (TTL) of a package is determined by the TTL received during download. As you develop and test a package, assign it a unique pre-release or build tag each time you modify the package. This forces the runtime to reload the new version of the package rather than using the cached version during testing.

accept

accept requires APL 2024.3 or later. Provide an alternate experience for devices running older versions of APL.

Specifies a version range that's acceptable for this package. An APL runtime might already have a copy of the package you request, but with a different version number. That package is used instead of loading a new copy if the package version number matches the accept version range.

The accept syntax is a simplified version of the normal range syntax used to match semantic patterns. Each simple_range is an operator and a single semantic version, for example: >=1.1.3. Multiple simple_range patterns are separated by spaces and combined with a Boolean "and" operation. An explicit Boolean "or" operation allows for disjoint ranges.

Here are some examples of common accept criteria:

>=1.1.3 <1.2.3      # Greater than or equal to 1.1.3 and less than 1.2.3
>=1.4.0 <2.0        # Anything 1.4.0 or higher as long as the major number is 1.
>=1.1.0-0 <1.1.0    # Anything that's 1.1.0 with at least one prerelease element

Package order comparison follows the standard semantic rules:

  • The build information in the version is ignored. For example, 1.3.2+alpha.6 == 1.3.2.
  • The first three digits in the version (the major, minor, and patch numbers) are compared numerically. For example 1.2 < 1.4.3 and 2.0.0 > 1.99.999-alpha.44.
  • If the major, minor, and patch numbers match, a version with a prerelease is always before one without. For example 1.1-alpha < 1.1.0.
  • When comparing prerelease data, compare each of the dot-separated elements individually. The number values are compared numerically and identifier values are compared as strings. A number value is always less than a identifier value. For example 1.0.0-alpha < 1.0.0-beta, 2.1-134 > 2.1.0-99 and 1.3.2-alpha.23425 < 1.3.2-alpha.b16.
  • If the two prerelease element lists match but are of different lengths, the short list comes first. For example 2.1.0-alpha.16.beta < 2.1.0-alpha.16.beta.2.

Semantic versions with prerelease values match only when the range explicitly has a simple_range with matching major, minor, and patch versions and a prerelease tag. For example:

Packages: 2.0.3, 2.1.0-alpha.1, 2.1.0-beta.1, 2.1.1-beta.1, 2.1.1

>2                          =>  2.0.3, 2.1.1
>2.1.0-beta                 =>  2.1.0-beta.1, 2.1.1
>2 || >2.1.0-a              =>  2.0.3, 2.1.0-alpha.1, 2.1.0-beta.1, 2.1.1
>2 <2.1.1 || 2.1.1-beta.1   =>  2.0.3, 2.1.1-beta.1

The accept property supports the following grammar:

accept       ::=  and_list ( ws* "||" ws* and_list )*
and_list     ::=  simple_range ( ws+ simple_range )*
simple_range ::=  ( "<" | ">" | "<=" | ">=" | "=" )? version
ws           ::=  [ \n\t\f]

The version property is defined in the version property grammar. When the accept property isn't set, the package version property must match exactly.

name

Package names follow the pattern [a-zA-Z][a-zA-Z0-9-]*.

source

The source property, when specified, provides the URL location from which to download the package. When not specified, Alexa retrieves the package from an Alexa-supported central repository. For the current set of Amazon-provided packages, see Alexa Design System for APL.

Use https instead of http for package source URLs. Many Alexa devices don't support the http scheme in skill APL documents for security reasons.

When you host your own APL packages on a site such as Amazon S3, be sure to enable Cross-Origin Resource Sharing for any APL resources hosted on an HTTPS endpoint. For more about creating and hosting your own package, see Host Layouts, Graphics, and Other Resources in an APL Package.

version

Package versions should follow the semantic versioning convention given by the following grammar:

vers         ::= <<release>> <<prerelease>>? <<build>>?
release      ::= <<number>> "." <<number>> "." <<number>>
prerelease   ::= "-" <<identifier>> ( "." <<identifier>> )*
build        ::= "+" <<identifier>> ( "." <<identifier>> )*
identifier   ::= [a-zA-Z0-9-]+
number       ::= [0-9] | [1-9][0-9]+

The release value is in the form MAJOR.MINOR.PATCH. When the MINOR or PATCH numbers are omitted, they're assumed to be 0. However, the best practice is to use the full MAJOR.MINOR.PATCH format to avoid potential implementation problems for package caches.

Examples of valid package versions include: 10.2.1, 0.1.10-beta.3, and 0.9.7-alpha2.17+build.1002

Package import list

APL documents and packages have an import property that defines the packages to load before the current document or property. The runtime system guarantees that the imported packages are loaded first; if they fail to load, the entire document fails.

Package imports form a directed dependency graph. Resource, style, and layout lookup is depth-first, following the package import order. For example, assume document A depends on packages B and C, and packages B and C depend on the package D. The search order for the definition of a resource is therefore A, B, C, and then D. This means that document A can override any of the resources, styles, or layouts defined in B, C, or D.

You can control package ordering with the loadAfter property if the dependency graph. In the previous example, the dependency graph doesn't specify an ordering between B and C. You can use the loadAfter property to enforce a specific order.

The import property supports data binding. Data-binding expressions within the import property can access the properties available in the initial data-binding context. For details, see [Initial data-binding context](../alexa-presentation-language/apl-data-binding-evaluation.html.

A basic package import list is an array of package references. The following example shows an import property for an APL document. The import specifies two packages, alexa-layouts and my-custom-stuff.

{
  "import": [
    {
      "name": "alexa-layouts",
      "version": "1.7.0"
    },
    {
      "name": "my-custom-stuff",
      "version": "1.1.0-alpha",
      "source": "https://example.com/packages/"
    }
  ]
}

After the document inflates, the environment packages property in the data-binding context contains an array of all the loaded packages. You can use this to help debug more complicated package loading operations.

To support more complicated imports, the import list supports the following additional options for specifying packages.

  • Rich package selector (package type) – Loads a single package and supports ordering that package relative to other packages.

    This syntax is equivalent to a package import in versions of APL before 2023.3. Versions before 2023.3 don't support the loadAfter, type, or when properties. Versions before 2024.3 don't support the accept property.

  • Array package selector (type allOf or oneOf) – Defines a list of package selectors and a predicate for loading either one or all of those selectors.

Rich package selector

A rich package selector conditional loads a single package and supports ordering that package load relative to other package loads. The rich package selector has the properties shown in the following table.

Property Type Required Description

accept

String

version

Package accept property. (APL 2024.3 and later).

loadAfter

Array

[]

The list of the import names this import should load after. (APL 2023.3 and later).

name

String

REQUIRED

Package name property.

source

URL

Optional package source property.

type

String

package

Polymorphic type property. Set to package to use the rich package selector. (APL 2023.3 and later)

version

String

REQUIRED

Package version property.

when

Boolean

true

When false, ignore this import. (APL 2023.3 and later)

The following example shows a fully-qualified package import with all properties defined. This example includes the type property, which isn't necessary because the type property defaults to package when not provide.

{
  "import": [
    {
      "type": "package",
      "when": "${viewport.mode == 'hub'}",
      "loadAfter": [
        "alexa-layouts"
      ],
      "name": "MyDisplayColors",
      "version": "1.2.2-release12",
      "source": "https://mycompany.com/packages"
    },
    {
      "name": "alexa-layouts",
      "version": "1.7.0"
    }
  ]
}

loadAfter

Identifies a set of imports after which this import loads in the same import block. Follows same pattern as name. This array lists the package names and doesn't specify package version. Therefore, the packages named in the array must be defined elsewhere in the import array.

Any cyclic dependencies cause the document processing to fail.

when

When true, include the package. When false, ignore this package.

The following example shows using when to override the default style with a custom one depending on the environment.

"import": [
  {
    "when": "${environment.overrideName && environment.overrideVersion}",
    "name": "${environment.overrideName + viewport.mode}",
    "version": "${environment.overrideVersion}",
    "loadAfter": "default-styles"
  },
  {
    "name": "default-styles",
    "version": "1.0"
  }
]

Array package selector

An array package selector defines a list of package selectors and a predicate for loading either one or all of those selectors. Array package selectors support the properties shown in the following table.

Property Type Default Description

accept

String

version

Package accept property.

items

Array

REQUIRED

Array of package selectors.

loadAfter

Array

[]

The list of the import names this import should load after.

name

String

Package name property.

otherwise

Array

[]

Array of packages to process if none were selected from items array.

type

String

One of: allOf, oneOf

Polymorphic type property.

version

String

Package version property.

when

Boolean

true

When false, ignore this import.

The allOf type imports all the packages in the items array. The oneOf type imports the first package in the items array where the when is true.

The accept, name, and version properties in an array package selector pass through to the underlying package selectors and used there if they're not specifically defined. This allows a more compact notation.

{
  "import": [
    {
      "type": "oneOf",
      "name": "my-layouts",
      "items": [
        {
          "when": "${viewport.type == 'hub'}",
          "version": "1.1.5",
          "accept": ">=1.1.5 <1.2"
        },
        {
          "version": "1.1.2"
        }
      ]
    }
  ]
}

The allOf type is useful to conditionally include multiple packages. The following example imports both the hub-styles and hub-overrides packages when the viewport.mode for the device is hub.

{
  "import": [
    {
      "type": "allOf",
      "when": "${viewport.mode == 'hub'}",
      "items": [
        {
          "name": "hub-styles",
          "version": "1.0"
        },
        {
          "name": "hub-overrides",
          "version": "1.0",
          "loadAfter": [ "hub-styles" ]
        }
      ]
    }
  ]
}

The oneOf array package selector is useful when keeping the same package name and version, but loading the package contents from a different source. In the following example, the document imports a package called styles from one of three different possible sources, depending on the value of viewport.mode.

{
  "import": [
    {
      "type": "oneOf",
      "name": "styles",
      "version": "1.0",
      "items": [
        {
          "when": "${viewport.mode == 'hub'}",
          "source": "https://styles.com/hub.json"
        },
        {
          "when": "${viewport.mode == 'tv'}",
          "source": "https://styles.com/tv.json"
        },
        {
          "source": "https://styles.com/generic.json"
        }
      ]
    }
  ]
}

The oneOf type supports a special otherwise array of packages to import if none of the imports in the items list are selected. This can be helpful as a guaranteed fallback in complicated nested package selectors.

{
  "import": [
    {
      "type": "oneOf",
      "name": "styles",
      "items": [
        {
          "when": "${viewport.mode == 'hub'}",
          "type": "oneOf",
          "version": "1.0",
          "items": [
            {
              "when": "${viewport.width > viewport.height}",
              "source": "https://styles.com/hub-landscape.json"
            },
            {
              "source": "https://styles.com/hub-portrait.json"
            }
          ]
        },
        {
          "when": "${viewport.mode == 'tv'}",
          "version": "1.0",
          "source": "https://styles.com/tv.json"
        }
      ],
      "otherwise": [
        {
          "source": "https://styles.com/generic.json"
        }
      ]
    },
    {
      "name": "overrides",
      "version": "1.0"
    }
  ]
}

Was this page helpful?

Last updated: Dec 18, 2024