この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
CX事業本部の平内(SIN)です。
Amazon AlexaのAPLを構成するTouchWrapperコンポーネントは、1つの子コンポーネントをラップして、タッチイベントを取得します。Alexaで音声以外のイベントを処理するためには、TouchWrapperコンポーネントが必須です。
今回は、TouchWrapperコンポーネントの使い方について、確認してみたいと思います。
2 単一コンポーネント
下記の例は、30vw*20vwのボタンを画面の中央に配置したものです。ちょっと分かりやすいように、TouchWrapperコンポーネントをFrameコンポーネントの中に配置しています。タッチされた際に、SendEventが 発生します。
{
"type": "APL",
"version": "1.1",
"settings": {},
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"commands": {},
"layouts": {},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"alignItems": "center",
"justifyContent": "center",
"item": [
{
"type": "Frame",
"item": {
"type": "TouchWrapper",
"onPress": [
{
"type": "SendEvent",
"arguments": [
"button"
]
}
],
"items": [
{
"type": "Text",
"width": "30vw",
"height": "20vh",
"textAlign": "center",
"textAlignVertical": "center",
"text": "Button"
}
]
},
"backgroundColor": "#006600",
"borderColor": "#00ff00",
"borderWidth": "4"
}
]
}
]
}
}
3 イベント処理
先のドキュメントが表示された画面で、TouchWrapperコンポーネントをタップすると、Alexa.Presentation.APL.UserEventリクエストがスキルに送られます。
UserEventリクエストのプロパティは以下のとおりです。
- type リクエストタイプ Alexa.Presentation.APL.UserEvent
- token トークン
- arguments SendEventから送られた値
- source 発生元コンポーネント
- components コンポーネントの情報
source.typeで、TouchWrapperコンポーネントからのイベントであることが分かり、argumentsの値を見ることで、対象コンポーネントを判定することができます。
"request": {
"type": "Alexa.Presentation.APL.UserEvent",
"requestId": "amzn1.echo-api.request.xxxxxxxxx",
"timestamp": "2019-07-19T06:49:48Z",
"locale": "ja-JP",
"arguments": [
"button"
],
"components": {},
"source": {
"type": "TouchWrapper",
"handler": "Press",
"id": "",
"value": false
},
"token": "xxxxxx"
}
スキル側でこのイベントを処理するとしたら、下記のようなハンドラになるでしょう。
const TouchEventHandler = {
canHandle(h: Alexa.HandlerInput) {
const request = h.requestEnvelope.request;
return ((request.type === 'Alexa.Presentation.APL.UserEvent' &&
(request.source.handler === 'Press' || request.source.handler === 'onPress')));
},
handle(h: Alexa.HandlerInput) {
const request = h.requestEnvelope.request;
if (request.type === 'Alexa.Presentation.APL.UserEvent') {
if (request.arguments) {
// request.arguments[0]には、"button"が入っている
const speechText = `${request.arguments[0]} がタップされました。`
return h.responseBuilder
.speak(speechText)
.withShouldEndSession(true)
.getResponse();
}
}
throw new Error("error");
}
};
3 複数コンポーネント
Containerコンポーネント若しくは、Sequenceコンポネントの子としてTouchWrapperコンポーネントを使用すると、結果的に列挙されるデータ数分のコンポーネントのイベントを取得することができます。
下記の例は、30vw*20vwのボタンをContainerコンポーネントの子として配置したものです。ちょっと分かりやすいように、TouchWrapperコンポーネントをFrameコンポーネントの中に配置しています。
タッチされたのが、何番目のコンポーネントかを取得するためには、SendEventのargumentsに "${data.text}" のような変数を指定する必要があります。
const mainDocument = {
"type": "APL",
"version": "1.1",
"settings": {},
"theme": "dark",
"import": [],
"resources": [],
"styles": {},
"onMount": [],
"graphics": {},
"commands": {},
"layouts": {},
"mainTemplate": {
"parameters": [
"payload"
],
"items": [
{
"type": "Container",
"height": "100vh",
"data": [
{
"text": "Button001"
},
{
"text": "Button002"
},
{
"text": "Button003"
},
{
"text": "Button004"
},
{
"text": "Button005"
},
{
"text": "Button006"
},
{
"text": "Button007"
}
],
"alignItems": "center",
"items": [
{
"type": "Frame",
"backgroundColor": "#006600",
"borderColor": "#00ff00",
"borderWidth": "4",
"item": {
"type": "TouchWrapper",
"onPress": [
{
"type": "SendEvent",
"arguments": [
"${data.text}"
]
}
],
"item": {
"type": "Text",
"width": "30vw",
"height": "20vh",
"textAlign": "center",
"textAlignVertical": "center",
"text": "${data.text}"
}
}
}
]
}
]
}
}
5番目のボタンをタップした時にスキルに送られるクリエスとは、次のとおりです。
argumentsに "${data.text}" の内容が入っていることが分かります。ちなみに、source.idで、何番目のコンポーネントかを取得することはできません。
"request": {
"type": "Alexa.Presentation.APL.UserEvent",
"requestId": "amzn1.echo-api.request.xxxxxxxxx",
"timestamp": "2019-07-24T06:14:46Z",
"locale": "ja-JP",
"arguments": [
"Button005"
],
"components": {},
"source": {
"type": "TouchWrapper",
"handler": "Press",
"id": ""
},
"token": "token"
}
4 最後に
今回は、TouchWrapperコンポーネントについて確認してみました。
Sequenceコンポーネントや、Containerコンポーネントの中で利用することで、リストの選択が簡単に実現できます。
ちなみに、TouchWrapperコンポーネントの中に、Containerコンポーネント等を配置することも可能ですが、argumentsで区別できないため、リスト等の選択には利用できません。