もうホントいまさらですが、ずっと食わず嫌いだったAlexaのマルチモーダル用言語『APL(Alexa Presentation Language)』をきちんとやって理解しようと思います。
目次
APLとは?
上でも書いていますが、乱暴に言っちゃうと「Alexaで画面付きデバイスに表示する画面のデザインを行うための言語」です。こんな感じで画面を作ると、ディスプレイ付きデバイスだと表示されます。
さらに、単純なデザインだけでなく、タッチによるイベントやアニメーションなど凝ったこともできますが、凝ったことをやろうと思うと一気にハードルが上がり、Alexaの通信の仕組みや制約を理解しないと厳しくなります(だから見ないふりをしてきたのです・・・)。ということで、基本的なところから理解を深めていきたいと思います。
ということで2年前(もうそんなになるのか・・・・)のAlexa道場を見ていきます。
APLとは?
- JSONベースの宣言的なUI記述言語
- 特徴
- GUIのコンポーネントが揃っている
- テキストやイメージ、コンテナなど
- 柔軟にレイアウトできる
- GUIコンポーネントを組み合わせたり並べたり
- データバインディングによるデザインとデータの分離
- デザインをテンプレートとして、あとからデータを差し込む
- コマンドによる動的な画面生成
- GUIのコンポーネントが揃っている
- 特徴
APLの主なコンポーネント
- 基本コンポーネント
- Image
- Text
- Frame(枠)
- TouchWrapper(コンポーネントをタッチ可能にする)
- 複数コンポーネントのレイアウト
- Container
- 複数のコンポーネントをまとめるコンポーネント。レイアウトのキモ。
- Container
- 複数項目の切り替え
- Pager/Sequenceなど
- ページの切り替えや複数項目を並べたり
- Pager/Sequenceなど
レイアウト
- Container
- コンポーネントを一方向(縦 or 横)に配置
- directionで方向。columnにすると縦にならぶ。
- justifyContentで縦方向の寄せ。endにすると下寄せになる。
- alignItemsで横方向の寄せ。centerにすると中央寄せになる。
- コンポーネントを一方向(縦 or 横)に配置
- レイアウトのサンプル
- 1行目でContainerを定義
- width/heightでviewport width/height
- 100vw/100vhで100%定義
- 4〜6行目でレイアウト要素(direction/justifyContent/alignItems)
- 7行目のitemsで子要素
- 例ではヘッダー、テキスト、画像が縦に並んでいる
- ヘッダー部分の"headerLayout"はビルトインではなく、自分でFrameとtextを使って別で作ったもの。このようにレイアウトを自分で定義して使うこともできる。
- 10行目や17行目にある
${payload.....}
がデータバインディングにより、外部データが差し込まれる - 5行目のjustifyContentにあるような
${viewport.shape == 'round' ? 'end': 'center'}
ところで画面形により分岐というようなこともできる(roundはEcho Spot)
- レイアウトの作り分け
- whenを使ってコンポーネント単位で表示・非表示させるやり方もある。
項目の切り替え
- Pager
- シンプルに書く場合と凝った書き方の場合
- Pagerコンポーネントでitemsにいれる
- Pagerコンポーネントにdataをバインディングさせて、itemsの中でそれを順に表示する
- Sequence
- Pagerは順にスライド
- Sequenceはスクロールに近い
- Sequence
- scrollDiretionでスクロールの方向を指定
APLオーサリングツール
コマンド
- コマンドのユースケース
- タッチでイベントを飛ばす
- ページ送りやスクロールの制御をタッチではなく「自動」で
- 発話コマンドを使って画面上のテキストと発話を動悸させる
- カラオケ的なやつ
タッチ操作
- TouchWrapperコンポーネント
- TouchWrapperの下のitemに紐づく
- onPressで「タッチした」ときにSendEventでイベントをスキルバックエンドに送信。argumentsで送るデータを指定。
- スキル側でそのイベントを拾うハンドラを用意しておく
スライドショー
- タッチでスライドするのではなく、自動でスライドさせる
- SetPageコマンド
- Pagerにおけるページを指定する
- componentIdで該当のPagerを指定する
- positionでページを指定
- relativeで相対指定(次のページへ)
- absoluteで絶対指定(何ページへ)
- delayでタイミング
- ParallelやSequentialで実行方法を指定
- Parallelで並列実行
- Sequentialで順次実行
- ページを切り替えるごとにしゃべるとか
- 長い文章を発話させる間に画面をスライドさせるとか
- Pagerにおけるページを指定する
読み上げ・テキスト同期
- 3つの要素
- APLデータ
- 読み上げデータをSSMLで用意する
- transformerでSSMLを音声に変換する
- 同時にtransformerでSSMLをテキストに変換する
- 読み上げデータをSSMLで用意する
- APLドキュメント
- データをバインディングする
- APLコマンド
- SpeakItemコマンドでテキストを読ませる
- highliteModeでハイライトさせる
- APLデータ
ちょっとどういうことかわからなかったのだけど、ここのtopicTextはpayloadで渡されるtopicTextではなくて、APLドキュメントのidで指定されているtopicTextの方みたい。でこれにより、topicTextのSpeechで指定されている、ssmlToSpeechでオーディオ化されたデータが再生されるということだと思う。 以下のほうがわかりやすい。 テキストブロックでのAPL音声およびテキストの同期 | Alexa Skills Kit
バックエンド
- responseBuilderにaddDirectiveでAPLドキュメントやAPLコマンドを追加する
まとめ
これまでは見様見真似で適当にAPLやってきたのですが、改めてAlexa道場を見てみると、当時リアルタイムで見ていたときよりは理解できている気がしました。多少は成長しているのかな、と。ただ依然として腹落ち感がないので、次回以降で手を動かしてやっていこうと思います。