Alexa APL, 第2回　画面非対応Echoへの対応

#はじめに
画面付きAlexaへの画面出力対応のために、Alexa APLを学び始めました。
その理解がとても難しく、わからないことが多いため、備忘のためにまとめておくことにしました。
今回は、画面非対応Echoへの対応方法をまとめます。
基本的に、ソースコードはAlexa APL関連でまとめているソースコードに続いていきますので、読んでいただける方は、つじつまが合わない箇所は、「参考」に記載する過去の記事も読んでいただいたほうが良いかと思います。

##今回実施する内容
APLで記載した画面付きデバイスに対応したスキルを、画面非対応デバイスでエラーが発生しないように実装する。

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

#参考
・[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)
第1回のAlexa APLの記事です。タイトル通り、ハローAPLを表示させるだけのAPLです。

・[APLトレーニングシリーズ第1回: 初めての Alexa Presentation Language (APL)](https://developer.amazon.com/ja/blogs/alexa/post/a3712152-cd02-4fda-9d33-3b64ef3a13af/jp-alexa-presentation-language-part1)
AmazonのAlexa Blogsに画面非対応Echoへの対応の記載がありました。

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

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

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

#画面非対応Echoへの対応
##「ハローAPL」を画面非対応Echoで実施してみる
前回の「[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)」で作成した「**ハローAPL**」を表示するだけのスキルを、画面付きEcho（私の場合、Echo Show 5）で実行すると、画面に「ハローAPL」が表示されます。

このスキルを画面非対応Echo（私の場合、Echo Dot）で実行すると、「スキルがリクエストに正しく応答できませんでした」とAlexaに言われます。

また、iphoneのAmazon Alexaアプリで実行すると、以下のようなエラーが表示され、やはり、「スキルがリクエストに正しく応答できませんでした」とAlexaに言われます。

```
Invalid Directive
Request Identifier:null

The device does not support Alexa.Presentation.APL directives
```

なるほど、このままではスキル公開したとしても、審査に落ちてしまいますね。
画面非対応Echoの場合にエラーが発生しないようにしないといけないですね。

##画面非対応の識別関数の追加
スキルのソースコードに画面非対応Echoなのか画面対応Echoなのか判断する処理が必要になってきます。
その内容は、**参考**に記載した[APLトレーニングシリーズ第1回: 初めての Alexa Presentation Language (APL)](https://developer.amazon.com/ja/blogs/alexa/post/a3712152-cd02-4fda-9d33-3b64ef3a13af/jp-alexa-presentation-language-part1)にそのまま載っていました。

判断するために関数を準備して、それによって、responseBuilderを変更するということですね。
その判断処理の関数は以下です。

>```js
>// util.js へ以下を追加
>module.exports.isAPLSupported = function isAPLSupported(request) {
>  return request
>    && request.context
>    && request.context.System
>    && request.context.System.device
>    && request.context.System.device.supportedInterfaces
>    && request.context.System.device.supportedInterfaces['Alexa.Presentation.APL'];
>}
>```
>
>この関数を使って、例えば次のように、APLドキュメントの追加をコントロールします。
>
>```js
>const Util = require('util.js');
>
>...
>    handle(handlerInput) {
>        ...
>        const builder = handlerInput.responseBuilder
>            .speak(speechText)
>            .reprompt(speechText);
>        if (Util.isAPLSupported(handlerInput.requestEnvelope)) {
>            ...
>            builder.addDirective({
>                type : 'Alexa.Presentation.APL.RenderDocument',
>                ...
>            });
>        }
>        return builder.getResponse();
>    }
>};
>```

isAPLSupported関数は、ほかのスキルでも使用できるため、モジュール化してるわけですね。モジュール化しない場合は、`index.js`にそのまま記載すればよいと思います。
私は、記載の通り、Util.jsを作成して試してみました。うまくいきそうです。
でも、`index.js`に少しだけ手を加えました。

```js:index.js
const Alexa = require('ask-sdk');
const Util = require('./org_modules/util.js');

const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    const builder = handlerInput.responseBuilder
      .speak("画面表示へようこそ")
      .reprompt("画面表示へようこそ")
      .withStandardCard("画面", "画面表示へようこそ");

    if(Util.isAPLSupported(handlerInput.requestEnvelope)) {  
      builder.addDirective({
        type : 'Alexa.Presentation.APL.RenderDocument',
        version: '1.1',
        token: "token",
        document: require('./helloAPL.json'),
        datasources: {
          "hello": {
            "text": "ハローAPL"
          }
        }
      });
    } 
    return builder.getResponse();
  },
};
```

違いは大したところではないですが、モジュールの読み込みは、私の場合、「org_modules」というフォルダに置いているため、パスは違います。
builderに、「.withStandardCard("画面", "画面表示へようこそ");」を一文加えました。
画面非対応Echoへの対応であるため、不要な一文ではありますが、iphoneのAlexaアプリから実行すると、画面に何も表示されないため、気持ち悪いなと思い、つけておきました。


#おわりに
今回は、画面非対応Echoへの対応方法を記載しました。
といっても、Amazon Blogsに書いている内容の転載であり、目新しいことはないです。