手順6: Lambdaパッケージを作成・デプロイする


手順6: Lambdaパッケージを作成・デプロイする

Fire TVでアプリを実行できるようになったので、AlexaビデオスキルAPIから受け取ったディレクティブをアプリに渡す機能を追加するため、Lambda関数を更新する必要があります。アプリにメッセージを渡す際は、Amazon Device Messaging(ADM)を使用します。

Fire TV対応サンプルアプリに関する注意点

Fire TV対応サンプルアプリを使用する場合でも、このトピックで説明する全タスクを完了させる必要があります。

Lambdaデプロイパッケージについて

手順C: ビデオスキルのLambda関数を作成する(「手順1: ビデオスキルとLambda関数を作成する」のサブタスク)では、基本的なLambdaコードをLambdaエディターにコピーしてLambda関数を構成しました。しかし、ビデオスキルAPIから受信するディレクティブを処理するには、より多くの機能を備えたLambdaコードを開発する必要があります。この手順では、ADM構成を含む、より堅牢なLambda関数を使用します。

手順A: Lambdaデプロイパッケージを作成する

この手順では、まずNode.jsアプリ内のindex.jsファイルを使用します。このファイルはFire TV対応アプリでビデオスキルAPIを統合する際に使用するLambda関数のサンプルコードで、Discovery、SearchAndPlay、FastForward、ChangeChannelなどのディレクティブに対するレスポンスが含まれています。以前にコピーした基本的なLambdaコードに似ていますが、ADM構成など、より多くのロジックが記述されています。このindex.jsコードを基にして、独自のロジックを追加していきます。

このLambda関数は、クライアントシークレット、クライアントID、登録IDを実際の値で更新する必要があります。Node.jsアプリを使用して、関数をLambdaデプロイパッケージ(パッケージ化されたzipファイル)として生成し、AWS Lambdaにアップロードします。後ほど、受信したディレクティブを処理してアプリに渡すロジックを記述し、この関数をカスタマイズします。

Lambda関数を仕上げるには、次の手順を実行します。

  1. sample-nodejs-vsk-with-admプロジェクトのzipファイルをダウンロードして解凍します。
  2. sample-nodejs-vsk-with-admフォルダ内のindex.jsをテキストエディターで開きます。
  3. CLIENT_IDCLIENT_SECRETの値を入力します。これは、手順5: アプリに署名してセキュリティプロファイルを構成するでコピーした値です。

    const CLIENT_ID = '<クライアントIDを入力>';
    const CLIENT_SECRET = '<クライアントシークレットを入力>';
    
  4. アプリでinitializeADM()メソッドからADM登録IDを取得します(この関数については、「Alexa Client Libraryを統合する」の手順D: ダウンチャンネルサービスを初期化するで説明しています)。

    登録IDを取得するには、アプリが実行中であればAndroid Studioで [Logcat] を展開し、デバイスとアプリを選択します。次に、[Verbose] を選択し、ADM registration Idというテキストで絞り込みます。一致するものがない場合は、アプリを停止して再度実行してください。アプリが起動すると、Logcatに登録IDが表示されます。この値は次の手順で必要になるため、アクセスしやすい場所に保存しておいてください。

    LogcatでADM登録IDを取得する
    Logcatで登録IDを取得する
  5. sample-nodejs-vsk-with-admアプリのindex.jsファイルで、admRegistrationIdに(先ほど取得した)登録IDの値を入力します。

    var admRegistrationId = '<アプリのADM登録IDを入力>';
    

    Lambda関数はADM経由でアプリにメッセージを送信します。登録IDは、アプリへの通信を認証するために必要になります。

  6. ファイルを保存します。
  7. Node.jsとNPMがインストールされていない場合は、インストールします。Node.jsとNPMの有無は、node -vおよびnpm -vを実行することで確認できます。
  8. ターミナルウィンドウを開き、sample-nodejs-vsk-with-admアプリが含まれているディレクトリに移動します。以下に例を示します。

    cd /Users/<ユーザー名>/skills/sample-nodejs-vsk-with-adm/
    
  9. npm installコマンドを実行します。node_modulesというフォルダがない場合は作成され、そこにすべての依存パッケージが保存されます。

    npm install
    

    added 86 packages from 130 contributors and audited 115 packages in 3.165s found 4 vulnerabilities (3 moderate, 1 high)といった警告が表示されても対応は不要です。

  10. zip -r sample-nodejs-vsk-with-adm.zip .コマンドを実行して、すべてのLambdaコードをパッケージ化したzipファイルを作成します(Windowsの場合は、Windowsエクスプローラーでフォルダを右クリックし、[送る] > [圧縮(zip形式)フォルダー] を選択して作成することもできます)。

    zip -r sample-nodejs-vsk-with-adm.zip .
    

    ディレクトリにsample-nodejs-vsk-with-adm.zipというパッケージが作成されました。次の手順でこのパッケージをアップロードします。

