マルチモーダルなAlexaスキルの作り方

APLオーサリングツールで初めての視覚要素を開発する

目次

このセクションでは、オーサリングツールについて学びます。このツールを使って、Cake TimeスキルのAPL LaunchRequestレスポンシブ対応ドキュメントを作成します。このセクションの最後には、「Welcome to Cake Time!」という文と小さなケーキの画像が表示される画面が完成します。この画面を作成するために、以下について学んでいきます。

  • APL ImageおよびTextコンポーネント
  • スタイル
  • データバインディングの基本
  • レスポンシブ対応ドキュメント

さっそく始めましょう。

このコースでは、FirefoxまたはChromeを使用することをお勧めします。Safariはオーサリングツールでサポートされていません。

1. Hello Cake Time

A. ここをクリックしてオーサリングツールに移動します。コースの学習中は、いつでも参照できるように、このリンクをブックマークとして保存しておいてください。

B. 最初に新しいエクスペリエンスに関する確認画面が表示されるので、はいをクリックします。

authoring tool new experience image

新しいエクスペリエンスでは、APLドキュメントをスキルに保存できます。

C. ドロップダウンで使用中のスキルを探し、選択をクリックします。

Select Skill Image

D. テンプレートを作成をクリックします。さまざまなテンプレートが表示されます。

Authoring Tool Landing page image

E. ここでは最初から作成を選択します。mainTemplateにコンポーネントが追加されていない基本的なAPLドキュメントが表示されます。

F. オーサリングツールの左側で、GUIが選択されていることを確認します。これにより、レイアウトセクションの下にグラフィックで示されたドキュメント構造と、プロパティを入力できるテキストボックスが表示されます。右側にはコンポーネントが表示されています。ここからコンポーネントをドラッグアンドドロップできます。では、Textコンポーネントをドラッグしてみましょう。以下のようになります。

hello world image

G. 「Hello Cake Time!」というテキストを追加していきましょう。レイアウトセクションで、Textコンポーネントをクリックします。

H. 中央のセクションを下にスクロールして、Textコンポーネントのtextプロパティを探します。テキストボックスに入力されているメッセージを「Hello Cake Time!」に変更します。

I. この上にあるfontSizeプロパティを「72dp」に変更します。ユーザーが遠くからデバイスを見てもわかるように、テキストサイズを大きくします。テキストが青いバウンディングボックスの外に出てしまいました。残念ながら、 テキストはとても小さいレンダリングボックスにバインドされているので、このような大きいフォントのテキストは適切に表示できません。これを修正していきましょう。

J. 下にスクロールしてWidthセクションを表示し、Textコンポーネントのwidthプロパティを探します。widthテキストボックスの値を削除します。これで、デフォルトのautoが適用されます。

K. Heightセクションのheightについても同様に値を削除します。autoの場合は、テキストのバウンディングボックスのサイズがコンテンツに合わせて自動的に拡大縮小されるので、この設定をお勧めします。前の手順で行ったように、後でフォントサイズを変更したくなった場合に便利です。

これで、表示は以下のようになるはずです。

Hello cake walk gui

おめでとうございます。 Hello Cake Timeドキュメントはきちんと機能しています。ドキュメントの出力は、サイドバーのAPLタブで確認できます。

ここで表示される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",
                        "paddingTop": "12dp",
                        "paddingBottom": "12dp",
                        "fontSize": "72dp",
                        "text": "Hello Cake Time!"
                    }
                ],
                "height": "100%",
                "width": "100%"
            }
        ]

    }
}

ここまでで、Textコンポーネントを作成し、GUIを使って一部のプロパティを変更しました。Textコンポーネントのすべてのプロパティについては、Textコンポーネントのドキュメントを参照してください。ただし、このページにはpaddingTopとpaddingBottomが記載されていません。これは、どのコンポーネントも親から継承したプロパティを持っているためです。すべてのコンポーネントで共通のスタイルのプロパティの一覧も参照してください。

