目次
はじめに
ディスプレイを持つAlexaデバイスに、視覚エクスペリエンスを提供するAPLドキュメントについて、その基本構造を解き明かし、ドキュメント内のどこに何を定義すれば良いのか、サンプル画面を例にステップバイステップで解説します。
APLドキュメントの基本構成
APLドキュメントは、デバイスに表示する画面構成を定義したものです。本稿では下記のような基本構造を持つAPLドキュメントに対して、各構成要素の仕様や使い方について説明します。APLドキュメントには、この他にもキーボードハンドラなど幾つかの定義ができますが、本稿では画面表示に関係の深いものに絞って、説明するものとします。
{
"type": "APL",
"version": "1.6",
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"layouts": {},
"mainTemplate": {}
}
バージョン1 – ベタ書き
下図のように、メッセージを一組だけ表示する、APLドキュメントを定義します。
この画面を表示するAPLドキュメントの定義を下記に示します。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"layouts": {},
"mainTemplate": {
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "タイトル1",
"fontSize": "20dp",
"color": "red"
},
{
"type": "Text",
"text": "メッセージ1",
"fontSize": "60dp",
"color": "yellow"
}
]
}
]
}
}
表示内容は、mainTemplateに定義されています。タイトルとメッセージを表示するために、2つのTextコンポーネントがあり、それらをContainerコンポーネントの中に入れています。Containerコンポーネントは、2つのTextコンポーネントの配置を調整してくれます。
バージョン2 – レイアウトによる部品化
ここではmainTemplateの中に直接定義していた、2行のテキスト表示を行うコンポーネントを、レイアウトとして部品化します。レイアウトは複数のコンポーネントを組み合わせた複合的なコンポーネントです。またレイアウトには、他のレイアウトを含めることもできます。部品化することで、再利用性を高めることが期待できます。
レイアウトはAPLドキュメントのlayoutsセクションに定義します。下記ではTextMessageという名前で、レイアウトを定義しています。内容はバージョン1でmainTemplateに定義したものを、そのまま移動した形になっています。(mainTemplate自身もレイアウトです。APIドキュメントの最上位のレイアウト (コンポーネント) と位置づけられています)
"layouts": {
"TextMessage": {
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "タイトル1",
"fontSize": "20dp",
"color": "red"
},
{
"type": "Text",
"text": "メッセージ1",
"fontSize": "60dp",
"color": "yellow"
}
]
}
]
}
}
mainTemplateでは、このTextMessageを使って実際に表示する画面を定義します。せっかく部品化したので、2つ表示するようにしてみました。
"mainTemplate": {
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage"
},
{
"type": "TextMessage"
}
]
}
]
}
このAPLドキュメントを表示すると下図のようになります。
このバージョンのAPLドキュメントの全体定義を下記に示します。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"layouts": {
"TextMessage": {
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "タイトル1",
"fontSize": "20dp",
"color": "red"
},
{
"type": "Text",
"text": "メッセージ1",
"fontSize": "60dp",
"color": "yellow"
}
]
}
]
}
},
"mainTemplate": {
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage"
},
{
"type": "TextMessage"
}
]
}
]
}
}
本当に再利用の効果が大きいのは、複数のAPLドキュメントでの再利用です。これはレイアウトを別ファイルに出してパッケージ化し、APLドキュメントにインポートすることで実現できます。
パッケージ化については下記の記事に記載しました。
「同じテキストを2回表示するだけなら、部品化しても意味ないのでは?」「というか、バージョン1の時点でテキスト固定は拙くない?」そんなツッコミが聞こえてきそうです。
次は表示テキストをパラメータ化して、2つのTextMessageに異なるメッセージを表示してみます。
バージョン3 – パラメータ化
TextMessageレイアウトの表示するテキストは、その中のTextコンポーネントのtextプロパティに設定されています。このtextプロパティに外部からアクセスして、直接テキストを書き換えることはできません。しかしTextMessageレイアウトにパラメータを定義すると、そのパラメータを通してTextコンポーネントのtextプロパティを、変更することができます。
パラメータの定義例を下記に示します。
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"fontSize": "20dp",
"color": "red"
},
{
"type": "Text",
"text": "${message}",
"fontSize": "60dp",
"color": "yellow"
}
]
}
]
}
ここではtitle, messageという2つのパラメータを定義しています。またそれらをTextコンポーネントで${title}, ${message}として参照しています。
これらのパラメータの値は、mainTemplateの中でTextMessageレイアウトのプロパティとして設定します。
"mainTemplate": {
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "タイトル1",
"message": "メッセージ1"
},
{
"type": "TextMessage",
"title": "タイトル2",
"message": "メッセージ2"
}
]
}
]
}
この例のように繰り返し表示するものが2個だけならば、決め打ちで定義しても良いですが、たくさん表示させる場合、または可変個のものを表示させる場合は、Sequenceコンポーネントが使えます。画面に収まらないときは、スクロールさせるなど柔軟な表示ができます。
このバージョンのAPLドキュメントの全体定義を下記に示します。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"fontSize": "20dp",
"color": "red"
},
{
"type": "Text",
"text": "${message}",
"fontSize": "60dp",
"color": "yellow"
}
]
}
]
}
},
"mainTemplate": {
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "タイトル1",
"message": "メッセージ1"
},
{
"type": "TextMessage",
"title": "タイトル2",
"message": "メッセージ2"
}
]
}
]
}
}
バージョン4 - パラメータのスキルからの変更
実際のスキルでは、titleやmessageはスキルで定義したものを、動的に表示したい場合が多いと思います。これはスキルから渡されたデータソースを、APLドキュメントにバインドすることで、実現できます。この方法について説明します。
まずスキル側のリクエストハンドラでは、下記のようなコードでAPLディレクティブを、レスポンスとして送り返します。
// Request Handler
return inputHandler.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
token: 'XyzRequest',
document: aplDocument,
datasources: datasources
});
documentにはAPLドキュメント、datasourcesにはAPLドキュメントに渡すデータを設定します。ここで定義しているAPLドキュメントの場合は、datasourcesは下記のように定義できます。
{
"data": {
"title1": "タイトル1",
"message1": "メッセージ1",
"title2": "タイトル2",
"message2": "メッセージ2"
}
}
このデータソースの内容を、APLドキュメントに反映するには、下記のようにmainTemplateにパラメータを定義し、データソースとバインドします。
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "${payload.data.title1}",
"message": "${payload.data.message1}"
},
{
"type": "TextMessage",
"title": "${payload.data.title2}",
"message": "${payload.data.message2}"
}
]
}
]
}
パラメータのpayloadはマジックワードで (?)、この識別子があるとスキルから渡されたデータソースとバインドされます。APLのサンプルの多くでpayloadが使われています。しかしpayloadではなくデータソースの名前を直接書くこともできます。
"mainTemplate": {
"parameters": [
"data"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "${data.title1}",
"message": "${data.message1}"
},
{
"type": "TextMessage",
"title": "${data.title2}",
"message": "${data.message2}"
}
]
}
]
}
もしデータソースに複数のデータソースが含まれている場合は、パラメータにデータソース名を複数指定することになります。
このバージョンのAPLドキュメントの全体定義を下記に示します。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"fontSize": "20dp",
"color": "red"
},
{
"type": "Text",
"text": "${message}",
"fontSize": "60dp",
"color": "yellow"
}
]
}
]
}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "${payload.data.title1}",
"message": "${payload.data.message1}"
},
{
"type": "TextMessage",
"title": "${payload.data.title2}",
"message": "${payload.data.message2}"
}
]
}
]
}
}
バージョン5 – リソースによる構成定義
Textコンポーネントには、textの他にfontSizeやcolorも設定されています。これらもパラメータ化して、スキルから変更することもできます。しかしtextと違って、これらは固定で良い場合もあります。その場合、プログラムコードであれば定数として定義して、それを使い回すところです。
同様のことがAPLドキュメントでもできます。resourcesセクションに定数相当のものを定義できます。ただしresourcesセクションでは、定義できるものの種類が決まっています。下記にfontSizeとcolorを定義した例を示します。
"resources": [
{
"dimensions": {
"titleFontSize": "20dp",
"messageFontSize": "60dp"
},
"colors": {
"titleColor": "red",
"messageColor": "yellow"
}
}
]
このリソースの定義を、下記のようにレイアウトの中で参照します。リソースで定義したものは、@マークを付けることで参照できます。
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"fontSize": "@titleFontSize",
"color": "@titleColor"
},
{
"type": "Text",
"text": "${message}",
"fontSize": "@messageFontSize",
"color": "@messageColor"
}
]
}
]
}
このバージョンのAPLドキュメントの全体定義を下記に示します。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "dark",
"import": [],
"resources": [
{
"dimension": {
"titleFontSize": "20dp",
"messageFontSize": "60dp"
},
"colors": {
"titleColor": "red",
"messageColor": "yellow"
}
}
],
"styles": {},
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"fontSize": "@titleFontSize",
"color": "@titleColor"
},
{
"type": "Text",
"text": "${message}",
"fontSize": "@messageFontSize",
"color": "@messageColor"
}
]
}
]
}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "${payload.data.title1}",
"message": "${payload.data.message1}"
},
{
"type": "TextMessage",
"title": "${payload.data.title2}",
"message": "${payload.data.message2}"
}
]
}
]
}
}
バージョン6 – スタイルの設定
バージョン5では、フォントのサイズと色をリソースに定義しました。これらを定義するもう一つの方法がスタイル定義です。スタイルは、コンポーネントのルック&フィールに関わる幾つかのプロパティを、まとめて定義できます。ただし対象となるコンポーネントとプロパティは、予め決まっています。TextコンポーネントのfontSizeとcolorはその対象になります。
スタイルの定義を下記に示します。ここではタイトルとメッセージの表示スタイルを、titleStyle, messageStyleとして定義しています。
"styles": {
"titleStyle": {
"values": [
{
"fontSize": "20dp",
"color": "red"
}
]
},
"messageStyle": {
"values": [
{
"fontSize": "60dp",
"color": "yellow"
}
]
}
}
スタイルの定義をレイアウトの中で参照して、下記のようにタイトルとメッセージの表示を定義しています。
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"style": "titleStyle"
},
{
"type": "Text",
"text": "${message}",
"style": "messageStyle"
}
]
}
]
}
}
このバージョンのAPLドキュメントの全体定義を下記に示します。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "dark",
"import": [],
"resources": [],
"styles": {
"titleStyle": {
"values": [
{
"fontSize": "20dp",
"color": "red"
}
]
},
"messageStyle": {
"values": [
{
"fontSize": "60dp",
"color": "yellow"
}
]
}
},
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"style": "titleStyle"
},
{
"type": "Text",
"text": "${message}",
"style": "messageStyle"
}
]
}
]
}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "${payload.data.title1}",
"message": "${payload.data.message1}"
},
{
"type": "TextMessage",
"title": "${payload.data.title2}",
"message": "${payload.data.message2}"
}
]
}
]
}
}
バージョン7 – 条件付きの設定
最近のOSやアプリケーションは、ダークモードをサポートしているものが増えています。バージョン6で定義したAPLドキュメントにも、themeというプロパティが定義されていて、デフォルトではdarkとなっています。これをlightに変えてみます。
{
"type": "APL",
"version": "1.6",
"theme": "light",
...
}
このAPLドキュメントを表示すると下図のようになります。
白背景なのでメッセージの黄色が見えにくいですね。このような場合、テーマに応じて文字の色を変更してやる必要があります。
バージョン6で定義したスタイルを変更して、テーマに応じて文字色を設定するようにします。対応したスタイル定義を下記に示します。messageStyleの定義に条件指定を入れています。
"styles": {
"titleStyle": {
"values": [
{
"fontSize": "20dp",
"color": "red"
}
]
},
"messageStyle": {
"values": [
{
"fontSize": "60dp",
"color": "${viewport.theme == 'dark' ? 'yellow' : 'blue'}"
}
]
}
}
viewport.themeで現在のテーマを確認できます。この値に応じてスタイルの文字色を指定しています。
このスタイルを適用したAPLドキュメントの表示結果を下記に示します。メッセージの文字色が青色となり、白背景でも見えるようになっています。
viewportは、APLドキュメント内で参照可能なデータの1つです。表示デバイスに関する情報を得ることができます。
テーマによる条件指定をバージョン6で定義したリソースにも適用してみます。
"resources": [
{
"dimension": {
"titleFontSize": "20dp",
"messageFontSize": "60dp"
}
},
{
"when": "${viewport.theme == 'dark'}",
"colors": {
"titleColor": "red",
"messageColor": "yellow"
}
},
{
"when": "${viewport.theme == 'light'}",
"colors": {
"titleColor": "red",
"messageColor": "blue"
}
}
]
ここではwhenを使ってcolorsの定義全体を切り替えています。この例では実際に変更されているのはmessageColorのみですが、複数の定義を一度に切り替える場合は、このwhenを使う方法は効率的です。
このバージョンのAPLドキュメントの全体定義を下記に示します。stylesとresourcesの両方の定義を残していますが、実際に使用しているのはstylesの定義のみです。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "light",
"import": [
{
"name": "alexa-layouts",
"version": "1.3.0"
}
],
"resources": [
{
"dimension": {
"titleFontSize": "20dp",
"messageFontSize": "60dp"
}
},
{
"when": "${viewport.theme == 'dark'}",
"colors": {
"titleColor": "red",
"messageColor": "yellow"
}
},
{
"when": "${viewport.theme == 'light'}",
"colors": {
"titleColor": "red",
"messageColor": "blue"
}
}
],
"styles": {
"titleStyle": {
"values": [
{
"fontSize": "20dp",
"color": "red"
}
]
},
"messageStyle": {
"values": [
{
"fontSize": "60dp",
"color": "${viewport.theme == 'dark' ? 'yellow' : 'blue'}"
}
]
}
},
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"style": "titleStyle"
},
{
"type": "Text",
"text": "${message}",
"style": "messageStyle"
}
]
}
]
}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "${payload.data.title1}",
"message": "${payload.data.message1}"
},
{
"type": "TextMessage",
"title": "${payload.data.title2}",
"message": "${payload.data.message2}"
}
]
}
]
}
}
バージョン8 – 標準パッケージの利用
APLドキュメントの構成要素について見てきましたが、最後の構成要素はインポートです。
APLには事前に定義されたパッケージがあり、それらをインポートすることで、APLドキュメントの定義に使うことができます。ここではスタイルパケージをインポートして、テキストの表示サイズに適用することにします。
"import": [
{
"name": "alexa-styles",
"version": "1.2.0"
}
]
スタイルパッケージに定義されたフォントサイズを使って、バージョン6で定義したスタイルを再定義します。
"styles": {
"titleStyle": {
"values": [
{
"fontSize": "@fontSize2XSmall",
"color": "red"
}
]
},
"messageStyle": {
"values": [
{
"fontSize": "@fontSize2XLarge",
"color": "${viewport.theme == 'dark' ? 'yellow' : 'blue'}"
}
]
}
},
fontSize2XSmall, fontSize2XLargeで、タイトルとメッセージのフォントサイズを定義しています。これらの値は、表示されるデバイスのviewportのサイズに応じて調整されます。このスタイルを適用した画面表示を下記に示します。
このバージョンのAPLドキュメントの全体定義を下記に示します。
APLドキュメント (↓)
{
"type": "APL",
"version": "1.6",
"license": "",
"theme": "light",
"import": [
{
"name": "alexa-styles",
"version": "1.2.0"
}
],
"resources": [],
"styles": {
"titleStyle": {
"values": [
{
"fontSize": "@fontSize2XSmall",
"color": "red"
}
]
},
"messageStyle": {
"values": [
{
"fontSize": "@fontSize2XLarge",
"color": "${viewport.theme == 'dark' ? 'yellow' : 'blue'}"
}
]
}
},
"layouts": {
"TextMessage": {
"parameters": [
{
"name": "title",
"type": "string"
},
{
"name": "message",
"type": "string"
}
],
"items": [
{
"type": "Container",
"items": [
{
"type": "Text",
"text": "${title}",
"style": "titleStyle"
},
{
"type": "Text",
"text": "${message}",
"style": "messageStyle"
}
]
}
]
}
},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"items": [
{
"type": "TextMessage",
"title": "${payload.data.title1}",
"message": "${payload.data.message1}"
},
{
"type": "TextMessage",
"title": "${payload.data.title2}",
"message": "${payload.data.message2}"
}
]
}
]
}
}
スタイルの他にも下記のパッケージが利用可能です。
- alexa-layouts
- alexa-viewport-profiles
スタイルパッケージも含めて、これらのパッケージには、さまざまなデバイスに対応するAPLドキュメントの作成に有用な、レイアウト、コンポーネント、スタイル、デバイス情報などが定義されています。
これらのパッケージのインポート定義を下記に示します。バージョンは本稿執筆時点のものなので、最新のものを確認してください。
"import": [
{
"name": "alexa-layouts",
"version": "1.3.0"
},
{
"name": "alexa-viewport-profiles",
"version": "1.2.0"
}
]
レスポンシブなAPLドキュメント
さまざまなデバイスに対応するAPLドキュメントは、レスポンシブ対応APLドキュメントと呼ばれます。Alexaのサポートするデバイスは多様になっており、それぞれのデバイスでベストなユーザーエクスペリエンスを提供することは、かなりチャレンジングな取り組みになるのではと思います。
ここで紹介した標準パッケージは、レスポンシブに対応したものを多く提供していて、それらを利用することが、レスポンシブなユーザーエクスペリエンス実現への近道になります。(と言い切れるほど、筆者はレスポンシブに詳しい訳ではありませんが …)
おわりに
APLには様々な画面表示に対応した、多くのテンプレートやサンプルが用意されています。それらを使用すれば、APLドキュメントをゼロから作ることは、あまり無いと思います。テンプレートのパラメータを調整したり、サンプルに1つ2つのコンポーネントを追加したり、そういった程度の作業であれば、試行錯誤しながらでもなんとかなりそうです。
しかし大規模なカスタマイズを行おうとしたり、サンプルに無いインタフェースを実現しようとすると、やはりAPLドキュメントの構造や仕様を理解していないと、試行錯誤では難しいように思います。少なくとも筆者はその点で苦労したことから、これまでに得られた知見を、APLドキュメントの基本構成やその仕様に絞ってまとめてみました。
変更履歴
日付 | 内容 |
2021/07/04 | 初版公開 |