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
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 theversion
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
and2.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 example1.1-alpha < 1.1.0
. - When comparing
prerelease
data, compare each of the dot-separated elements individually. Thenumber
values are compared numerically andidentifier
values are compared as strings. Anumber
value is always less than aidentifier
value. For example1.0.0-alpha < 1.0.0-beta
,2.1-134 > 2.1.0-99
and1.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 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 (
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
, orwhen
properties. Versions before 2024.3 don't support theaccept
property. -
Array package selector (type
allOf
oroneOf
) – 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