オーサリングツールではContainerも作成されました。 Containerは、ほかのコンポーネントを「column」または「row」で配置して収めるコンポーネントです。Containerはコンポーネントでもあるので、基本的なコンポーネントのプロパティも持っています。これは、レスポンシブ対応のAPLドキュメントの作成には不可欠です。複雑なドキュメントでは、rowとcolumnのContainerを組み合わせて使用し、どのデバイスでもそれに合わせて拡大縮小してコンポーネントを適切にレイアウトします。

2. スタイル設定したHello Cake Time

いくつかのコンポーネントプロパティは、スタイルを使用して定義できます。スタイルは、コンポーネント間で再利用できる名前付きのセットです。

すべてのコンポーネントですべてのプロパティをスタイル設定できるわけではありません。 各コンポーネントのスタイル設定可能プロパティの一覧については、こちらを参照してください。

A. STYLESサイドバーをクリックします。空のかっこが1組表示されるので、こちらを上書きします。

{
    "bigText": {
        "values": [
            {
                "fontSize": "72dp"
            }
        ]
    }
}

B. サイドバーのAPLタブをクリックして戻ると、STYLESセクションに追加したスタイルでドキュメントが更新されています。

C. APLタブを開いた状態で、Textコンポーネントを修正していきましょう。fontSizeプロパティを削除し、以下を追加します。

"style": "bigText"

paddingTopやpaddingButtomプロパティがまだ表示されていますが、これは定義したスタイルから取得されたものです。文字の大きさは、stylesブロックのfontSizeプロパティを変更することでテストできます。ここまでの変更でAPLコードは以下のようになっているはずです。

final hello apl diagram

次はさらに、スタイルを使用してテキストを中央揃えにしてみましょう。

D. styleセクションにtextAlignプロパティを追加し、中央揃えに設定します。

"textAlign": "center"

これでスタイルの記述は以下のようになります。

{
    "bigText": {
        "values": [
            {
                "fontSize": "72dp",
                "textAlign": "center"
            }
        ]
    }
}

実際のTextコンポーネントは変更していませんが、bigTextスタイルを使用しているので、変更がTextコンポーネントに適用されます。

3. データバインディング

DATAボタンがあることにお気付きでしょうか? これは、ドキュメントをレンダリングするためにスキルのバックエンドから送信するAlexa.Presentation.APL.RenderDocument ディレクティブの一部になるデータソースをシミュレートします。これについては後述しますが、まずはデータソースを使用してドキュメントを作成する方法を見ていきましょう。

データソースのデータを参照するには、 先にAPL ドキュメントの中にパラメーターを渡しておく必要があります。古いバージョンのAPLでは、データソース全体が、「payload」という名前のデフォルトの単一のパラメーターにバインドされていました。しかし、現在のバージョンのAPL(1.3)では、どのパラメーターも「payload」という名前をつけずに、データソースで定義されている複数のパラメーターを渡せるようになりました。「payload」という名前を使用しても、後方互換性のため古い動作に戻りますが、このレガシーな名前を使用することは推奨されません。おそらく既存のAPLドキュメントを見てみると、「payload」というデフォルトのオーサリングツールのパラメーターが残っていることでしょう。ここではデータパラメーターにマッチするように修正する必要があります。それではシンプルなデータソースを追加して使ってみましょう。

A. mainTemplate.parameters 配列の中の、「payload」を「text」に置き換えます。以下のようになります。

 

"mainTemplate": {
    "parameters": [
        "text"
    ]
    ...
}

これでパラメーターがドキュメントに渡され、参照できるようになりました。データソースはキーと値がペアになっているJSON形式です。このオブジェクトをネストさせることもできます。それでは、データソースとスタイルを使って、もう一つテキストコンポーネントを追加してみましょう。データの参照は、${parameterName.YourDefinedObject} のように記述します。では APL JSONを修正します。

{
    "type": "Text",
    "style": "bigText",
    "text": "${text.middle}"
},
{
    "type": "Text",
    "style": "bigText",
    "text": "${text.end}"
}

