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 |
|---|---|---|---|
|
|
String |
|
A range of accepted package versions. Supported in APL 2024.3 and later. |
|
|
String |
REQUIRED |
The name of the import. |
|
|
URL |
— |
When provided, a URL from which to download the package. |
|
|
String |
REQUIRED |
The version of the import. |
Packages use one of two mechanisms to download.
- When you provide the
sourceproperty, the document downloads the package from the specified source URL. - When you don't provide the
sourceproperty, 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
buildinformation in theversionis 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.3and2.0.0 > 1.99.999-alpha.44. - If the major, minor, and patch numbers match, a version with a
prereleaseis always before one without. For example1.1-alpha < 1.1.0. - When comparing
prereleasedata, compare each of the dot-separated elements individually. Thenumbervalues are compared numerically andidentifiervalues are compared as strings. Anumbervalue is always less than aidentifiervalue. For example1.0.0-alpha < 1.0.0-beta,2.1-134 > 2.1.0-99and1.3.2-alpha.23425 < 1.3.2-alpha.b16. - If the two
prereleaseelement lists match but are of different lengths, the short list comes first. For example2.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.
simple_range operations with AND and OR clauses.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 (
packagetype) – 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, orwhenproperties. Versions before 2024.3 don't support theacceptproperty. -
Array package selector (type
allOforoneOf) – 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 |
|---|---|---|---|
|
|
String |
|
Package |
|
|
Array |
[] |
The list of the import names this import should load after. (APL 2023.3 and later). |
|
|
String |
REQUIRED |
Package |
|
|
URL |
— |
Optional package |
|
|
String |
|
Polymorphic type property. Set to |
|
|
String |
REQUIRED |
Package |
|
|
Boolean |
|
When |
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 |
|---|---|---|---|
|
|
String |
|
Package |
|
|
Array |
REQUIRED |
Array of package selectors. |
|
|
Array |
[] |
The list of the import names this import should load after. |
|
|
String |
— |
Package |
|
|
Array |
[] |
Array of packages to process if none were selected from |
|
|
String |
One of: |
Polymorphic type property. |
|
|
String |
— |
Package |
|
|
Boolean |
|
When |
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"
}
]
}
Related topics
Last updated: Dec 18, 2024