1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ask-sdk-jsx-for-apiで時計を作ってみた

Posted at

はじめに

APLのドキュメントを見ていると自分のスキルに使えそうな機能があったので作ってみました。
ask-sdk-jsx-for-api (v1.0.0-beta.4)もアップデートされており、APL v1.4まで対応していたので利用します。

作成物

clock.gif

実際に作ったスキルはこちら!

Alexaで「シンプル時計」をお試しください
朝の5秒を守る!3.7倍の改善で、たった8文字までに効率化した時短スキル...
clock_108_108.jpeg

Quick Linkを使っているので、開くだけでスキルが起動します。

実装

package.json
...
  "scripts": {
    "create-json": "cp node_modules/ask-sdk-jsx-for-apl/package.json node_modules/ask-sdk-jsx-for-apl/dist/ && npx ts-node createAplJson.tsx",
  },
  "dependencies": {
    "ask-sdk": "^2.10.0",
    "ask-sdk-jsx-for-apl": "^1.0.0-beta.4",
    "ask-sdk-runtime": "^2.10.1",
    "ask-utils": "^3.11.0",
    "moment": "^2.29.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "source-map-support": "^0.5.19"
  },
...

ask-sdk-jsx-for-aplなどをインストールしておきます。

注意点として、手元の環境で1.0.0-beta.4を使うとエラーになったので、下記のおまじないで回避しています。

$ cp node_modules/ask-sdk-jsx-for-apl/package.json node_modules/ask-sdk-jsx-for-apl/dist/

また、VS Codeのプラグイン Alexa Skills Kit (ASK) Toolkit を利用して、ローカル環境でAPLのpreviewを確認するためにscriptsを定義しておきます。


メインの時計の部分は、APL v1.3から使えるようになった、クロックとタイマー変数と関数を利用します。

clock.tsx
import React from "react";
import { Container, Text, Frame } from "ask-sdk-jsx-for-apl";

export const Clock: React.FC = () => {
    return (
        <Container direction="row" bind={[{name: "now", value: "${localTime}"}]}>
            <Container>
                <Text fontSize="@largeFontSize" text="${Time.format('HH:mm', now)}"/>
            </Container>
            <Container paddingLeft="2vw" bottom="@secondBottom" justifyContent="end">
                <Text fontSize="@smallFontSize" text="${Time.format('ss', now)}"/>
            </Container>
        </Container>
    )
}

bindnowという変数に現在時刻をバインドします。(localTimeは現在時刻を表す)
Textコンポーネントでは、時間関数を使ってフォーマットを整えます。


LaunchDocument.tsx

import React from "react";
import { APL, MainTemplate, Container, Text } from "ask-sdk-jsx-for-apl";
import { Clock } from "./clock";

export const LaunchAplDocument: React.FC = () => {
  return (
    <APL theme="dark" resources={resources}>
      <MainTemplate>
        <Container width="100vw" height="100vh" justifyContent="center" alignItems="center" >
          <Clock />
        </Container>
      </MainTemplate>
    </APL>
  );
};

const resources = [
  {
    "strings": {
      "largeFontSize": "160dp",
      "smallFontSize": "80dp",
      "secondBottom": "4vh",
    },
  },
  {
    "when": "${viewport.shape == 'round'}",
    "string": {
      "largeFontSize": "120dp",
      "smallFontSize": "60dp",
      "secondBottom": "3vh",
    }
  },
];

スタイル調整用にresources定義と、Documentの作成を行います。


handler.tsx
import { getViewportState } from "@ask-utils/core";

import moment from 'moment';
import { AplDocument } from 'ask-sdk-jsx-for-apl';
import { LaunchAplDocument } from "./LaunchDocument";

const LaunchRequestHandler = {
  canHandle(handlerInput: Ask.HandlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'LaunchRequest';
  },
  async handle(handlerInput: Ask.HandlerInput) {
    // 画面あり
    if (getViewportState(handlerInput)) {
      return handlerInput.responseBuilder
      .addDirective(new AplDocument(<LaunchAplDocument />).getDirective())
      .speak(`${moment().format('hh:mm')}です`)
      .getResponse();
    }

    // 画面なし
    return handlerInput.responseBuilder
      .speak(`${moment().format('hh:mm')}です`)
      .withShouldEndSession(true)
      .getResponse();
  }
};

export const alexa = Ask.SkillBuilders.custom()
  .addRequestHandlers(
    LaunchRequestHandler
  )
  .lambda();

handlerでは、画面がある場合にAPLを返すようにします。
エラーやヘルプハンドラーなどは省略します。


ここまでのものをデプロイすれば実機で確認できます。
毎回デプロイして画面を確認するのは大変なのでローカルで確認します。

createAplJson.tsx
import React from "react";
import { AplDocument } from "ask-sdk-jsx-for-apl";
import { LaunchAplDocument } from "./LaunchDocument";
import fs from "fs";

const file = "../skill-package/response/display/start_from_scratch/document.json";
const aplDoc = JSON.stringify(new AplDocument(<LaunchAplDocument/>).getDirective().document, null, 2);
try {
    fs.writeFileSync(file, aplDoc);
} catch(e){
    console.log(e);
}

jsxからjsonを作成するプログラムを実行します。

$ npm run create-json

jsonファイルが出力されます。

document.json
{
  "type": "APL",
  "version": "1.4",
  "theme": "dark",
  "resources": [
    {
      "strings": {
        "largeFontSize": "160dp",
        "smallFontSize": "80dp",
        "secondBottom": "4vh"
      }
    },
    {
      "when": "${viewport.shape == 'round'}",
      "string": {
        "largeFontSize": "120dp",
        "smallFontSize": "60dp",
        "secondBottom": "3vh"
      }
    }
  ],
  "mainTemplate": {
    "parameters": [],
    "items": [
      {
        "type": "Container",
        "width": "100vw",
        "height": "100vh",
        "justifyContent": "center",
        "alignItems": "center",
        "items": [
          {
            "type": "Container",
            "direction": "row",
            "bind": [
              {
                "name": "now",
                "value": "${localTime}"
              }
            ],
            "items": [
              {
                "type": "Container",
                "items": [
                  {
                    "type": "Text",
                    "fontSize": "@largeFontSize",
                    "text": "${Time.format('HH:mm', now)}"
                  }
                ]
              },
              {
                "type": "Container",
                "paddingLeft": "2vw",
                "bottom": "@secondBottom",
                "justifyContent": "end",
                "items": [
                  {
                    "type": "Text",
                    "fontSize": "@smallFontSize",
                    "text": "${Time.format('ss', now)}"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

このjsonを、Alexa Skills Kit (ASK) ToolkitAlexa Presentation Lancuage(APL) -> Preview -> ファイル指定で開くとローカルでpreviewを確認できます。

jsonを上書き保存するとpreviewにすぐに反映されるので、ちょっとした修正はjsonで直接行い、
ある程度固まったらjsxも修正するというやり方も良いかもしれません。

最後に

APL書くときはjsonだけでなくjsxもおすすめです。
ask-sdk-jsx-for-apiのGAが待ち遠しいです!)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?