B. ここで、最初のTextコンポーネントのテキストデータも ${text.start}に変更しておきましょう。変更すると、画面のプレビューからテキストの表示が消えたことに気づきましたか? これは、参照中のデータソースにデータがないことが原因です。DATAタブを使って修正しましょう。

C. DATAボタンをクリックすると、空のデータセット {}が表示されます。ここに「text」という名前をつけたパラメーターでセットした構造に従ってデータを追加する必要があります。つまり、「start」、「middle」、「end」のフィールドを持つ「text」オブジェクトを追加します。

D. オーサリングツールのDATAセクションに以下を追加します。

{
    "text": {
        "start": "Welcome",
        "middle": "to",
        "end": "Cake Time!"
    }
}

データのJSONオブジェクトはドキュメントの変数データを表します。このレイアウトを後で再利用して、同様の構造のテキストを新しいデータでレンダリングします。このテクニックを使うと、ローカライズ用のロジックをすべてバックエンドに配置できるため、スキルを簡単にローカライズすることができます。また、この機能を利用して、APLドキュメントを再利用することもできます。この時点で、表示は以下のようになっています。

welcome to cakewalk image

これで、このAPLドキュメントで再利用可能なスタイルセットができました。ここまでは、データバインディングを使用して画面を作成する方法を学びました。次は、誕生日ケーキの画像を追加してみましょう。

4.誕生日ケーキを追加する

Imageコンポーネントを追加し、データバインディングを使用する必要があります。Imageコンポーネントは、画像を保存しているリソースへのURLを使用します。しかし、Imageはプリミティブなコンポーネントです。自動的に拡大縮小されないため、あらゆるviewportのサイズに合わせて画像を拡大縮小するには大きな手間がかかるうえ、複数の画像解像度も必要になります。そこで、代わりにAlexaImageレスポンシブ対応コンポーネントを使用します。こうすれば、1つの画像を使用してすべてのデバイス解像度に合わせて拡大縮小することができます。

AlexaImageコンポーネントを使用するには、importを追加する必要があります。importでは、ほかのパッケージで定義されているレイアウト、スタイル、リソースを参照できます。ここでは、alexa-layoutsという名前の標準パッケージを使用します。importは次のように記述します。

{
    "name": "alexa-layouts",
    "version": "1.1.0"
}

A. 上記のimportオブジェクトを、APLドキュメントのimportセクションのimportリストに追加します。そうすると次のようになります。

{
    "type": "APL",
    "version": "1.1",
    "settings": {},
    "theme": "dark",
    "import": [
        {
            "name": "alexa-layouts",
            "version": "1.1.0"
        }
    ],
 ...<以下省略>
}

Alexa layoutsは、レスポンシブ対応レイアウトの重要なパッケージです。AlexaImageコンポーネントには多くのパラメーターがあり、そのほとんどはオプションです。

B. 最後のTextコンポーネントの後に新しいContainerを追加して、以下のimageブロックを含めます。この新しいブロックは、既存のContainerに入れ子にする必要があるので、必ずTextコンポーネントと同じ「items」配列に追加してください。

{
    "type": "AlexaImage",
    "alignSelf": "center",
    "imageSource": "${assets.cake}",
    "imageRoundedCorner": false,
    "imageScale": "best-fill",
    "imageHeight":"40vh",
    "imageAspectRatio": "square",
    "imageBlurredBackground": false
}

詳しく見ていきましょう。

  • AlexaImageに使用しているフィールドで重要なのは、imageSourceです。ここで画像をホストしているURLを指定しているためです。
  • 指定した画像の解像度を維持できるように、標準の横長のアスペクト比を設定します。
  • 画像を拡大縮小するときは、best-fitスケールを使用します。
  • サイズを制御するために、imageHeightプロパティを使用して、viewportの高さの40vh (40%)に設定します。vhとは縦方向の比率を表す単位です。

個々のパラメーターの詳細については、技術資料を参照してください。しかし、ImageコンポーネントのページにalignSelfの説明はありません。このプロパティは、コンポーネントがContainerの子コンポーネントであるためここに含まれて機能しています。AlignSelfはその子についてのみ、Containerの配置を上書きします。ほかにも、Containerの子であることから追加されているプロパティがあります。これは、データセクションに追加される新しい「assets.cake」オブジェクトに依存しています。新しいデータセクションは次のようになります。

