Host Layouts, Graphics, and Other Resources in an APL Package
Define a set of reusable layouts, graphics, and other resources as an Alexa Presentation Language (APL) package. Host this package on the internet to use the resources in other APL documents. Packages are useful for sharing common items across multiple APL documents without duplicating your code and for simplifying and reducing the size of the code in your skill responses.
Define the package as an APL document
A package uses the same JSON structure as an APL document. A package can leave out the mainTemplate property. The package ignores the mainTemplate property if present. Define the items for the package in the top-level properties:
commandsextensionsgraphicslayoutsresourcesstyles
For example, you could define a set of layouts in the layouts property, and then use those layouts in other APL documents.
The following example shows a package that defines a layout called CircleWithText.
{
"type": "APL",
"version": "2024.3",
"import": [
{
"name": "alexa-styles",
"version": "1.6.0"
}
],
"layouts": {
"CircleWithText": {
"parameters": [
{
"name": "backgroundColor",
"default": "green"
},
{
"name": "textToDisplay",
"default": "Set text to show!"
}
],
"items": [
{
"type": "Frame",
"borderRadius": "@shapeCircle",
"width": "300dp",
"height": "300dp",
"backgroundColor": "${backgroundColor}",
"item": {
"type": "Text",
"width": "100%",
"height": "100%",
"padding": "@spacingSmall",
"text": "${textToDisplay}",
"textAlign": "center",
"textAlignVertical": "center"
}
}
]
}
}
}
Import other packages
Your package can import other packages. For example, you can create custom layouts that use the responsive components provided in the alexa-layouts package. Add the import to the import array, as you would when using the package in a standard APL document:
{
"import": [
{
"name": "alexa-layouts",
"version": "1.7.0"
}
]
}
The CircleWithText example shown earlier imports the alexa-styles package to use the spacing and border radius resources.
For details about how to define imports in the import array, see Package import list.
Export specific items
Use the export property to define which items you intend to use in other documents when you import your package. This property is useful when you define a layout using multiple "internal" layouts to make the code more modular, but you intend to use the final "public" version.
Tools such as the authoring tool use the export property to check a document for errors and present the exported items as available. However, the export property is informational. An APL document that imports the package can still access all the resources defined in the package, even when not included in export.
The following example shows a package with two layouts (the layout items are omitted for brevity):
- The
CircleWithTextlayout displays specified text within a circle. - The
ListOfCirclestakes an array of strings and displays a list ofCircleWithTextobjects. - The example specifically exports the
ListOfCircleslayout to indicate thatListOfCirclesis the layout to use.
When building a document in the authoring tool, using CircleWithText directly displays as an error to alert you that it isn't intended for use. However, APL still renders the layout.
{
"type": "APL",
"version": "2024.3",
"import": [
{
"name": "alexa-styles",
"version": "1.6.0"
}
],
"export": {
"layouts": [
{
"name": "ListOfCircles",
"description": "A list of circles; specify the text and background colors."
}
]
},
"layouts": {
"ListOfCircles": {
"parameters": [
{
"name": "textItems",
"type": "array"
},
{
"name": "defaultColor",
"type": "string",
"default": "purple"
}
],
"items": []
},
"CircleWithText": {
"parameters": [
{
"name": "backgroundColor",
"default": "green"
},
{
"name": "textToDisplay",
"default": "Set text to show!"
}
],
"items": []
}
}
}
Host the package
To use the package in other APL documents, you must host the JSON file publicly on the internet. You can use services such as Amazon Web Services (AWS) S3 to host your package. Your hosted package must meet the following requirements:
- The link to the JSON file must be fully public
- Cross-Origin Resource Sharing (CORS) for the host must allow
*.amazon.com - The JSON file must never expire
Make objects stored in Amazon S3 public
To make the link to your package public in Amazon S3, add a bucket policy to grant access. For details, see Setting permissions for website access.
Alternatively, you can use AWS CloudFront to make your package accessible, but restrict access to the direct S3 URL. See the following AWS resources:
- Getting started with a simple CloudFront distribution
- Restricting access to Amazon S3 content by using an origin access identity (OAI)
Configure an S3 CORS policy
The following CORS policy on an S3 bucket gives Alexa devices access to your package:
[
{
"AllowedHeaders": [],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*.amazon.com"
],
"ExposeHeaders": []
}
]
For more about configuring CORS for an S3 bucket, see Using cross-origin resource sharing (CORS).
Import your package into your document
To use your external package, import the package. Specify the public URL to the package in the source property. Set the version and name to strings that make sense for your package. These properties are required, but don't need to match the actual content of the package. For convenience, use a consistent naming convention. For example, use the name of your JSON file as the package name.
{
"import": [
{
"name": "circle-list",
"version": "1.0",
"source": "https://d111111abcdef8.cloudfront.net/circle-list.json"
}
]
}
You can import multiple packages. For example, if your document uses layouts from your custom package, as well as responsive components, import both your own package and alexa-layouts. You can also define conditions on imports to control which packages should be imported.
For details about how to define imports in the import array, see Package import list.
Package example
The following example shows an external package that defines a graphic imported from Lottie.
The following example shows how you could import this package and then use the graphic within an APL document. The CloudFront URL shown in this example is fictitious.
{
"type": "APL",
"version": "2024.3",
"import": [
{
"name": "my-lottie-graphics",
"version": "1.0",
"source": "https://d111111abcdef8.cloudfront.net/my-lottie-graphics.json"
}
],
"mainTemplate": {
"parameters": [
"payload"
],
"items": {
"type": "VectorGraphic",
"source": "blockTowerAnimation",
"width": "100%",
"height": "100%",
"scale": "best-fit",
"align": "center",
"frame": "${(elapsedTime*0.06)%360}"
}
}
}
Troubleshooting an external package
Issue: 403 Error trying to fetch package
Symptoms
The resources specified in the package aren't accessible to your APL document. The Authoring tool reports the error "Request failed with status code 403"
Try this
This error usually indicates that your link to the package URL isn't publicly accessible. Test the link in a browser and make sure you can see the content of the JSON file.
The steps to make your file publicly available depend on how you're hosting the package. For Amazon S3, consider using CloudFront to provide access to your resources. See the following:
- Getting started with a simple CloudFront distribution
- Restricting access to Amazon S3 content by using an origin access identity (OAI)
Issue: Unable to find resources
Symptoms
The package is publicly available, but the resources specified in the package aren't accessible to your APL document. For example, the authoring tool reports "Unable to find layout <layoutName>."
Try this
Make sure your uploaded package is a valid APL document. The APL document must be the top-level of the file and not within any other properties. Note that the authoring tool export feature saves the document, data sources, and sources in a single JSON file with document, datasources, and sources properties. This format isn't valid as an APL document.
For example, an exported APL document initially looks like the following:
{
"document": {
"type": "APL",
"version": "1.8",
"settings": {},
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"commands": {},
"layouts": {
"ListOfCircles": {},
"CircleWithText": {}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": []
}
},
"datasources": {},
"sources": {}
}
To make this a valid package, move the object assigned to the document property to the top level and delete the datasources and sources properties:
{
"type": "APL",
"version": "1.8",
"settings": {},
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"commands": {},
"layouts": {
"ListOfCircles": {},
"CircleWithText": {}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": []
}
}
Try this
Make sure you configured cross-origin resource sharing (CORS) to allow *.amazon.com.
When using Amazon S3 and Amazon CloudFront, see the following links for information about configuring CORS:
- Using cross-origin resource sharing (CORS)
- Troubleshooting CORS
- How do I resolve the "No 'Access-Control-Allow-Origin' header is present on the requested resource" error from CloudFront?
Related topics
Last updated: Dec 18, 2024