Alexa ハローAPL、Alexaスキルの画面への対応

#はじめに
趣味でAlexaのスキル開発をしています。
今まではamazon echo dotしか持っていなかったので、音声ファーストで、画面表示は後回しで開発を行ってきました。
画面はホームカードを出すだけでした。
私のPC環境では、alexa developer consoleのテストシミュレーターがうまく動作せず、画面は初期画面しか出ないというのも理由のひとつでした。

色々Alexaデバイスも増えてきて、そろそろ画面対応した方がいいなあと思い、7月のプライムデーの時に、Alexa echo show 5を購入しました。
早速APL (Alexa Presentation Language)を含むスキルの勉強を始めてみたのですが、なかなか理解できず、悪戦苦闘しました。
ということでまだまだAPLをわかってると言い難い状態ですが、備忘と整理のためにまとめます。
APLはかなり書きたいこと(整理しておきたいこと)があるので、複数回に分けて書いていこうと思います。
まずは、ハローAPLから。今回はまずは説明は置いておき、まずは作ってみます。
その後、色々構造とか、APIとか説明とかコードの解説とかを記載したいと思います。
なお、参考に記載した資料はとてもわかりやすく、非常に理解に役立ちました。

##今回実施するする内容
画面付きデバイスのスキルで、画面中央に「ハローAPL」を表示するスキルを作成する。

-------
#環境
OS:Windows 10 JP
Alexaスキル言語：Node.js
Editor：Visual Studio Code
APLバージョン：1.0, 1.1

