[日本語Alexa] Alexa-SDK Ver2(その6) 所在地情報

2018.05.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

本記事は、Alexa SDK for Node.js Ver2入門と題して、入門用という位置付けで、Alexa SDKの使い方を、順に紹介しているものです。(対象は、Node.js用のみです。Java用には触れておりません)

その6では、所在地情報(郵便番号や住所)の利用方法について見ていきたいと思います。

最初に、今回作成したサンプルの動作している様子をご確認下さい。

パーミッションの変更は、テストシミュレーターでは確認出来ないため、実機を使用しています。

2 所在地情報

スキルでは、ユーザーが許可を与えた場合、Alexa端末に設定された所在地情報(GPSや他の位置情報データではありません)を利用することが可能です。

所在地情報を取得するには、Amazonで提供されているDevice Address APIを利用しますが、Alexa SDK (v2)では、これを利用するためのファンクションが予め用意されていますので、非常に簡単に利用することが可能です。

ユーザーからのパーミッションと所在地データを取得する手順は、以下のとおりです。

  • 所在情報の設定
  • パーミッションの設定
  • パーミッションの要求
  • 所在地情報の取得

3 所在情報の設定

所在地情報は、予めユーザーが各デバイスごとに設定している必要があります。これは、Aleaアプリから行います。

赤字で記載されているものは、APIで取得した際のプロパティ名です。

4 パーミッションの設定

所在地情報を利用したいスキルは、アクセス権限デバイスのアドレスにチェックを入れる必要があります。この時、取得の対象として「住所」及び「国と郵便番号のみ」が選択できます。

5 パーミッションの要求

ユーザーが所在地情報の利用を許可した場合、Alexaからのリクエストでcontext.System.user.permissionsの中にconsentTokenが含まれるようになります。

"context": {
        "System": {
            "user": {
                "userId": "amzn1.ask.account.xxxx",
                "permissions": {
                    "consentToken": "xxxxxxxx"
                }
            },

ユーザーが利用を許可していない場合、このconsentTokenが無いため、通常、下記のようにユーザーに許可を促します。

const PERMISSIONS = ['read::alexa:device:all:address'];

handle(handlerInput) {
    const consentToken = handlerInput.requestEnvelope.context.System.user.permissions && handlerInput.requestEnvelope.context.System.user.permissions.consentToken;
    if (!consentToken) {
          return responseBuilder
            .speak('住所の利用が許可されていません。アレクサアプリの設定を変更して下さい。')
            .withAskForPermissionsConsentCard(PERMISSIONS)
            .getResponse();
    }

ResponseBuilderwithAskForPermissionsConsentCard()を使用すると、Alexaアプリに次のようなカードが表示されます。

6 所在地情報の取得

所在地情報を取得するコードは以下のとおりです。

handleInputserviceClientFactorygetDeviceAddressServiceClient()を使用してサービスクライアントを準備します。

サービスクライアントでは、getFullAddress()にデバイスIDを設定することで所在地情報を取得することができます。先程のconsentTokenは、getFullAddress()の内部で利用されています。

const { requestEnvelope, serviceClientFactory } = handlerInput;
const { deviceId } = requestEnvelope.context.System.device;
const deviceAddressServiceClient = serviceClientFactory.getDeviceAddressServiceClient();
const address = await deviceAddressServiceClient.getFullAddress(deviceId);

追記:現在、Alexa.SkillBuilders.standard()で生成したスキルオブジェクトは、DefaultApiClientで初期化されるため、わざわざcustom() を使用する必要はありません。逆に、custom()を使用する場合は、ApiClientの初期化が必須となることにご注意下さい。

なお、getDeviceAddressServiceClientを使用するためには、スキルオブジェクトの作成時に、withApiClient()でサービスクライアントを設定しておく必要があります。

skill = Alexa.SkillBuilders.custom() // <= custom()である必要がある
    .addRequestHandlers(XXXXHandler)
    .withApiClient(new Alexa.DefaultApiClient()) // <= ApiClientを設定する
    .create();

7 実装

最初に動画で紹介したサンプルスキルの全コードは、下記のとおりです。Device Address APIを呼び出すコードが必要ないため、非常にシンプルになっています。

※必須インテントやエラーの実装は、省略されています。

const Alexa = require('ask-sdk');

let skill;
exports.handler = async function (event, context) {
    if (!skill) {
      skill = Alexa.SkillBuilders.custom() // <= custom()である必要がある
        .addRequestHandlers(
            LaunchRequestHandler)
        .withApiClient(new Alexa.DefaultApiClient()) // <= ApiClientを設定する
        .create();
    }
    return skill.invoke(event);
}

const PERMISSIONS = ['read::alexa:device:all:address'];

const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    async handle(handlerInput) {
        const { responseBuilder, requestEnvelope, serviceClientFactory } = handlerInput;
        const consentToken = requestEnvelope.context.System.user.permissions && requestEnvelope.context.System.user.permissions.consentToken;
        if (!consentToken) {
              return responseBuilder
                .speak('住所の利用が許可されていません。アレクサアプリの設定を変更して下さい。')
                .withAskForPermissionsConsentCard(PERMISSIONS)
                .getResponse();
        }
        try{
            const { deviceId } = requestEnvelope.context.System.device;
            const deviceAddressServiceClient = serviceClientFactory.getDeviceAddressServiceClient();
            const address = await deviceAddressServiceClient.getFullAddress(deviceId);
            const speechText = '郵便番号' + address.postalCode + '<break time="200ms"/>' + address.stateOrRegion + address.city + address.addressLine1;
            return responseBuilder
                .speak(speechText)
                .getResponse();
        } catch (error) {
            if (error.name == 'ServiceError') {
                console.log('ERROR StatusCode:' + error.statusCode + ' ' + error.message)
            }
            return responseBuilder
                .speak('所在地情報の取得に失敗しました')
                .getResponse();
        }
    }
};

8 最後に

今回は、所在地情報(住所・郵便番号など)を利用する方法について見てきました。

SDK Ver1.xでは、Device Address APIを利用するには、非同期でのRestAPIコールが必須であったため、比較的複雑な実装になっていましたが、Ver2では、たったの数行になってしまいました。

serviceClientFactoryは、Ver2での大きな進化の1つだと感じました。

9 参考リンク


Alexa Skills Kit SDK for Node.js
Now Available: Version 2 of the ASK Software Development Kit for Node.js
GitHub repository for the SDK v2 for Node.js
所在地情報を使用してスキルを拡張する
[日本語Alexa] Alexa SDK for Node.js Ver2入門(その1)はじめの一歩
[日本語Alexa] Alexa SDK for Node.js Ver2入門(その2)ハンドラの登録
[日本語Alexa] Alexa SDK for Node.js Ver2入門(その3)レスポンスの作成
[日本語Alexa] Alexa-SDK Ver2(その4)スキル属性
[日本語Alexa] Alexa-SDK Ver2(その5)ダイアログモード
[日本語Alexa] Alexa-SDK Ver2(その6) 所在地情報
[日本語Alexa] Alexa-SDK Ver2(その7) ディスプレイ表示