手順B: LambdaパッケージをAWS Lambdaにアップロードする

この手順では、前のセクション(手順A: Lambdaデプロイパッケージを作成する)で作成したzipファイルをAWSのLambda関数にアップロードします。

  1. https://aws.amazon.com/jp/にログインします。
  2. 左上のメニューで [サービス] をクリックし、[コンピューティング] の下にある [Lambda] をクリックします。
  3. 以前に(手順C: ビデオスキルのLambda関数を作成するで)作成した関数名をクリックします。
  4. [関数コード] で、[コードエントリタイプ] を [.zipファイルをアップロード] に変更します。
  5. [アップロード] をクリックし、sample-nodejs-vsk-with-adm.zip(前の手順A: Lambdaデプロイパッケージを作成するで作成したzipファイル)を選択します。
  6. [保存] をクリックします。

手順C: Fire TV対応アプリでビデオスキルをテストする

アプリがLambda関数からディレクティブを受信していることを確認するために、簡単なテストを行います。Echoに向かって、「アレクサ、<ビデオ名>を再生して」または「アレクサ、<ビデオ名>を探して」と話しかけてください(ビデオ名は『ボッシュ』など、IMDbにあるタイトルに置き換えます)。

Fire TV対応アプリが実行中の状態でLogcatを開くと、ADMでディレクティブを受信したことがADMメッセージハンドラーに表示されます(検索したタイトルで絞り込んでください)。

アプリのADMメッセージハンドラーでディレクティブの受信を確認する
アプリのADMメッセージハンドラーでディレクティブの受信を確認する(検索したメディアタイトルで絞り込んだ状態)

アプリに配信される内容は、手順4: Amazon Device Messaging(ADM)を統合するでADMを統合した際に記述したコードによって決まります。

たとえば、「『ボッシュ』を再生して」というフレーズで配信されるメッセージは次のようになります。