#参考
[APLハンズオン](https://apl-handson.netlify.com/#0)

-----
#用語
##APL
Alexa Presentation Language
amazonの画面つきのAlexaの画面表示用の言語。
JSONを使用した記載方法です。
インターネットのホームページはHTMLとCSSで作成しますが、AlexaはAPLで作成するということです。

##APLオーサリングツール
APL作成を視覚的に見ながらAPLのJSONファイルを作成するツール。
サンプルテンプレートも準備されており、その中から選択していくだけで、だいたいの画面は作成できる。

-----
#前提条件
前提条件はとくにないといえばないですが、本まとめを読むにあたり、以下がわかっていることが前提です。
・alexa developer consoleのアカウントがある
・Alexaスキルを開発したことがある
・JSONの記載方法を知っている

-----
#ハローAPLの作成
今回作成するスキルは、「アレクサ、〇〇〇を開いて」（〇〇〇は呼び出し名です）というと、「ハローAPL」と画面が表示されるだけのスキルです。とても公開できるものではありませんので、単にローカル環境で試すだけ、もしくはAPLを学ぶためだけのスキルです。

##スキルの新規作成
・まずは、画面表示用の新しいカスタムスキルをalexa developer consoleから作成します。
スキルの呼び出し名などは任意でかまいません。
作成方法は省略します。
・続いて、alexa developer consoleのインターフェースから「Alexa Presentation Language」を有効にします。
・ついでに、デバイスの種類がデフォルトで選択されていますが、「Echo show 5」は選択されていないため、チェックします。
・そのほか、コードへのエンドポイントはなんらか設定します。
　ここも省略します。（私の場合はLambdaでコード作成します）
![APL設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/099f821f-a38c-a438-a17e-ff21b7daee96.jpeg)

-----
##画面の作成（JSON作成）
まずは、amazon developer consoleにAPL作成するAPLオーサリングツールがありますので、それを使いながら作ります。
・amazon developer consoleの左側のメニュー「画面表示」をクリックするとAPLオーサリングツールが起動する。

![画面表示ベータ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/77333530-8f66-9ce7-9469-6af4cb1707e9.jpeg)

-----
###「最初から作成」を選択
・スキルの表示方法を選択する画面では、「最初から作成」を選択する。
自分でJSONを記載しても同じことなのですが、最初のとっつきやすさという点ではこのほうが良いかと思います。
![画面表示選択.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/605e42d8-9fc7-f191-1600-645c5fd0715d.jpeg)

-----
###ツールの画面イメージ
・ 以下のような画面が表示されます。大きく左右に画面が分かれますが、右側は画面に直接コンポーネントを置きながら画面を作成しますが、今回は左側の画面を操作しながらハローAPLを作成します。
以下の図で、主に赤枠で囲った部分を使っていきます。
用語の定義はよくわからなかったため、下図のとおりとします。
![APLオーサリングツール画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/75f5d787-158e-e5b7-70e6-20e4611c6c7d.jpeg)

-----
###ボタンを押してみる
・まず最初に、最左のアイコンを順に押してみて、どう変化が起こるのかだけ確認しておきましょう。
レイアウト画面が、レイアウトを示したり、ソースコードを書くような画面になったりするかと思います。
・一番上の「レイアウトボタン」を押すと、レイアウト画面が表示され、「mainTemplate」とだけ表示されます。
・APL JSONボタンを押すと、APLファイルが以下の通り、初期状態で表示されます。
これを埋めていけば、APLが完成します。

```json
{
    "type": "APL",
    "version": "1.1",
    "settings": {},
    "theme": "dark",
    "import": [],
    "resources": [],
    "styles": {},
    "onMount": [],
    "graphics": {},
    "commands": {},
    "layouts": {},
    "mainTemplate": {
        "parameters": [
            "payload"
        ],
        "items": []
    }
}
```
・「JSONデータ」ボタンを押すと、ソースを記載する画面になります。
ここには、APLのデータ情報を記載することになります。

```json
{}
```
-----
###コンテナの追加

・「レイアウト」ボタンを押して、レイアウト画面に「mainTemplate」を表示する。
・「mainTemplate」を選択すると、「追加」ボタンが有効になる。これを押すと、以下のような「Add Component」が表示される。

![Container.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/500b2a35-c511-3e98-ccb3-07013a9aef48.jpeg)

`Container`を選択し、「{type}を追加」ボタンを押す。
こうすると、レイアウト画面上で、「mainTemplate」の配下に「Container」が表示される。
今後の操作はこのように追加したい場所にコンポーネントを追加することになります。

![レイアウト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/efaf62c3-5c8e-ff29-1cbe-6754b2608616.jpeg)

-----
###「ハローAPL」テキストの追加

・今作成した「Container」を選択し、「追加」ボタンを押して「Add Component」画面で、`Text`を選択し、「{type}を追加」を押して、「Container」の配下に「Text」を追加する。
・説明していませんでしたが、「mainTemplete」、「Container」、「Text」を選択すると、「詳細レイアウト」画面に、色々表示されます。ここに設定を記載していくとそれに応じて画面の表示方法が変更されます。
・「レイアウト画面」で「Text」を選択し、「詳細設定画面」をスクロールすると、「text」があるため、ここに`ハローAPL`と入力する。
すると「画面レイアウトイメージ」の左上に「ハローAPL」と表示される。
これがもっともシンプルなAPLだと思います（Containerなしで、「Text」だけ追加がさらにシンプルですが、通常はそんなことはしないです）。

-----
###「ハローAPL」のAPL JSONの確認

・再左の「APL JSON」ボタンを押すと、この「ハローAPL」のAPL JSONが表示される。
「mainTemplete」のところに、`"parameteres"`と`"items"`というキーがあり、それぞれ値が設定される。
・`"items"`の記載は、今実施した`Container`を追加して、`Text`を追加して、「ハローAPL」を記載という流れのため、イメージできるはずです。
・`"parameters"`は何もしていないですが、入っています。これも実は「レイアウト画面」で「mainTemplate」を選択すると、「詳細設定画面」の「mainTemplate parameters」に、`payload`と最初から記載されており、これが設定されるのです。
この`payload`は、外部のJSONデータからデータを変数で受け取るときに使用するキーワードですが、ここではこういうものだ程度の理解でよいと思います。

```json
{
    "type": "APL",
    "version": "1.1",
    "settings": {},
    "theme": "dark",
    "import": [],
    "resources": [],
    "styles": {},
    "onMount": [],
    "graphics": {},
    "commands": {},
    "layouts": {},
    "mainTemplate": {
        "parameters": [
            "payload"
        ],
        "items": [
            {
                "type": "Container",
                "items": [
                    {
                        "type": "Text",
                        "text": "ハローAPL"
                    }
                ]
            }
        ]
    }
}
```
-----
###「ハローAPL」のセンタリング
このままでは、「ハローAPL」が左上に表示されているため、画面の中央にくるように調整します。
・「レイアウト画面」で「Container」を選択し、「詳細設定画面」の「justifyContent」に「center」と入力する。これを実施すると「ハローAPL」が画面の中央に移動します。横方向はまだ左側にあります。
画面レイアウトで余白がある場合に文字を中央にするという設定です。
・「レイアウト画面」で「Text」を選択し、「詳細設定画面」の「textAlign」に「center」と入力する。これを実施すると「ハローAPL」が左右方向で画面中央に移動します。
この二つの設定で、期待通り、「ハローAPL」が画面中央になります。

![ハローAPL.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/6902dccb-2ded-7ce8-dcf2-fef59f2c25a3.jpeg)

ところで、「Container」にはその配下に置くコンポーネントの位置を設定するための設定が「justifyContent」と「alignItems」の2種類があります。
「justifyContent」は、主軸方向に対する設定。
「alignItems」は、主軸と交差する方向の設定。
それぞれセンタリングすると発生する動作を図に示します。
![Align.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/4428c210-4ce0-a942-0b31-2f788b39c99d.jpeg)

-----
###JSONデータって？
APLの画面表示は、今回作成したような文字列を直にAPL JSONに記載するわけではなく、構造を記すAPL JSONとそこに記載するデータを記載するJSONデータを分離して管理するのが一般的なようです。構造を示すAPL JSONがテンプレートで、表記構造を作りこんで、JSONデータによって、さまざまなデータを与えることで、表示する画面が切り替わるということです。

![構造イメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/a65668f0-4ef6-f0ef-fb2a-aad96e62b14d.jpeg)

-----
###JSONデータに「ハローAPL」設定
・「レイアウト画面」で「Text」を選択し、「text」のところに、
`"${payload.hello.text}"`
と記載する。こうすると、「画面レイアウトイメージ」から「ハローAPL」の記載は削除されます。
この${}の記載方法は、最近のJava Scriptのテキスト内に変数を記載するときの表記方法と同じです。
知っていれば違和感ないはずです。
`payload.hello.text`というのは、これから記載しますが、`payload`がJSONデータの最上位へのリンクであり、「mainTemplate」の「mainTemplate parameters」に設定されていた「payload」です。ここを違うキーワードにすれば、それになるかと思いますが、標準では、`payload`であることからそのまま使います。
その後の`hello.text`はJSONの階層構造を示します。
・最左の「JSONデータ」ボタンを押すと「レイアウト画面」がコードを記載する画面に切り替わる。
・以下の通り、JSONを記載する。

```json
{
    "hello": {
        "text": "ハローAPL"
    }
}
```

こうすると、再び「画面レイアウトイメージ」に「ハローAPL」が表示される。

-----
###JSONファイルの保存
これで今回作成する「ハローAPL」のコードは完成したため、保存する。
・右下にある「コード書き出し」ボタンを押下し、ファイルに保存する。ファイル名はなんでも構いません。
参考に今回作成したJSONを以下にに示します。

`````json
{
    "document": {
        "type": "APL",
        "version": "1.1",
        "settings": {},
        "theme": "dark",
        "import": [],
        "resources": [],
        "styles": {},
        "onMount": [],
        "graphics": {},
        "commands": {},
        "layouts": {},
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "type": "Container",
                    "justifyContent": "center",
                    "items": [
                        {
                            "type": "Text",
                            "textAlign": "center",
                            "text": "${payload.hello.text}"
                        }
                    ]
                }
            ]
        }
    },
    "datasources": {
        "hello": {
            "text": "ハローAPL"
        }
    }
}
`````

APL JSONで表示されたJSONが、`"document"`のキー配下に記載され、JSONデータに表示されたJSONが`"datasources"`のキー配下に記載されているはずです。

-----
###APL JSONの切り離し
・先ほど作成したJSONファイルから、`"document"`キー配下のJSONを切り取って、`helloAPL.json`として保存する。
・`"datasources"`キー配下のJSONは、別途ソースコードへ反映しますが、以降で説明する。

```json:helloAPL.json
{
    "type": "APL",
    "version": "1.1",
    "settings": {},
    "theme": "dark",
    "import": [],
    "resources": [],
    "styles": {},
    "onMount": [],
    "graphics": {},
    "commands": {},
    "layouts": {},
    "mainTemplate": {
        "parameters": [
            "payload"
        ],
        "items": [
            {
                "type": "Container",
                "justifyContent": "center",
                "items": [
                    {
                        "type": "Text",
                        "textAlign": "center",
                        "text": "${payload.hello.text}"
                    }
                ]
            }
        ]
    }
```

-----
##APLのソースコードへの追加
APLファイルは作成できたため、それをAlexaスキルのソースコードに紐づけます。今回は起動時に先ほどの「ハローAPL」を表示されますので、`index.js`のLaunchRequestに紐づけを行います。
・LaunchRequestのresponseBuilderにaddDirective関数を以下のように追加する。

```js:index.js
...
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak("ハローAPLへようこそ")
      .reprompt("ハローAPLへようこそ")
      .addDirective({
        type : 'Alexa.Presentation.APL.RenderDocument',
        version: '1.1',
        token: "token",
        document: require('./helloAPL.json'),
        datasources: {
          "hello": {
            "text": "ハローAPL"
          }
        }
      })           
      .getResponse();
  },
...
```

気になるところだけコメントを記載する。
・`document`キーの配下に、`require('./helloAPL.json'),`を記載する。この時先ほど作成した`helloAPL.json`を`index.js`と同じ階層に置く。
これでdocument配下に、`helloAPL.json`の内容が反映される。
・`datasources`キーの配下に、先ほど作成したJSONデータのデータ部分を記載する。
このような仕組みにすると、ソースコードからAPLの内容を自由に変更することができる。

これで、ソースコードの記載は終了。

-----
##スキルを起動してみる
・「アレクサ、〇〇を開いて」といってみて、画面に「ハローAPL」と表示されれば成功である。

------
#おわりに
今回は、初めてAPLを使ったAlexaスキルを開発するために、
・もっともシンプルな形でAPLの作成
・ソースコードの記載
の実施方法をまとめました。

次回以降で、APLのそれぞれのキーの説明とか、まとめようかと思います。