{
    "text": {
        "start": "Welcome",
        "middle": "to",
        "end": "Cake Time!"
    },
    "assets": {
        "cake":"https://github.com/alexa/skill-sample-nodejs-first-apl-skill/blob/master/modules/assets/alexaCake_960x960.png?raw=true"
    }
}

C. Dataタブをクリックし、新しい「assets」オブジェクトでデータを更新します。

D. 最後のステップは、新しい mainTemplate パラメーターである「assets」を追加します。APLタブに戻り、mainTemplate.parametersリストにそれを追加します。以下のようになります。

{
    "mainTemplate": {
        "parameters": [
            "text",
            "assets"
    ]

    ...

}

すると、以下のように表示されます。

authoring tool image

いかがですか? おいしそうでしょう? 誕生日にぴったりのスキルになってきました。では、これをほかのviewportプロファイルでも機能するようにしましょう。

5.レスポンシブ対応ドキュメントを作成する

変更を表示しているシミュレーター画面の下に、複数の画面付きEchoデバイスが表示されています。ここまでは「中型デバイス」(Echo Showの画面パラメーター)を使用してきましたが、サポートされるデバイスはほかにも多数あります。作成したドキュメントをほかの画面で試してみましょう。

A. それぞれのシンボルをクリックして、気付いた問題を記録します。

シミュレーターデバイスのタイプ

  • 小型デバイス 円形(480x480)
  • 小型デバイス 横長(960x480)
  • 中型デバイス 横長(1024x600)
  • 大型デバイス 横長(1280x800)
  • 超大型TV 横長(1920x1080)
  • カスタムデバイスを追加(任意x任意)

最後のオプションでは、デバイスのレンダリングをシミュレートする画面解像度を任意で作成できます。

図1.問題ありの表示

broken hello spot image
Figure 1. Well, that doesn’t look quite right…​

B. 小型デバイス(円形)の画面では文字表示が切れてしまいます。whenプロパティを使用して修正しましょう。このプロパティではブール値評価ができます。trueの場合、コンポーネントとその子を表示しますが、falseの場合は表示しません。whenに加えて、alexa-layouts importのResourcesを使用します。Resourcesは、 @<Resource_name>で参照されるシンプルな名前付き定数です。ここでは、前述のデバイスタイプとviewportプロファイルを表すalexa-layoutsパッケージの定数を使用します。この場合は、定義済みのviewport固有の定数を使った文を次のように作成できます。

${@viewportProfile == @hubLandscapeLarge}

次のような指定はしません。

${viewport.width == "1280dp"}

Echo Showデバイスで表示した場合、これらの文に違いはありません。しかし、1300dpのワイドスクリーンの新しいデバイスが登場したとしたらどうでしょうか?この条件に合わせた文を追加すべきでしょうか? 同じクラスで第3のデバイスが登場した場合はどうでしょうか? Amazonで定義されたresourcesを使うと、使用される画面サイズの組み合わせがわからなくても、APLドキュメントを適切に拡大縮小できます。 @hubLandscapeLarge が幅1280~1920の画面を表しているのはこのためです。こうしておけば、そのクラスの多くのデバイスを含めることができます。同じクラスのデバイスであっても、確認していた幅と画面が正確に一致しない場合は、何も表示されません。

C. 円形の小型デバイス以外のすべてのデバイスでドキュメントが正しく表示されたので、小型デバイス用のコンポーネントセットを新たに追加します。小型デバイス円形のアイコンをクリックします。

D. 評価がfalseの場合は子コンポーネントが表示されないので、最初のContainerの上に以下の文を追加します。

"when":"${@viewportProfile != @hubRoundSmall}"

E. 黒い画面が表示されるはずです。 長方形の画面で試してみましょう。コンポーネントはレンダリングされます。このContainerとその子から@hubRoundSmallクラスを省いたため、 @hubRoundSmall デバイスが使用されるときにレンダリングする新しいContainerを作成する必要があります。.

F. 1つ目のContainerの下に、Containerと子Textコンポーネントを複製し、mainTemplateのitemsリストを追加します。このブロックの上に、先ほどとは逆の文を追加します。

"when":"${@viewportProfile == @hubRoundSmall}"

G. 1つ目のTextコンポーネントが正しく表示されるように、上部にパディングを追加します。

"paddingTop": "75dp",

H. 次に、テキストボックスのほかのパディング値をすべて削除します。

I. ケーキの画像を削除します。これで、どのデバイスタイプでも適切に表示されるようになりました。別の画面タイプのデバイスに切り替えても表示に問題がないことを確認します。

J. このJSONは次のセクションでも使用します。APLドキュメントをlaunchDocument.json.という名前で保存します。

余談ですが、このドキュメントを円形の小型デバイスのプロファイルに合わせて修正する方法は、ほかにもいろいろあります。たとえば、画像を残してテキストを削除したり、画像を円形の小型デバイスの背景に移動したりすることができます。構成的には、すべてを1つのContainerに入れておき、条件に応じてパディングを追加したり画像を隠したりして、同じエクスペリエンスを提供することも可能です。この技術的なアプローチの利点は、将来デフォルトで新たに追加されるコンポーネントを取得する必要がないことです。さらに、長方形デバイスの見直しや変更を行うときに、円形の小型デバイスの画面の構造を修正する必要もなくなります。円形のデバイスは、特にデザインにおいて長方形デバイスと異なるため、別のコンポーネントを用意しています。ほかのスキルでは、デザインに合わせて別のアプローチをとっても構いません。

最終的なAPLドキュメントのJSONは以下のようになりました。

{
    "type": "APL",
    "version": "1.1",
    "settings": {},
    "theme": "dark",
    "import": [
        {
            "name": "alexa-layouts",
            "version": "1.1.0"
        }
    ],
    "resources": [],
    "styles": {
        "bigText": {
            "values": [
                {
                    "fontSize": "72dp",
                    "textAlign": "center"
                }
            ]
        }
    },
    "onMount": [],
    "graphics": {},
    "commands": {},
    "layouts": {},
    "mainTemplate": {
        "parameters": [
            "text",

            "assets"
        ],
        "items": [
            {
                "type": "Container",
                "when":"${@viewportProfile != @hubRoundSmall}",
                "items": [
                    {
                        "type": "Text",
                        "style": "bigText",
                        "paddingTop": "12dp",
                        "paddingBottom": "12dp",
                        "text": "${text.start}"
                    },
                    {
                        "type": "Text",
                        "style": "bigText",
                        "paddingTop": "12dp",
                        "paddingBottom": "12dp",
                        "text": "${text.middle}"
                    },
                    {
                        "type": "Text",
                        "style": "bigText",
                        "paddingTop": "12dp",
                        "paddingBottom": "12dp",
                        "text": "${text.end}"
                    },
                    {
                        "type": "AlexaImage",
                        "alignSelf": "center",
                        "imageSource": "${assets.cake}",
                        "imageRoundedCorner": false,
                        "imageScale": "best-fill",
                        "imageHeight":"40vh",
                        "imageAspectRatio": "square",
                        "imageBlurredBackground": false
                    }
                ],
                "height": "100%",
                "width": "100%"
            },
            {
                "type": "Container",
                "when":"${@viewportProfile == @hubRoundSmall}",
                "items": [
                    {
                        "type": "Text",
                        "style": "bigText",
                        "paddingTop": "75dp",
                        "text": "${text.start}"
                    },
                    {
                        "type": "Text",
                        "style": "bigText",
                        "text": "${text.middle}"
                    },
                    {
                        "type": "Text",
                        "style": "bigText",
                        "text": "${text.end}"
                    }
                ],
                "height": "100%",
                "width": "100%"
            }
        ]
    }
}

次のセクションでもこのドキュメントを使っていきます。

Githubのコード(完全版)