{
  "directive": {
    "payload": {
      "entities": [
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
          "value": "Bosch",
          "externalIds": {
            "avc_vending_de": "amzn1.dv.gti.e0a9f6b7-ca7e-dc0c-c80e-f5801c580da8",
            "ENTITY_ID": "amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
            "avc_vending_us": "amzn1.dv.gti.56a9f78c-4cfe-36f0-663d-9104c6dd6595",
            "asin_row_na": "B01M32CYV3",
            "asin_row_fe": "B01MCYRKGY",
            "avc_vending_jp": "amzn1.dv.gti.fea9f575-39fd-7a77-622b-a400f9b511f8",
            "asin_us": "B00S45ZDVE",
            "avc_vending": "amzn1.dv.gti.8cac011f-78c3-114b-b3f8-246a48f23ec0",
            "asin_roe_eu": "B01MCYRQHG",
            "imdb": "tt3502248",
            "ontv": "SH018737530000",
            "asin_gb": "B00IGQC64I",
            "asin_row_eu": "B01MDRHYR2",
            "asin_jp": "B014QF5HMU",
            "avc_vending_gb": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
            "tms": "SH018737530000",
            "cravetv": "m32254",
            "asin_de": "B00ZWBWZXW",
            "gti": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
            "ontv_de": "SH026719310000"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
          "value": "Bosch",
          "externalIds": {
            "ENTITY_ID": "amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
            "imdb": "tt2773036"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad",
          "value": "Bosch",
          "externalIds": {
            "gvd": "GN2EAWZBASRC1PJ",
            "ENTITY_ID": "amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
          "value": "Bosch",
          "externalIds": {
            "ENTITY_ID": "amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
            "tms": "SH018739470000",
            "ontv_gb": "SH018739470000"
          }
        },
        {
          "type": "Video",
          "uri": "entity:\/\/provider\/program\/amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202",
          "value": "Bosch",
          "externalIds": {
            "gvd": "GN794XKHCHGKGJZ",
            "ENTITY_ID": "amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202"
          }
        }
      ]
    },
    "header": {
      "payloadVersion": "3",
      "messageId": "20d83e2d-6b20-4590-92ee-f252c2f607a9",
      "namespace": "Alexa.RemoteVideoPlayer",
      "name": "SearchAndPlay",
      "correlationToken": "cf662810-879e-4d8f-afb7-7488b778cd35"
    },
    "endpoint": {
      "cookie": {

      },
      "endpointId": "VSKTV",
      "scope": {
        "token": "452d41e7-8e4a-71ed-e8fb-dd31b126bf2e",
        "type": "BearerToken"
      }
    }
  }
}
Fire TV対応サンプルアプリに関する注意点

Fire TV対応サンプルアプリで作業している場合は、カタログに3つのオープンソースビデオが統合されています。「アレクサ、『ビックバックバニー』を見せて」、「アレクサ、『コスモスローンドロマット』を見せて」、「アレクサ、『ティアーズ・オブ・スティール』を見せて」などと話しかけると、アプリが開き、それぞれのビデオが再生されます。以下は統合されている3つのビデオのスクリーンショットです。
サンプルアプリで利用可能なビデオ
サンプルアプリで利用可能なビデオ

CloudWatch Logsに表示される全体のやり取りについて

ここまでのやり取りについての理解をより深めるために、CloudWatchでログを開いて、通信全体を確認しましょう。CloudWatchでログを表示するには、次の手順を実行します。

  1. AWSで [CloudWatch] に移動し、左側のサイドバーの [ログ] をクリックします。
  2. 作成したLambda関数を選択します。
  3. 最新のログストリームを選択します。
  4. [テキスト] ラジオボタンをクリックして、詳細を展開します。
  5. Lambda was invoked by Alexaなど、ワークフローの始まりを示すログを探します。

    CloudWatchでログを確認する
    CloudWatchでログを確認する

    Cloudwatchへのアクセスの詳細については、手順B: Cloudwatchに送信されたディレクティブを表示するを参照してください。

Cloudwatchログは次のように表示されます。各ログメッセージの意味については、インラインコメントを参照してください。

START RequestId: 6a2b...c488 Version: $LATEST
# ログを開始します

2019-05-01T19:29:17.766Z	6a2b...c488	Lambda was invoked by Alexa
# ユーザーがAlexa搭載Fire TVデバイスにコマンド(「『ボッシュ』を再生して」)を発話しました。
# 発話はAlexaによってクラウドで解析され、ディレクティブが生成されました。
# ビデオスキルAPIを通じて、AlexaからLambda関数にディレクティブが送信されます。

2019-05-01T19:29:17.766Z	6a2b...c488	Event:
{
    "directive": {
        "payload": {
            "entities": [
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
                    "value": "Bosch",
                    "externalIds": {
                        "avc_vending_de": "amzn1.dv.gti.e0a9f6b7-ca7e-dc0c-c80e-f5801c580da8",
                        "ENTITY_ID": "amzn1.p11cat.merged-video.858df979-c070-5533-9b1f-ecae15e9f139",
                        "avc_vending_us": "amzn1.dv.gti.56a9f78c-4cfe-36f0-663d-9104c6dd6595",
                        "asin_row_na": "B01M32CYV3",
                        "asin_row_fe": "B01MCYRKGY",
                        "avc_vending_jp": "amzn1.dv.gti.fea9f575-39fd-7a77-622b-a400f9b511f8",
                        "asin_us": "B00S45ZDVE",
                        "avc_vending": "amzn1.dv.gti.8cac011f-78c3-114b-b3f8-246a48f23ec0",
                        "asin_roe_eu": "B01MCYRQHG",
                        "imdb": "tt3502248",
                        "ontv": "SH018737530000",
                        "asin_gb": "B00IGQC64I",
                        "asin_row_eu": "B01MDRHYR2",
                        "asin_jp": "B014QF5HMU",
                        "avc_vending_gb": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
                        "tms": "SH018737530000",
                        "cravetv": "m32254",
                        "asin_de": "B00ZWBWZXW",
                        "gti": "amzn1.dv.gti.10a9f690-1c9c-8c4e-5f67-2007ea0c5ceb",
                        "ontv_de": "SH026719310000"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
                    "value": "Bosch",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.a63315af-c728-56bc-90bb-0b8cbdcdad86",
                        "imdb": "tt2773036"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad",
                    "value": "Bosch",
                    "externalIds": {
                        "gvd": "GN2EAWZBASRC1PJ",
                        "ENTITY_ID": "amzn1.p11cat.merged-video.d9ceb2e4-4802-557d-9461-24e19a438aad"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
                    "value": "Bosch",
                    "externalIds": {
                        "ENTITY_ID": "amzn1.p11cat.merged-video.75f0a242-6a4c-5912-97be-a06a3a0d5e05",
                        "tms": "SH018739470000",
                        "ontv_gb": "SH018739470000"
                    }
                },
                {
                    "type": "Video",
                    "uri": "entity://provider/program/amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202",
                    "value": "Bosch",
                    "externalIds": {
                        "gvd": "GN794XKHCHGKGJZ",
                        "ENTITY_ID": "amzn1.p11cat.merged-video.ca646a58-8e1d-55f3-acc7-30245f8ac202"
                    }
                }
            ]
        },
        "header": {
            "payloadVersion": "3",
            "messageId": "20d83e2d-6b20-4590-92ee-f252c2f607a9",
            "namespace": "Alexa.RemoteVideoPlayer",
            "name": "SearchAndPlay",
            "correlationToken": "cf662810-879e-4d8f-afb7-7488b778cd35"
        },
        "endpoint": {
            "cookie": {},
            "endpointId": "VSKTV",
            "scope": {
                "token": "452d41e7-8e4a-71ed-e8fb-dd31b126bf2e",
                "type": "BearerToken"
            }
        }
    }
}

# これはAlexaによって生成されたSearchAndPlayディレクティブであり、アプリで再生する
# コンテンツ(ここでは『ボッシュ』)を指定しています。この時点では、ペイロードには全カタログの
# 『Bosch』のインスタンスが含まれています。ドキュメントの後半で、
# 自動ペアリングの手順を実行して、ペイロードが自分のカタログだけにペアリングされるようにします。

2019-05-01T19:29:17.766Z	6a2b...c488	Context: [object Object]

2019-05-01T19:29:17.766Z	6a2b...c488	Directive received from
Alexa: [object Object]
# Lambda関数がディレクティブを受信しました。

2019-05-01T19:29:17.859Z	6a2b...c488	Got Access Token Type:bearer
Expires In:3600
# ADMは、認証情報を使用してaccessTokenを取得します。成功した場合、Lambda
# 関数は、sendMessageToDevice()関数を呼び出します。失敗した場合は、
# アクセストークンは付与されません。

2019-05-01T19:29:17.859Z	6a2b...c488	Calling device...
# ADMはsendMessageToDevice()関数を呼び出して、APIキーで識別したアプリにディレクティブを送信します。ADMは
# ディレクティブの送信にリクエストモジュールを使用します。ADMのドキュメントのヘッダーについては
# https://developer.amazon.com/docs/adm/request-access-token.htmlを参照してください。

2019-05-01T19:29:17.932Z	6a2b...c488	Response from the app:
{
    "registrationID": "amzn1.adm-registration.v3.Y29tLmFtYXpvbi5EZXZpY2VNZXNzYWdpbmcuUmVnaXN0cmF0aW9u..."
}

# Lambda関数は、通信を確認するために登録IDを返します。
# Alexaに返すのはこの確認のみであり、ユーザーに向けての
# 発話に解析されるようなメッセージを返すことは
# ありません。

2019-05-01T19:29:17.932Z	6a2b...c488	Sending SearchAndPlay
response back to Alexa:
{
    "event": {
        "header": {
            "messageId": "not-required",
            "correlationToken": "not-required",
            "name": "Response",
            "namespace": "Alexa",
            "payloadVersion": "3"
        },
        "endpoint": {
            "scope": {
                "type": "DirectedUserId",
                "directedUserId": "not-required"
            },
            "endpointId": "not-required"
        },
        "payload": {}
    }
}

# Lambda関数はAlexaに成功レスポンスを返し、Lambda関数で
# ディレクティブを受信したことを通知します。

END RequestId: 6a2b...c488
# ディレクティブのリクエストIDです。

REPORT RequestId: 6a2b...c488	Duration: 167.40 ms	Billed
Duration: 200 ms Memory Size: 128 MB	Max Memory Used: 80 MB
# リクエストの処理に要した時間とメモリです。

Billed Duration: 600 ms Memory Size: 128 MB	Max Memory Used: 81 MB
# この処理で請求対象となる実行時間です。ビデオスキルを備えた
# Fire TV対応アプリで、40GBの無料利用枠を超えるメモリを使用することは
# ほとんどありません(https://aws.amazon.com/jp/lambda/pricing/?nc1=h_ls)。

トラブルシューティング

統合のこの段階で問題が発生した場合は、以下のトラブルシューティング情報を参照してください。

エラー: LWA#getToken() failed ...Register LWA authentication after 20 seconds

エラー: LWA#authorize() errorAuthError cat= INTERNAL type=ERROR_SERVER_REPSONSE - com.amazon.identity.auth.device.AuthError: Error=invalid_scope error_description=An unknown scope was requested

エラー: LWA authentication failed.Voice service will not be available!`

エラー: RequestedScope shouldn't be null!!!! - null, but continuing anyway...Can't post event:EVENT_TYPE_DISCOVERY, LWA access token is not valid yet or Can't post event:EVENT_TYPE_DISCOVERY, LWA access token is not valid yet.`

Login with Amazonとセキュリティプロファイルの関連付けが原因でアプリが失敗しています。手順5: アプリに署名してセキュリティプロファイルを構成するが完了していることを確認してください(アプリでLogin with Amazonをで有効にする必要があります)。Login with Amazonと統合すると、さまざまなコンポーネントでやり取りが行われるため、ここでは多くの確認が必要です。次の点を確認してください。

  1. セキュリティプロファイルのパッケージ名が正しい。
  2. 開発者コンソールにアップロードしたAPKとセキュリティプロファイルのパッケージ名が同じである。
  3. Lambdaコードで、セキュリティプロファイルのクライアントIDとクライアントシークレットを使用している。
  4. 登録IDが正しい。

次のステップ

次の 手順7: スキルの自動ペアリングを設定して仕上げるに進みます。